feat: add npm nightly release channel (#2126)

This commit is contained in:
José Almeida
2026-08-04 00:45:50 +01:00
committed by GitHub
parent f985ef1ff9
commit 1d5c3e3f5f
87 changed files with 7253 additions and 446 deletions
+179 -26
View File
@@ -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