diff --git a/.github/workflows/update-configuration.yml b/.github/workflows/update-configuration.yml index fae4f91..66b6cc2 100644 --- a/.github/workflows/update-configuration.yml +++ b/.github/workflows/update-configuration.yml @@ -22,7 +22,7 @@ on: skip_bot_events: description: "manifest.skipBotEvents value for generated manifest." required: false - default: "true" + default: "false" exclude_supported_events: description: "Comma-separated supported events to exclude from manifest listeners." required: false @@ -35,16 +35,29 @@ on: delete: jobs: - deploy: - name: "Deploy (Action / Deno)" + resolve-context: + name: "Resolve Context" runs-on: ubuntu-latest - permissions: write-all - environment: ${{ (github.event.ref == 'refs/heads/main' || github.ref == 'refs/heads/main' || github.event.workflow_run.head_branch == 'main') && 'main' || 'development' }} + permissions: read-all env: BUILD_ACTION_ENABLED: ${{ github.event_name == 'workflow_dispatch' && inputs.build_action_enabled || vars.BUILD_ACTION_ENABLED || 'true' }} DEPLOY_DENO_ENABLED: ${{ github.event_name == 'workflow_dispatch' && inputs.deploy_deno_enabled || vars.DEPLOY_DENO_ENABLED || 'true' }} - SKIP_BOT_EVENTS: ${{ github.event_name == 'workflow_dispatch' && inputs.skip_bot_events || vars.SKIP_BOT_EVENTS || 'true' }} + SKIP_BOT_EVENTS: ${{ github.event_name == 'workflow_dispatch' && inputs.skip_bot_events || vars.SKIP_BOT_EVENTS || 'false' }} EXCLUDE_SUPPORTED_EVENTS: ${{ github.event_name == 'workflow_dispatch' && inputs.exclude_supported_events || vars.EXCLUDE_SUPPORTED_EVENTS || 'issue_comment.created,pull_request_review_comment.created' }} + outputs: + source_ref: ${{ steps.refs.outputs.source_ref }} + is_tag_ref: ${{ steps.refs.outputs.is_tag_ref }} + is_dist_ref: ${{ steps.refs.outputs.is_dist_ref }} + build_action_enabled: ${{ steps.config.outputs.build_action_enabled }} + deploy_deno_enabled: ${{ steps.config.outputs.deploy_deno_enabled }} + skip_bot_events: ${{ steps.config.outputs.skip_bot_events }} + exclude_supported_events: ${{ steps.config.outputs.exclude_supported_events }} + should_publish_action_artifact: ${{ steps.config.outputs.should_publish_action_artifact }} + should_run_deno: ${{ steps.config.outputs.should_run_deno }} + artifact_environment: ${{ steps.config.outputs.artifact_environment }} + deno_environment: ${{ steps.config.outputs.deno_environment }} + artifact_action: ${{ steps.config.outputs.artifact_action }} + deno_action: ${{ steps.config.outputs.deno_action }} steps: - name: Resolve source ref @@ -61,93 +74,104 @@ jobs: is_tag_ref="true" fi - is_artifact_ref="false" + is_dist_ref="false" if [[ "$source_ref" == dist/* ]]; then - is_artifact_ref="true" - fi - - if [[ "$BUILD_ACTION_ENABLED" == "true" ]]; then - action_ref_branch="dist/${source_ref}" - else - action_ref_branch="${source_ref}" + is_dist_ref="true" fi echo "source_ref=$source_ref" >> "$GITHUB_OUTPUT" echo "is_tag_ref=$is_tag_ref" >> "$GITHUB_OUTPUT" - echo "is_artifact_ref=$is_artifact_ref" >> "$GITHUB_OUTPUT" - echo "ACTION_REF=${GITHUB_REPOSITORY}@${action_ref_branch}" >> "$GITHUB_ENV" + echo "is_dist_ref=$is_dist_ref" >> "$GITHUB_OUTPUT" - - name: Print deployment mode + - name: Resolve deployment settings + id: config shell: bash + env: + SOURCE_REF: ${{ steps.refs.outputs.source_ref }} + IS_TAG_REF: ${{ steps.refs.outputs.is_tag_ref }} + IS_DIST_REF: ${{ steps.refs.outputs.is_dist_ref }} run: | - echo "BUILD_ACTION_ENABLED=${BUILD_ACTION_ENABLED}" - echo "DEPLOY_DENO_ENABLED=${DEPLOY_DENO_ENABLED}" - echo "SKIP_BOT_EVENTS=${SKIP_BOT_EVENTS}" - echo "EXCLUDE_SUPPORTED_EVENTS=${EXCLUDE_SUPPORTED_EVENTS}" - echo "SOURCE_REF=${{ steps.refs.outputs.source_ref }}" - echo "IS_ARTIFACT_REF=${{ steps.refs.outputs.is_artifact_ref }}" - echo "IS_TAG_REF=${{ steps.refs.outputs.is_tag_ref }}" - echo "ACTION_REF=${ACTION_REF}" + artifact_environment="development" + deno_environment="development" + if [[ "$SOURCE_REF" == "main" || "$SOURCE_REF" == "demo" ]]; then + artifact_environment="main" + deno_environment="main" + fi + + artifact_action="publish" + deno_action="provision" + if [[ "${{ github.event_name }}" == "delete" ]]; then + artifact_action="delete" + deno_action="delete" + fi + + should_publish_action_artifact="false" + if [[ "$BUILD_ACTION_ENABLED" == "true" && "$IS_TAG_REF" != "true" && "$IS_DIST_REF" != "true" ]]; then + should_publish_action_artifact="true" + fi + + should_run_deno="false" + if [[ "$DEPLOY_DENO_ENABLED" == "true" && "$IS_TAG_REF" != "true" && "$IS_DIST_REF" != "true" ]]; then + should_run_deno="true" + fi + + echo "build_action_enabled=$BUILD_ACTION_ENABLED" >> "$GITHUB_OUTPUT" + echo "deploy_deno_enabled=$DEPLOY_DENO_ENABLED" >> "$GITHUB_OUTPUT" + echo "skip_bot_events=$SKIP_BOT_EVENTS" >> "$GITHUB_OUTPUT" + echo "exclude_supported_events=$EXCLUDE_SUPPORTED_EVENTS" >> "$GITHUB_OUTPUT" + echo "artifact_environment=$artifact_environment" >> "$GITHUB_OUTPUT" + echo "deno_environment=$deno_environment" >> "$GITHUB_OUTPUT" + echo "artifact_action=$artifact_action" >> "$GITHUB_OUTPUT" + echo "deno_action=$deno_action" >> "$GITHUB_OUTPUT" + echo "should_publish_action_artifact=$should_publish_action_artifact" >> "$GITHUB_OUTPUT" + echo "should_run_deno=$should_run_deno" >> "$GITHUB_OUTPUT" + publish-action-artifact: + name: "Publish Action Artifact" + needs: resolve-context + if: ${{ needs.resolve-context.outputs.should_publish_action_artifact == 'true' }} + runs-on: ubuntu-latest + permissions: write-all + environment: ${{ needs.resolve-context.outputs.artifact_environment }} + + steps: - name: Publish action artifact branch - if: ${{ env.BUILD_ACTION_ENABLED == 'true' }} uses: ubiquity-os/action-deploy-plugin@main with: - action: ${{ github.event_name == 'delete' && 'delete' || 'publish' }} + action: ${{ needs.resolve-context.outputs.artifact_action }} treatAsEsm: true sourcemap: true - pluginEntry: "${{ github.workspace }}/src/action.ts" - excludeSupportedEvents: ${{ env.EXCLUDE_SUPPORTED_EVENTS }} - skipBotEvents: ${{ env.SKIP_BOT_EVENTS }} + pluginEntry: "${{ github.workspace }}/src/worker.ts" + excludeSupportedEvents: ${{ needs.resolve-context.outputs.exclude_supported_events }} + skipBotEvents: ${{ needs.resolve-context.outputs.skip_bot_events }} env: APP_ID: ${{ secrets.APP_ID }} APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} - - name: Check out the repository - if: ${{ env.DEPLOY_DENO_ENABLED == 'true' && steps.refs.outputs.is_tag_ref != 'true' && steps.refs.outputs.is_artifact_ref != 'true' }} - uses: actions/checkout@v6 - - - name: Set up Deno - if: ${{ env.DEPLOY_DENO_ENABLED == 'true' && steps.refs.outputs.is_tag_ref != 'true' && steps.refs.outputs.is_artifact_ref != 'true' }} - uses: denoland/setup-deno@v2 - with: - deno-version: v2.x - - - name: Install dependencies - if: ${{ env.DEPLOY_DENO_ENABLED == 'true' && steps.refs.outputs.is_tag_ref != 'true' && steps.refs.outputs.is_artifact_ref != 'true' && github.event_name != 'delete' }} - run: deno install --node-modules-dir=auto --no-lock - - - name: Generate manifest for deploy - if: ${{ env.DEPLOY_DENO_ENABLED == 'true' && steps.refs.outputs.is_tag_ref != 'true' && steps.refs.outputs.is_artifact_ref != 'true' && github.event_name != 'delete' }} - run: deno x -A -y --no-lock npm:@ubiquity-os/plugin-manifest-tool@latest - env: - SKIP_BOT_EVENTS: ${{ env.SKIP_BOT_EVENTS }} - EXCLUDE_SUPPORTED_EVENTS: ${{ env.EXCLUDE_SUPPORTED_EVENTS }} - GITHUB_REF_NAME: ${{ steps.refs.outputs.source_ref }} + deploy-deno: + name: "Provision Deno App" + needs: resolve-context + if: ${{ needs.resolve-context.outputs.should_run_deno == 'true' }} + runs-on: ubuntu-latest + permissions: write-all + environment: ${{ needs.resolve-context.outputs.deno_environment }} - - uses: ubiquity-os/deno-plugin-adapter@main - if: ${{ env.DEPLOY_DENO_ENABLED == 'true' && steps.refs.outputs.is_tag_ref != 'true' && steps.refs.outputs.is_artifact_ref != 'true' && github.event_name != 'delete' }} - id: adapter - with: - pluginEntry: "./worker" + steps: + - uses: actions/checkout@v6 + if: ${{ needs.resolve-context.outputs.deno_action != 'delete' }} - uses: ubiquity-os/deno-deploy@main - if: ${{ env.DEPLOY_DENO_ENABLED == 'true' && steps.refs.outputs.is_tag_ref != 'true' && steps.refs.outputs.is_artifact_ref != 'true' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} KERNEL_PUBLIC_KEY: ${{ secrets.KERNEL_PUBLIC_KEY }} APP_ID: ${{ secrets.APP_ID }} APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} APP_INSTALLATION_ID: ${{ secrets.APP_INSTALLATION_ID }} - ACTION_REF: ${{ env.ACTION_REF }} LOG_LEVEL: ${{ secrets.LOG_LEVEL }} SUPABASE_URL: ${{ secrets.SUPABASE_URL }} SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }} with: token: ${{ secrets.DENO_DEPLOY_TOKEN }} - action: ${{ github.event_name == 'delete' && 'delete' || 'deploy' }} - organization: ${{ secrets.DENO_ORG_NAME }} - entrypoint: ${{ github.event_name == 'delete' && 'src/deno.ts' || steps.adapter.outputs.entrypoint }} - project_name: ${{ secrets.DENO_PROJECT_NAME }} - sourceRef: ${{ steps.refs.outputs.source_ref }} - artifactPrefix: dist/ + action: ${{ needs.resolve-context.outputs.deno_action }} + app: ${{ secrets.DENO_PROJECT_NAME }} + entrypoint: src/worker.ts diff --git a/bun.lock b/bun.lock index 19c2dc8..f46bef2 100644 --- a/bun.lock +++ b/bun.lock @@ -1,11 +1,12 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "plugin-template", "dependencies": { "@sinclair/typebox": "0.34.48", - "@ubiquity-os/plugin-sdk": "^3.12.0", + "@ubiquity-os/plugin-sdk": "^3.12.5", "@ubiquity-os/ubiquity-os-logger": "^1.4.0", "hono": "^4.11.9", }, @@ -723,7 +724,7 @@ "@ubiquity-os/eslint-plugin-no-empty-strings": ["@ubiquity-os/eslint-plugin-no-empty-strings@1.0.3", "", { "dependencies": { "@typescript-eslint/utils": "^8.38.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.38.0", "eslint": "^9.32.0", "typescript": "^5.8.2" } }, "sha512-lqEMJWqKevdhmye9FBgF+1uYrJmDXSmA2krZ6yyHgKlkyTsKT20UUO0okJW+ESa6kKTFjI8BLBeXtPrn9MF09A=="], - "@ubiquity-os/plugin-sdk": ["@ubiquity-os/plugin-sdk@3.12.0", "", { "dependencies": { "@actions/core": "^1.11.1", "@actions/github": "^6.0.1", "@octokit/core": "^7.0.6", "@octokit/plugin-paginate-graphql": "^6.0.0", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-rest-endpoint-methods": "^17.0.0", "@octokit/plugin-retry": "^8.0.3", "@octokit/plugin-throttling": "^11.0.3", "@octokit/types": "^16.0.0", "@octokit/webhooks": "^14.1.3", "@ubiquity-os/ubiquity-os-logger": "^1.4.0", "hono": "^4.10.6", "js-yaml": "^4.1.1", "ms": "^2.1.3", "openai": "^6.15.0" }, "peerDependencies": { "@sinclair/typebox": "0.34.41" } }, "sha512-/NfB1a0X+U4/fH9R+xTxfS/GasBjZ7h70jPRNoQrRkkHBXibnrEJr5xRT0HLyBz12cmzWTdKHOQxPYMTLmFxHQ=="], + "@ubiquity-os/plugin-sdk": ["@ubiquity-os/plugin-sdk@3.12.5", "", { "dependencies": { "@actions/core": "^1.11.1", "@actions/github": "^6.0.1", "@octokit/core": "^7.0.6", "@octokit/plugin-paginate-graphql": "^6.0.0", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-rest-endpoint-methods": "^17.0.0", "@octokit/plugin-retry": "^8.0.3", "@octokit/plugin-throttling": "^11.0.3", "@octokit/types": "^16.0.0", "@octokit/webhooks": "^14.1.3", "@ubiquity-os/ubiquity-os-logger": "^1.4.0", "hono": "^4.10.6", "js-yaml": "^4.1.1", "ms": "^2.1.3", "openai": "^6.15.0" }, "peerDependencies": { "@sinclair/typebox": "0.34.41" } }, "sha512-T1TAdD6rZDVrRELrEiQWM5bBRdzvFzMD+o6lthCahlGkvTOG3xxPHe8iXVnYrq60qnnMTrlUGm/uV9cIujZZ5A=="], "@ubiquity-os/ubiquity-os-logger": ["@ubiquity-os/ubiquity-os-logger@1.4.0", "", {}, "sha512-giybluPmu0sreEWi60t9X8NxC5d48X7oQAb9RjXR7wX/ZNYugbAaKgj0TYEqECvSVDqgzpKo7UNerh1UQBscGw=="], @@ -1963,8 +1964,6 @@ "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "@ubiquity-os/plugin-sdk/hono": ["hono@4.10.6", "", {}, "sha512-BIdolzGpDO9MQ4nu3AUuDwHZZ+KViNm+EZ75Ae55eMXMqLVhDFqEMXxtUe9Qh8hjL+pIna/frs2j6Y2yD5Ua/g=="], - "@ubiquity-os/plugin-sdk/js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], "@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], diff --git a/package.json b/package.json index d8713d0..1329566 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --setupFiles dotenv/config --coverage", "worker": "wrangler dev --env dev --port 4000", "prepare": "bun run prepare:manifest && husky", - "prepare:manifest": "bunx @ubiquity-os/plugin-manifest-tool@latest", + "prepare:manifest": "bun x @ubiquity-os/plugin-manifest-tool@latest", "prebuild": "bun run prepare:manifest" }, "keywords": [ @@ -37,7 +37,7 @@ ], "dependencies": { "@sinclair/typebox": "0.34.48", - "@ubiquity-os/plugin-sdk": "^3.12.0", + "@ubiquity-os/plugin-sdk": "^3.12.5", "@ubiquity-os/ubiquity-os-logger": "^1.4.0", "hono": "^4.11.9" }, diff --git a/src/worker.ts b/src/worker.ts index ac9f1bd..7335a53 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -1,18 +1,31 @@ import { LOG_LEVEL, LogLevel } from "@ubiquity-os/ubiquity-os-logger"; import { createPlugin, type Options as PluginSdkOptions } from "@ubiquity-os/plugin-sdk"; -import { Manifest } from "@ubiquity-os/plugin-sdk/manifest"; +import { Manifest, resolveRuntimeManifest } from "@ubiquity-os/plugin-sdk/manifest"; import { ExecutionContext } from "hono"; import manifest from "../manifest.json" with { type: "json" }; import { runPlugin } from "./index"; import { Env, envSchema, PluginSettings, pluginSettingsSchema, SupportedEvents } from "./types"; +function buildRuntimeManifest(request: Request) { + const runtimeManifest = resolveRuntimeManifest(manifest as Manifest); + return { + ...runtimeManifest, + homepage_url: new URL(request.url).origin, + }; +} + export default { async fetch(request: Request, env: Env, executionCtx?: ExecutionContext) { + const runtimeManifest = buildRuntimeManifest(request); + if (new URL(request.url).pathname === "/manifest.json") { + return Response.json(runtimeManifest); + } + return createPlugin( (context) => { return runPlugin(context); }, - manifest as Manifest, + runtimeManifest, { envSchema: envSchema as unknown as PluginSdkOptions["envSchema"], postCommentOnError: true, diff --git a/tests/__mocks__/helpers.ts b/tests/__mocks__/helpers.ts index a9fc8b0..e7596fc 100644 --- a/tests/__mocks__/helpers.ts +++ b/tests/__mocks__/helpers.ts @@ -1,7 +1,7 @@ import { db } from "./db"; import issueTemplate from "./issue-template"; import { STRINGS } from "./strings"; -import usersGet from "./users-get.json"; +import usersGet from "./users-get.json" with { type: "json" }; /** * Helper function to setup tests. diff --git a/tests/main.test.ts b/tests/main.test.ts index 196e80d..29060ee 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -4,7 +4,7 @@ import { CommentHandler } from "@ubiquity-os/plugin-sdk"; import { customOctokit as Octokit } from "@ubiquity-os/plugin-sdk/octokit"; import { Logs } from "@ubiquity-os/ubiquity-os-logger"; import dotenv from "dotenv"; -import manifest from "../manifest.json"; +import manifest from "../manifest.json" with { type: "json" }; import { runPlugin } from "../src"; import { Env } from "../src/types"; import { Context } from "../src/types/context"; @@ -35,7 +35,7 @@ describe("Plugin tests", () => { const worker = (await import("../src/worker")).default; const response = await worker.fetch(new Request("http://localhost/manifest.json"), {}); const content = await response.json(); - expect(content).toEqual(manifest); + expect(content).toEqual({ ...manifest, homepage_url: "http://localhost" }); }); it("Should handle an issue comment event", async () => {