Provisions Deno Deploy apps, syncs Deno environment variables, and optionally maintains dist/* manifest artifacts for UbiquityOS plugins.
- One local-source Deno Deploy app is managed per Git branch.
mainuses the unsuffixed base app slug. Every other branch uses<base-app>-<branch-suffix>, capped at 32 total characters.- Long branch names are truncated to fit the 32-character cap. No hash or other disambiguator is appended, so collisions are accepted by design.
provisioncreates a missing branch app through the Deno API when needed, always syncs runtime env vars to Denoproduction, deploys the branch app from the current workspace with--prod, and always outputs the stable branch app URLhttps://<app-slug>.<org-slug>.deno.net.- When
buildManifest=true,provisionalso syncs manifest build env vars, generatesmanifest.jsonin GitHub Actions, updates itshomepage_url, and publishes it todist/<branch>. - When
buildManifest=false, manifest generation, manifest homepage updates, anddist/<branch>manifest publication are skipped. deleteremoves both the paired Deno branch app and the paireddist/<branch>branch.
action:provisionordelete.token: Deno Deploy token used for app management, env sync, deploys, and deletion.organization: Optional Deno Deploy organization slug. When omitted,provisionfirst infers it from the token and then falls back toDENO_ORG_NAMEwhen available.app: Optional base Deno Deploy app slug override. Defaults to the sanitized repository name.mainuses this value directly; all other branches append a truncated branch suffix within the 32-character total slug cap.entrypoint: App runtime entrypoint. Defaults tosrc/deno.ts.buildManifest: Whether plugin manifest generation,homepage_urlwrites, anddist/*manifest publication should run. Defaults totrue. Set this tofalsefor non-plugin Deno apps such asubiquity-os-kernel.
app_slug: Resolved Deno app slug.homepage_url: Resolved stable branch app URL. Written intodist/*/manifest.jsononly whenbuildManifest=true.
- Runtime env vars always go to Deno
productionin this branch-per-app model. - Runtime env vars are always synced during
provision. - GitHub environment selection still happens in the consumer workflow:
mainanddemoshould use the GitHubmainenvironment- all other branches should use the GitHub
developmentenvironment
- Managed branch identity env vars are always synced:
REF_NAMEto both runtimeproductionand build
- Manifest-specific build env vars are synced only when
buildManifest=true:PLUGIN_MANIFEST_REPOSITORYPLUGIN_MANIFEST_PRODUCTION_BRANCH=main
- Reserved
DENO_*names from the workflow environment are excluded automatically.
The action treats the Deno dashboard config as the source of truth. It always applies:
runtime.type=dynamicruntime.entrypoint=<input entrypoint>unstablemerged withkv
When buildManifest=true, it also applies:
install:deno installbuild:deno x -y @ubiquity-os/plugin-manifest-tool@latest --repository <owner>/<repo> --production-branch mainpredeploy:deno install
Repository identity for Deno manifest builds comes from the persisted Build-context variable PLUGIN_MANIFEST_REPOSITORY.
Do not commit a deploy block in tracked deno.json or deno.jsonc. provision will fail fast if it finds one, because source config would override the action-managed dashboard config.
During provision, the action runs:
POST /v2/appswhen the app does not exist yet, using the managed config and synced env vars as app defaultsPATCH /v2/apps/{slug}for existing apps before deploydeno --unstable-kv deploy . --config <temporary deno.json|deno.jsonc> --prodas the single production deployment step for both newly created and existing branch appsdeno installanddeno x -y @ubiquity-os/plugin-manifest-tool@latestonly whenbuildManifest=trueWhenbuildManifest=true, this can create or updatemanifest.json, a temporary workspacedeno.jsonordeno.jsonc,node_modules, and related install artifacts in the checked-out workspace. Before each direct deploy, the action removesnode_modulesso Deno uploads only the workspace source, stages a standard Deno config file into the workspace for the upload itself, then restores the original config state after the deploy attempt. The staged config preserves the repo's tracked non-deployDeno settings and always includesunstable: ["kv"]soDeno.openKv()is available during the deploy runtime.
On first provision, this metadata-first create path avoids the extra bootstrap build that deno deploy create --source local would otherwise start before the explicit --prod deploy. The deploy step always includes --unstable-kv so workers that call Deno.openKv() can build without extra consumer-side workflow flags.
- Run
actions/checkout@v6beforeprovision. - Grant
contents: writeso the action can create/updatedist/*branches whenbuildManifest=true, and sodeletecan remove paireddist/*branches. - Use a Deno Deploy token with access to the target organization.
- Optionally wire
DENO_ORG_NAMEfrom${{ vars.DENO_ORG_NAME }}if you want a deterministic fallback when token-based organization inference is unavailable. - Configure consumer workflows so
mainanddemouse the GitHubmainenvironment, while all other branches use the GitHubdevelopmentenvironment.
name: Deno Deploy
on:
push:
branches-ignore:
- dist/**
delete:
jobs:
provision:
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: write
environment: ${{ (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/demo') && 'main' || 'development' }}
steps:
- uses: actions/checkout@v6
- uses: ubiquity-os/deno-deploy@main
env:
DENO_ORG_NAME: ${{ vars.DENO_ORG_NAME }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
action: provision
token: ${{ secrets.DENO_DEPLOY_TOKEN }}
app: ${{ vars.DENO_PROJECT_NAME }}
entrypoint: src/worker.ts
buildManifest: true
delete-branch-app:
if: github.event_name == 'delete'
runs-on: ubuntu-latest
permissions:
contents: write
environment: ${{ (github.event.ref == 'main' || github.event.ref == 'demo') && 'main' || 'development' }}
steps:
- uses: ubiquity-os/deno-deploy@main
env:
DENO_ORG_NAME: ${{ vars.DENO_ORG_NAME }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
action: delete
token: ${{ secrets.DENO_DEPLOY_TOKEN }}
app: ${{ vars.DENO_PROJECT_NAME }}deno run \
--allow-env \
--allow-read=.,../command-start-stop,./local.env \
--allow-write=.,./summary.md \
--allow-run=git,deno \
--allow-net=api.deno.com,api.github.com,console.deno.com \
./scripts/provision.js \
--repo-root ../command-start-stop \
--token "$DENO_DEPLOY_TOKEN" \
--github-owner ubiquity-os-marketplace \
--github-repo command-start-stop \
--ref-name demo \
--default-branch development \
--app command-start-stop-demo \
--entrypoint src/worker.ts \
--build-manifest=true \
--env-file ./local.env \
--dry-runIf token-based organization inference is unavailable locally, set DENO_ORG_NAME=ubiquity-os instead of passing --organization.
For cross-repo local testing before publishing @ubiquity-os/plugin-manifest-tool, you can point provision at a local checkout by setting PLUGIN_MANIFEST_TOOL_PATH=/abs/path/to/plugin-manifest-tool/bin/plugin-manifest-tool.js and adding node to --allow-run.