feat: add npm nightly release channel (#2126)
This commit is contained in:
+179
-26
@@ -1,7 +1,7 @@
|
||||
name: release
|
||||
|
||||
# Maintainer-only release workflow.
|
||||
# Trigger: GitHub Actions UI → "Run workflow" (workflow_dispatch).
|
||||
# Stable releases are maintainer-dispatched. npm nightlies run from main at
|
||||
# 12:00 UTC when main has changed since the latest stable npm release.
|
||||
#
|
||||
# Flow (one click → everything below):
|
||||
# 1. prepare — bump version, regen CHANGELOG, open + merge release PR, push tag vX.Y.Z
|
||||
@@ -39,10 +39,20 @@ name: release
|
||||
# TAURI_SIGNING_PRIVATE_KEY / TAURI_SIGNING_PRIVATE_KEY_PASSWORD — updater artifact signing
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 12 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
channel:
|
||||
description: "Release channel"
|
||||
required: true
|
||||
type: choice
|
||||
default: stable
|
||||
options:
|
||||
- stable
|
||||
- nightly
|
||||
bump:
|
||||
description: "Version bump"
|
||||
description: "Stable only: version bump"
|
||||
required: true
|
||||
type: choice
|
||||
default: minor
|
||||
@@ -51,19 +61,26 @@ on:
|
||||
- minor
|
||||
- major
|
||||
dry_run:
|
||||
description: "Dry run (no PR, tag, npm publish, or tap update)"
|
||||
description: "Validate selected channel without publishing"
|
||||
type: boolean
|
||||
default: false
|
||||
desktop_validation_only:
|
||||
description: "Build desktop artifacts only (no PR, tag, publish, npm, or tap update)"
|
||||
description: "Stable only: build desktop artifacts without publishing"
|
||||
type: boolean
|
||||
default: false
|
||||
backfill_tag:
|
||||
description: "Existing release tag to rebuild/publish (for recovery; leave empty for normal release)"
|
||||
description: "Stable only: existing release tag to rebuild/publish"
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
|
||||
# A Stable tag is pushed before its npm job is ready. Serializing whole runs
|
||||
# prevents a Nightly from using the previous npm baseline during that window.
|
||||
concurrency:
|
||||
group: release-npm-publication
|
||||
cancel-in-progress: false
|
||||
queue: max
|
||||
|
||||
# Default to read-only at the workflow level. Each job opts into the writes
|
||||
# it actually needs.
|
||||
permissions:
|
||||
@@ -72,6 +89,7 @@ permissions:
|
||||
jobs:
|
||||
prepare:
|
||||
name: Prepare release (bump version, PR, tag)
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' }}
|
||||
runs-on: ubuntu-latest
|
||||
environment: ${{ (!inputs.dry_run && !inputs.desktop_validation_only && inputs.backfill_tag == '') && 'release' || 'release-validation' }}
|
||||
permissions:
|
||||
@@ -574,15 +592,91 @@ jobs:
|
||||
echo "DRY RUN: apps/cli/package.json bumped to $NEXT (in-runner only)."
|
||||
echo "DRY RUN: CHANGELOG.md regenerated (in-runner only)."
|
||||
|
||||
nightly-prepare:
|
||||
name: Prepare npm nightly metadata
|
||||
if: >-
|
||||
${{
|
||||
github.event_name == 'schedule' ||
|
||||
(github.event_name == 'workflow_dispatch' && inputs.channel == 'nightly')
|
||||
}}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_publish: ${{ steps.metadata.outputs.should_publish }}
|
||||
version: ${{ steps.metadata.outputs.version }}
|
||||
tag: ${{ steps.metadata.outputs.tag }}
|
||||
ref: ${{ steps.metadata.outputs.ref }}
|
||||
stable_version: ${{ steps.metadata.outputs.stable_version }}
|
||||
nightly_version_at_start: ${{ steps.metadata.outputs.nightly_version_at_start }}
|
||||
nightly_tags_at_start: ${{ steps.metadata.outputs.nightly_tags_at_start }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
ref: ${{ github.sha }}
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version: "24"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: Validate manual Nightly request
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
env:
|
||||
CURRENT_REF: ${{ github.ref }}
|
||||
DESKTOP_VALIDATION_ONLY: ${{ inputs.desktop_validation_only }}
|
||||
BACKFILL_TAG: ${{ inputs.backfill_tag }}
|
||||
BUMP: ${{ inputs.bump }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ "$CURRENT_REF" != "refs/heads/main" ]; then
|
||||
echo "Manual Nightlies must be dispatched from refs/heads/main (got $CURRENT_REF)." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$DESKTOP_VALIDATION_ONLY" = "true" ]; then
|
||||
echo "desktop_validation_only cannot be combined with channel=nightly." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ -n "$BACKFILL_TAG" ]; then
|
||||
echo "backfill_tag cannot be combined with channel=nightly." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "::notice::The Stable-only bump input ($BUMP) is ignored for Nightly."
|
||||
|
||||
- name: Resolve nightly metadata
|
||||
id: metadata
|
||||
run: |
|
||||
bash scripts/release/nightly-release.sh prepare \
|
||||
--scheduled-sha "${{ github.sha }}" \
|
||||
--output "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Nightly dry-run summary
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }}
|
||||
env:
|
||||
SHOULD_PUBLISH: ${{ steps.metadata.outputs.should_publish }}
|
||||
VERSION: ${{ steps.metadata.outputs.version }}
|
||||
REF: ${{ steps.metadata.outputs.ref }}
|
||||
run: |
|
||||
if [ "$SHOULD_PUBLISH" = "true" ]; then
|
||||
echo "DRY RUN: Would publish $VERSION from $REF under npm's nightly dist-tag."
|
||||
else
|
||||
echo "DRY RUN: Nightly preflight found no eligible publication."
|
||||
fi
|
||||
echo "DRY RUN: No bundles were built and npm was not changed."
|
||||
|
||||
build-web:
|
||||
name: Build web SPA
|
||||
needs: prepare
|
||||
if: ${{ !inputs.dry_run }}
|
||||
needs: [prepare, nightly-prepare]
|
||||
if: >-
|
||||
${{ !cancelled() && (
|
||||
(github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && needs.prepare.result == 'success' && !inputs.dry_run) ||
|
||||
((github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.channel == 'nightly' && !inputs.dry_run)) && needs.nightly-prepare.result == 'success' && needs.nightly-prepare.outputs.should_publish == 'true')
|
||||
) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
ref: ${{ needs.prepare.outputs.ref }}
|
||||
ref: ${{ needs.nightly-prepare.result == 'success' && needs.nightly-prepare.outputs.ref || needs.prepare.outputs.ref }}
|
||||
persist-credentials: false
|
||||
- uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5
|
||||
with:
|
||||
@@ -596,7 +690,7 @@ jobs:
|
||||
run: pnpm -C apps install --frozen-lockfile
|
||||
- name: Build web (Vite)
|
||||
env:
|
||||
KANDEV_VERSION: ${{ needs.prepare.outputs.tag }}
|
||||
KANDEV_VERSION: ${{ needs.nightly-prepare.result == 'success' && needs.nightly-prepare.outputs.tag || needs.prepare.outputs.tag }}
|
||||
VITE_KANDEV_API_PORT: ""
|
||||
VITE_KANDEV_DEBUG: ""
|
||||
run: pnpm -C apps --filter @kandev/web build
|
||||
@@ -608,8 +702,12 @@ jobs:
|
||||
|
||||
build-bundles:
|
||||
name: Build platform bundle (${{ matrix.platform }})
|
||||
needs: [prepare, build-web]
|
||||
if: ${{ !inputs.dry_run }}
|
||||
needs: [prepare, nightly-prepare, build-web]
|
||||
if: >-
|
||||
${{ !cancelled() && needs.build-web.result == 'success' && (
|
||||
(github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && needs.prepare.result == 'success' && !inputs.dry_run) ||
|
||||
((github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.channel == 'nightly' && !inputs.dry_run)) && needs.nightly-prepare.result == 'success' && needs.nightly-prepare.outputs.should_publish == 'true')
|
||||
) }}
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
@@ -642,7 +740,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
ref: ${{ needs.prepare.outputs.ref }}
|
||||
ref: ${{ needs.nightly-prepare.result == 'success' && needs.nightly-prepare.outputs.ref || needs.prepare.outputs.ref }}
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
|
||||
with:
|
||||
@@ -671,7 +769,7 @@ jobs:
|
||||
- name: Build backend binaries
|
||||
env:
|
||||
CC: ${{ matrix.cc || '' }}
|
||||
KANDEV_VERSION: ${{ needs.prepare.outputs.tag }}
|
||||
KANDEV_VERSION: ${{ needs.nightly-prepare.result == 'success' && needs.nightly-prepare.outputs.tag || needs.prepare.outputs.tag }}
|
||||
run: |
|
||||
test -f apps/backend/internal/webapp/embedded/generated/index.html
|
||||
cd apps/backend
|
||||
@@ -725,7 +823,7 @@ jobs:
|
||||
build-desktop:
|
||||
name: Build desktop app (${{ matrix.platform }})
|
||||
needs: [prepare, build-bundles]
|
||||
if: ${{ !inputs.dry_run }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && !inputs.dry_run }}
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
@@ -1271,7 +1369,7 @@ jobs:
|
||||
docker-amd64:
|
||||
name: Build & push container image (amd64)
|
||||
needs: [prepare, build-bundles]
|
||||
if: ${{ !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -1342,7 +1440,7 @@ jobs:
|
||||
docker-arm64:
|
||||
name: Build & push container image (arm64)
|
||||
needs: [prepare, build-bundles]
|
||||
if: ${{ !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
runs-on: ubuntu-24.04-arm
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -1401,7 +1499,7 @@ jobs:
|
||||
docker-manifest:
|
||||
name: Assemble multi-arch base manifest
|
||||
needs: [prepare, docker-amd64, docker-arm64]
|
||||
if: ${{ !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -1455,7 +1553,7 @@ jobs:
|
||||
docker-universal-amd64:
|
||||
name: Build & push universal image (amd64)
|
||||
needs: [prepare, docker-manifest]
|
||||
if: ${{ !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -1507,7 +1605,7 @@ jobs:
|
||||
docker-universal-arm64:
|
||||
name: Build & push universal image (arm64)
|
||||
needs: [prepare, docker-manifest]
|
||||
if: ${{ !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
runs-on: ubuntu-24.04-arm
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -1558,7 +1656,7 @@ jobs:
|
||||
# docker-universal-manifest is included in publish-release's `needs` so
|
||||
# its size gate (and any per-arch build failure) blocks the release.
|
||||
needs: [prepare, docker-universal-amd64, docker-universal-arm64]
|
||||
if: ${{ !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -1615,7 +1713,7 @@ jobs:
|
||||
publish-release:
|
||||
name: Publish GitHub release
|
||||
needs: [prepare, build-bundles, build-desktop, docker-universal-manifest]
|
||||
if: ${{ !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write # softprops/action-gh-release creates the release
|
||||
@@ -1765,7 +1863,7 @@ jobs:
|
||||
publish-npm:
|
||||
name: Publish npm packages
|
||||
needs: [prepare, publish-release]
|
||||
if: ${{ !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write # Required for OIDC trusted publishing
|
||||
@@ -1794,13 +1892,68 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
bash scripts/release/publish-npm.sh \
|
||||
"${{ needs.prepare.outputs.version }}" \
|
||||
"${{ needs.prepare.outputs.tag }}"
|
||||
--version "${{ needs.prepare.outputs.version }}" \
|
||||
--dist-tag latest \
|
||||
--release-tag "${{ needs.prepare.outputs.tag }}"
|
||||
|
||||
publish-npm-nightly:
|
||||
name: Publish npm nightly packages
|
||||
needs: [nightly-prepare, build-bundles]
|
||||
if: >-
|
||||
${{ !cancelled() &&
|
||||
(github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.channel == 'nightly' && !inputs.dry_run)) &&
|
||||
needs.nightly-prepare.result == 'success' &&
|
||||
needs.nightly-prepare.outputs.should_publish == 'true' &&
|
||||
needs.build-bundles.result == 'success'
|
||||
}}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write # Required for OIDC trusted publishing
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
ref: ${{ needs.nightly-prepare.outputs.ref }}
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5
|
||||
with:
|
||||
version: "9.15.9"
|
||||
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version: "24"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
cache: pnpm
|
||||
cache-dependency-path: apps/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm -C apps install --frozen-lockfile
|
||||
|
||||
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
|
||||
with:
|
||||
pattern: bundle-*
|
||||
path: dist/nightly-assets
|
||||
merge-multiple: true
|
||||
|
||||
- name: Publish npm nightly packages
|
||||
env:
|
||||
NIGHTLY_BASELINE: ${{ needs.nightly-prepare.outputs.stable_version }}
|
||||
NIGHTLY_AT_START: ${{ needs.nightly-prepare.outputs.nightly_version_at_start }}
|
||||
NIGHTLY_TAGS_AT_START: ${{ needs.nightly-prepare.outputs.nightly_tags_at_start }}
|
||||
run: |
|
||||
bash scripts/release/nightly-release.sh publish \
|
||||
--stable-at-start "$NIGHTLY_BASELINE" \
|
||||
--nightly-at-start "$NIGHTLY_AT_START" \
|
||||
--tags-at-start "$NIGHTLY_TAGS_AT_START" \
|
||||
--version "${{ needs.nightly-prepare.outputs.version }}" \
|
||||
--assets-dir dist/nightly-assets
|
||||
|
||||
update-homebrew-tap:
|
||||
name: Update Homebrew tap
|
||||
needs: [prepare, publish-release]
|
||||
if: ${{ !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.channel == 'stable' && !inputs.dry_run && !inputs.desktop_validation_only }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
Reference in New Issue
Block a user