Skip to content

chore(deps-dev): bump @angular/core from 22.0.0 to 22.0.1 #1875

chore(deps-dev): bump @angular/core from 22.0.0 to 22.0.1

chore(deps-dev): bump @angular/core from 22.0.0 to 22.0.1 #1875

Workflow file for this run

name: ci
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
# Cancel an in-flight run when a newer commit is pushed to the same PR/branch.
# Main runs may publish releases, so do not cancel them once started.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
detect-alpha-release:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: depot-ubuntu-24.04-4
timeout-minutes: 5
outputs:
should_release: ${{ steps.detect.outputs.should_release }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Detect release-relevant changes
id: detect
env:
BEFORE: ${{ github.event.before }}
run: |
set -euo pipefail
base="$BEFORE"
if [ -z "$base" ] || [[ "$base" =~ ^0+$ ]] || ! git cat-file -e "$base^{commit}" 2>/dev/null; then
base="$(git rev-parse HEAD^ 2>/dev/null || true)"
fi
if [ -n "$base" ]; then
git diff --name-only "$base" HEAD > "$RUNNER_TEMP/release-changed-files"
else
git diff-tree --no-commit-id --name-only -r HEAD > "$RUNNER_TEMP/release-changed-files"
fi
node --input-type=module <<'NODE'
import { appendFileSync, readFileSync } from "node:fs";
import { PUBLIC_PACKAGE_MANIFESTS } from "./scripts/release-alpha-train.mjs";
const changed = readFileSync(`${process.env.RUNNER_TEMP}/release-changed-files`, "utf8")
.split("\n")
.map((line) => line.trim())
.filter(Boolean);
const publicPackageReleasePaths = new Set(
PUBLIC_PACKAGE_MANIFESTS.flatMap((manifestPath) => [
manifestPath,
manifestPath.replace(/package\.json$/, "CHANGELOG.md"),
]),
);
const releaseRelevant = changed.filter(
(path) => path.startsWith(".changeset/") || publicPackageReleasePaths.has(path),
);
const shouldRelease = releaseRelevant.length > 0;
console.log(`release-relevant changes: ${releaseRelevant.join(", ") || "none"}`);
appendFileSync(process.env.GITHUB_OUTPUT, `should_release=${String(shouldRelease)}\n`);
NODE
openapi-lint:
runs-on: depot-ubuntu-24.04-4
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- name: Set up node
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
- name: Lint OpenAPI spec
run: npx --yes @redocly/cli@2.31.5 lint api/openapi/openapi-spec.yaml --format=github-actions
go-unit-test:
runs-on: depot-ubuntu-24.04-8
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: true
- name: Verify gofmt formatting
run: |
unformatted="$(git ls-files -z -- '*.go' | xargs -0 -r gofmt -l)"
if [ -n "$unformatted" ]; then
printf '%s\n' "$unformatted"
exit 1
fi
- run: go generate ./...
- name: Verify generated code is up to date
run: |
git diff --stat --exit-code -- .
test -z "$(git status --porcelain)"
- run: go vet ./...
# Unit tests only. The DB-backed tests live behind the `postgres_integration` /
# `spanner_integration` build tags and run in the dedicated jobs below, so
# this job needs neither the postgres runtime deps nor the binary cache.
- run: go test -v -timeout=10m ./...
go-integration-test-postgres:
runs-on: depot-ubuntu-24.04-4
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: true
# Postgres integration tests run against a Docker testcontainer (mirroring
# the spanner job); the Depot Ubuntu runner ships Docker, so no embedded-postgres
# runtime deps or Maven binary cache are needed here.
- name: Postgres integration tests
run: |
mkdir -p test-output/go
set -o pipefail
go test -json -v -tags postgres_integration -timeout=10m ./... | tee test-output/go/postgres-integration.json
- name: Upload Postgres test log on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: postgres-integration-test-log
path: test-output/go/postgres-integration.json
if-no-files-found: ignore
retention-days: 7
go-integration-test-spanner:
runs-on: depot-ubuntu-24.04-4
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: true
# Spanner tests use a Docker testcontainer emulator, not the embedded
# postgres binary, so no Maven binary cache is needed here.
- run: go test -v -tags spanner_integration -timeout=10m ./...
goreleaser-snapshot:
runs-on: depot-ubuntu-24.04-8
timeout-minutes: 20
needs: [go-unit-test, go-integration-test-postgres, go-integration-test-spanner, node-check]
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Prune npm package tags for GoReleaser
run: |
# Changesets creates scoped package tags such as @zitadel/sdk-nuxt@0.1.0-alpha.0.
# GoReleaser should derive server versions only from server release tags.
git tag -l '@zitadel/*' | while read -r tag; do
git tag -d "$tag"
done
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: true
- name: Set up pnpm
uses: pnpm/action-setup@v5
with:
run_install: false
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: pnpm
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Run GoReleaser (snapshot)
uses: goreleaser/goreleaser-action@v7
with:
distribution: goreleaser
version: "~> v2"
args: release --snapshot --clean --skip=publish,sign
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Export Docker image for smoke tests
run: |
# Goreleaser builds linux/amd64 and linux/arm64 with the same tag; pin amd64
# for the linux/amd64 smoke jobs (see quickstart-smoke).
IMAGE_ID=""
IMAGE_REF=""
for id in $(docker images ghcr.io/zitadel/nextgen --format '{{.ID}}' | sort -u); do
arch=$(docker image inspect -f '{{.Architecture}}' "$id")
ref=$(docker image inspect -f '{{index .RepoTags 0}}' "$id")
case "$ref" in *snapshot*) ;; *) continue ;; esac
if [ "$arch" = "amd64" ]; then
IMAGE_ID="$id"
IMAGE_REF="$ref"
break
fi
done
if [ -z "$IMAGE_ID" ]; then
echo "::error::no linux/amd64 snapshot image found for ghcr.io/zitadel/nextgen"
docker images ghcr.io/zitadel/nextgen
exit 1
fi
# Save by a stable local tag: docker save by ID drops repo tags from the tarball.
CI_IMAGE="ghcr.io/zitadel/nextgen:ci-snapshot-smoke-amd64"
docker tag "$IMAGE_ID" "$CI_IMAGE"
echo "$CI_IMAGE" > dist/nextgen-image.tag
docker save "$CI_IMAGE" -o dist/nextgen-image.tar
- name: Upload GoReleaser snapshot artifacts
uses: actions/upload-artifact@v7
with:
name: goreleaser-snapshot
path: dist/**
if-no-files-found: error
retention-days: 7
go-smoke-test-embedded-postgres:
runs-on: depot-ubuntu-24.04-4
timeout-minutes: 15
needs: [goreleaser-snapshot]
steps:
- uses: actions/checkout@v6
- name: Download GoReleaser snapshot
uses: actions/download-artifact@v6
with:
name: goreleaser-snapshot
path: goreleaser-dist
# Boots the Goreleaser-built binary directly on the embedded-postgres
# default connector. This proves the single binary starts, migrates, and
# handles SIGTERM; Docker image and quick-start surfaces are covered below.
- name: Install embedded-postgres runtime deps
run: sudo apt-get update -qq && sudo apt-get install -y -qq libicu-dev libssl-dev
- name: Cache embedded-postgres binary
uses: actions/cache@v5
with:
path: ~/.embedded-postgres-go
key: embedded-postgres-${{ runner.os }}-${{ hashFiles('go.sum') }}
- name: Extract linux/amd64 server binary
run: |
TARBALL="$(find goreleaser-dist -name 'nextgen_*_linux_amd64.tar.gz' | head -1)"
test -n "$TARBALL"
tar -xzf "$TARBALL" -C .
test -x ./nextgen
chmod +x ./nextgen
- name: Smoke test (start, migrate, graceful exit 0)
run: |
./nextgen > server.log 2>&1 &
pid=$!
# "server listening" is logged only after embedded PG is up, migrations
# ran, and services wired; the generous timeout covers a cold Maven download.
ready=0
for i in $(seq 1 240); do
if grep -q "server listening for requests" server.log; then ready=1; break; fi
if ! kill -0 "$pid" 2>/dev/null; then
echo "::error::server exited before becoming ready"; cat server.log; exit 1
fi
sleep 1
done
if [ "$ready" -ne 1 ]; then
echo "::error::timed out waiting for server readiness"; cat server.log
kill -TERM "$pid" 2>/dev/null || true; exit 1
fi
test -f nextgen-data/server-encryption-key
kill -TERM "$pid"
code=0; wait "$pid" || code=$?
cat server.log
[ "$code" -eq 0 ] || { echo "::error::non-zero exit after SIGTERM: $code"; exit 1; }
echo "embedded-postgres smoke test passed (start, migrate, graceful exit 0)"
node-check:
runs-on: depot-ubuntu-24.04-8
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
- name: Set up pnpm
uses: pnpm/action-setup@v5
with:
run_install: false
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: pnpm
- name: Install dependencies
run: corepack pnpm install --frozen-lockfile
- name: Node checks
run: corepack pnpm nx run-many -t lint,typecheck,build,test
changeset-check:
# Gate PRs: fail when a PR changes a public npm package without adding a
# changeset, so no consumer-visible change merges without a release note.
# Private packages (apps, demos, mocks, lint, design-tokens, ui-react, ...)
# are never published and so do not require a changeset. Publishing itself
# runs on pushes to main in the release-alpha-train job below.
#
# The check lives in scripts/check-changeset-required.mjs so the publishable
# package list and rules are testable and shared, rather than duplicated in
# inline shell.
#
# Skip the Changesets "Version Packages" PR: it legitimately edits public
# package manifests/changelogs and *removes* changesets (consuming them),
# which would otherwise trip this gate.
if: github.event_name == 'pull_request' && github.head_ref != 'changeset-release/main'
runs-on: depot-ubuntu-24.04-4
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
with:
# Full history so we can diff against the PR base branch.
fetch-depth: 0
- name: Require a changeset for public package changes
run: |
git fetch --no-tags origin "${{ github.base_ref }}"
node scripts/check-changeset-required.mjs --base "origin/${{ github.base_ref }}"
quickstart-smoke:
runs-on: depot-ubuntu-24.04-4
timeout-minutes: 20
needs: [goreleaser-snapshot]
env:
GHCR_READONLY_TOKEN: ${{ secrets.GHCR_READONLY_TOKEN }}
steps:
- uses: actions/checkout@v6
- name: Download GoReleaser snapshot
uses: actions/download-artifact@v6
with:
name: goreleaser-snapshot
path: goreleaser-dist
- name: Load snapshot Docker image
run: |
test -f goreleaser-dist/nextgen-image.tar
test -f goreleaser-dist/nextgen-image.tag
docker load -i goreleaser-dist/nextgen-image.tar
docker image inspect -f '{{.Os}}/{{.Architecture}}' "$(cat goreleaser-dist/nextgen-image.tag)" | grep -q '^linux/amd64$'
- name: Prepare quick-start compose stack
run: |
mkdir -p nextgen_quickstart
cp docs/operations/docker-compose.yaml nextgen_quickstart/docker-compose.yaml
IMAGE="$(cat goreleaser-dist/nextgen-image.tag)"
{
echo "NEXTGEN_IMAGE=${IMAGE}"
echo "NEXTGEN_PORT=8080"
} > nextgen_quickstart/.env
docker compose -f nextgen_quickstart/docker-compose.yaml --env-file nextgen_quickstart/.env config >/dev/null
- name: Optional GHCR auth-path smoke check
if: ${{ env.GHCR_READONLY_TOKEN != '' }}
env:
GH_USER: ${{ github.repository_owner }}
run: |
echo "$GHCR_READONLY_TOKEN" | docker login ghcr.io -u "$GH_USER" --password-stdin
docker logout ghcr.io
- name: GHCR auth-path smoke check skipped
if: ${{ env.GHCR_READONLY_TOKEN == '' }}
run: echo "Skipping GHCR login smoke check because GHCR_READONLY_TOKEN is not configured."
- name: Start stack and verify HTTP endpoints
run: |
set -euo pipefail
# Separate from the customer local setup journey: this keeps the
# documented compose fallback valid for operators/manual quick-start
# usage.
COMPOSE=(docker compose -f nextgen_quickstart/docker-compose.yaml --env-file nextgen_quickstart/.env)
"${COMPOSE[@]}" up -d --wait
ready=0
for _ in $(seq 1 60); do
if curl -fsS http://localhost:8080/healthz >/dev/null; then
ready=1
break
fi
sleep 1
done
if [ "$ready" -ne 1 ]; then
echo "::error::timed out waiting for /healthz"
docker image inspect -f 'platform={{.Os}}/{{.Architecture}}' "$(cat goreleaser-dist/nextgen-image.tag)" || true
"${COMPOSE[@]}" logs nextgen || true
exit 1
fi
if ! curl -fsS -o /dev/null -w "%{http_code}\n" http://localhost:8080/ui/console/ | grep -q '^200$'; then
echo "::error::/ui/console/ did not return 200"
"${COMPOSE[@]}" logs nextgen || true
exit 1
fi
if ! curl -fsS -o /dev/null -w "%{http_code}\n" http://localhost:8080/ui/login/ | grep -q '^200$'; then
echo "::error::/ui/login/ did not return 200"
"${COMPOSE[@]}" logs nextgen || true
exit 1
fi
echo "quickstart compose smoke test passed"
- name: Tear down compose stack
if: always()
run: |
if [ -f nextgen_quickstart/.env ]; then
docker compose -f nextgen_quickstart/docker-compose.yaml --env-file nextgen_quickstart/.env down -v
else
echo "Skipping compose teardown because nextgen_quickstart/.env was not created."
fi
node-e2e:
runs-on: depot-ubuntu-24.04-4
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
- name: Set up pnpm
uses: pnpm/action-setup@v5
with:
run_install: false
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: pnpm
- name: Install dependencies
run: corepack pnpm install --frozen-lockfile
# The Playwright cache is keyed by the resolved version in
# pnpm-lock.yaml so a Playwright bump invalidates it automatically.
# Browsers live under ~/.cache/ms-playwright on Linux.
- name: Restore Playwright browsers
id: playwright-cache
uses: actions/cache@v5
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
# `pnpm exec` from the workspace root cannot find the `playwright`
# binary on a clean CI checkout because @playwright/test is a dep of
# the e2e packages only, not of root. Scoping the exec with --filter
# routes through that workspace's node_modules/.bin.
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: >-
corepack pnpm --filter @zitadel/demo-next-e2e
exec playwright install --with-deps chromium
- name: Install Playwright system deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: >-
corepack pnpm --filter @zitadel/demo-next-e2e
exec playwright install-deps chromium
# Boots the demo dev servers + api-mock through Playwright's webServer
# config; Nx rebuilds @zitadel/components first via ^build.
# console-e2e has no specs yet — it's intentionally excluded until
# Playwright would otherwise fail with "no tests found".
#
# demo-next-e2e and demo-nuxt-e2e use distinct api-mock ports
# (4000 / 4001) so Nx can run them in parallel without EADDRINUSE.
- name: End-to-end tests
run: >-
corepack pnpm nx run-many -t e2e
-p @zitadel/demo-next-e2e,@zitadel/demo-nuxt-e2e
- name: Upload Playwright reports on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: playwright-report
path: |
apps/demo-next-e2e/test-output/playwright/report/**
apps/demo-nuxt-e2e/test-output/playwright/report/**
apps/demo-next-e2e/test-output/playwright/output/**
apps/demo-nuxt-e2e/test-output/playwright/output/**
if-no-files-found: ignore
retention-days: 7
npm-pack-smoke:
runs-on: depot-ubuntu-24.04-4
timeout-minutes: 15
needs: node-check
steps:
- uses: actions/checkout@v6
- name: Set up pnpm
uses: pnpm/action-setup@v5
with:
run_install: false
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: pnpm
- name: Install dependencies
run: corepack pnpm install --frozen-lockfile
- name: Build packages
run: corepack pnpm nx run-many -t build
- name: Smoke test built CLI
run: |
node apps/cli/bin/run.js --version
node apps/cli/bin/run.js commands
- name: Dry-run npm packs
run: |
for dir in apps/cli packages/api packages/components packages/sdk-core packages/sdk-next packages/sdk-nuxt packages/sdk-react packages/sdk-vue packages/sdk-angular; do
corepack pnpm --dir "$dir" pack --dry-run
done
- name: Create npm package artifacts
run: |
mkdir -p "$RUNNER_TEMP/zitadel-npm-packages"
for dir in apps/cli packages/api packages/components packages/sdk-core packages/sdk-next packages/sdk-nuxt packages/sdk-react packages/sdk-vue packages/sdk-angular; do
corepack pnpm --dir "$dir" pack --pack-destination "$RUNNER_TEMP/zitadel-npm-packages"
done
ls -lh "$RUNNER_TEMP/zitadel-npm-packages"
- name: Verify npm package artifacts
run: node apps/cli-journey-e2e/scripts/verify-tarballs.mjs "$RUNNER_TEMP/zitadel-npm-packages"
- name: Upload npm package artifacts
uses: actions/upload-artifact@v7
with:
name: npm-packages
path: ${{ runner.temp }}/zitadel-npm-packages/*.tgz
if-no-files-found: error
retention-days: 7
consumer-journey-e2e:
runs-on: depot-ubuntu-24.04-4
timeout-minutes: 35
needs: [goreleaser-snapshot, npm-pack-smoke]
steps:
- uses: actions/checkout@v6
- name: Set up pnpm
uses: pnpm/action-setup@v5
with:
run_install: false
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: pnpm
- name: Install dependencies
run: corepack pnpm install --frozen-lockfile
- name: Download GoReleaser snapshot
uses: actions/download-artifact@v6
with:
name: goreleaser-snapshot
path: goreleaser-dist
- name: Download npm package artifacts
uses: actions/download-artifact@v6
with:
name: npm-packages
path: ${{ runner.temp }}/zitadel-npm-packages
- name: Restore Playwright browsers
id: playwright-cache
uses: actions/cache@v5
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: >-
corepack pnpm --filter @zitadel/cli-journey-e2e
exec playwright install --with-deps chromium
- name: Install Playwright system deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: >-
corepack pnpm --filter @zitadel/cli-journey-e2e
exec playwright install-deps chromium
- name: Start temporary npm registry
env:
VERDACCIO_CONFIG: ${{ runner.temp }}/verdaccio/config.yaml
VERDACCIO_LOG: ${{ runner.temp }}/verdaccio.log
VERDACCIO_NPMRC: ${{ runner.temp }}/verdaccio.npmrc
VERDACCIO_STORAGE: ${{ runner.temp }}/verdaccio/storage
run: |
mkdir -p "$(dirname "$VERDACCIO_CONFIG")" "$VERDACCIO_STORAGE"
cat > "$VERDACCIO_CONFIG" <<EOF
storage: $VERDACCIO_STORAGE
uplinks:
npmjs:
url: https://registry.npmjs.org/
packages:
'@zitadel/*':
access: \$all
publish: \$all
unpublish: \$all
'@*/*':
access: \$all
publish: \$all
unpublish: \$all
proxy: npmjs
'**':
access: \$all
publish: \$all
unpublish: \$all
proxy: npmjs
logs:
- { type: stdout, format: pretty, level: http }
EOF
npm exec --yes verdaccio@6.2.2 -- --config "$VERDACCIO_CONFIG" --listen 127.0.0.1:4873 > "$VERDACCIO_LOG" 2>&1 &
echo "VERDACCIO_PID=$!" >> "$GITHUB_ENV"
ready=0
for _ in $(seq 1 60); do
if curl -fsS http://127.0.0.1:4873/-/ping >/dev/null; then
ready=1
break
fi
sleep 1
done
if [ "$ready" -ne 1 ]; then
echo "::error::timed out waiting for Verdaccio"
cat "$VERDACCIO_LOG"
exit 1
fi
{
echo "registry=http://127.0.0.1:4873/"
echo "//127.0.0.1:4873/:_authToken=journey-token"
echo "always-auth=true"
} > "$VERDACCIO_NPMRC"
- name: Publish current npm packages to temporary registry
env:
JOURNEY_REGISTRY_URL: http://127.0.0.1:4873
NPM_CONFIG_USERCONFIG: ${{ runner.temp }}/verdaccio.npmrc
run: >-
node apps/cli-journey-e2e/scripts/publish-tarballs.mjs
"$RUNNER_TEMP/zitadel-npm-packages"
- name: Load snapshot Docker image
run: |
test -f goreleaser-dist/nextgen-image.tar
test -f goreleaser-dist/nextgen-image.tag
docker load -i goreleaser-dist/nextgen-image.tar
docker image inspect -f '{{.Os}}/{{.Architecture}}' "$(cat goreleaser-dist/nextgen-image.tag)" | grep -q '^linux/amd64$'
echo "ZITADEL_LOCAL_IMAGE=$(cat goreleaser-dist/nextgen-image.tag)" >> "$GITHUB_ENV"
- name: Prepare fresh Next.js app
id: prepare-app
env:
JOURNEY_REGISTRY_URL: http://127.0.0.1:4873
JOURNEY_WORK_DIR: ${{ runner.temp }}/zitadel-cli-journey
run: node apps/cli-journey-e2e/scripts/prepare-next-app.mjs
- name: Start generated Next.js app
run: |
cd "$JOURNEY_APP_DIR"
npm run dev -- --hostname localhost --port 3000 > "$RUNNER_TEMP/next-app.log" 2>&1 &
echo "NEXT_APP_PID=$!" >> "$GITHUB_ENV"
for _ in $(seq 1 90); do
if curl -fsS http://localhost:3000/login >/dev/null; then
exit 0
fi
sleep 1
done
echo "::error::timed out waiting for generated Next.js app"
cat "$RUNNER_TEMP/next-app.log"
exit 1
- name: Run consumer journey Playwright tests
run: >-
corepack pnpm --filter @zitadel/cli-journey-e2e
exec playwright test --config playwright.config.mts
- name: Collect diagnostics
if: failure()
run: |
DIAG_DIR="$RUNNER_TEMP/consumer-journey-diagnostics"
APP_DIR="$RUNNER_TEMP/zitadel-cli-journey/myapp"
mkdir -p "$DIAG_DIR/generated-app"
if [ -d "$APP_DIR" ]; then
(
cd "$APP_DIR"
npm_config_registry=http://127.0.0.1:4873 \
npm_config_yes=true \
npm_config_audit=false \
npm_config_fund=false \
npx --yes @zitadel/cli@alpha logs --tail 400 --non-interactive --json \
> "$DIAG_DIR/logs.json" 2> "$DIAG_DIR/logs.stderr.log"
) || true
fi
cp "$RUNNER_TEMP/next-app.log" "$DIAG_DIR/" 2>/dev/null || true
cp "$RUNNER_TEMP/verdaccio.log" "$DIAG_DIR/" 2>/dev/null || true
cp "$RUNNER_TEMP/zitadel-cli-journey/doctor.json" "$DIAG_DIR/" 2>/dev/null || true
cp "$RUNNER_TEMP/zitadel-cli-journey/doctor.stderr.log" "$DIAG_DIR/" 2>/dev/null || true
cp "$RUNNER_TEMP/zitadel-cli-journey/start.json" "$DIAG_DIR/" 2>/dev/null || true
cp "$RUNNER_TEMP/zitadel-cli-journey/start.stderr.log" "$DIAG_DIR/" 2>/dev/null || true
cp "$RUNNER_TEMP/zitadel-cli-journey/setup.json" "$DIAG_DIR/" 2>/dev/null || true
cp "$RUNNER_TEMP/zitadel-cli-journey/setup.stderr.log" "$DIAG_DIR/" 2>/dev/null || true
cp "$RUNNER_TEMP/zitadel-cli-journey/metadata.json" "$DIAG_DIR/" 2>/dev/null || true
cp "$APP_DIR/.zitadel/local/runtime.json" "$DIAG_DIR/runtime.json" 2>/dev/null || true
cp "$APP_DIR/package.json" "$DIAG_DIR/generated-app/" 2>/dev/null || true
cp "$APP_DIR/package-lock.json" "$DIAG_DIR/generated-app/" 2>/dev/null || true
- name: Upload consumer journey diagnostics
if: failure()
uses: actions/upload-artifact@v7
with:
name: consumer-journey-diagnostics
path: |
apps/cli-journey-e2e/test-output/playwright/report/**
apps/cli-journey-e2e/test-output/playwright/output/**
${{ runner.temp }}/consumer-journey-diagnostics/**
if-no-files-found: ignore
retention-days: 7
- name: Tear down consumer journey services
if: always()
run: |
if [ -n "${NEXT_APP_PID:-}" ]; then kill "$NEXT_APP_PID" 2>/dev/null || true; fi
APP_DIR="$RUNNER_TEMP/zitadel-cli-journey/myapp"
if [ -d "$APP_DIR" ]; then
(
cd "$APP_DIR"
npm_config_registry=http://127.0.0.1:4873 \
npm_config_yes=true \
npm_config_audit=false \
npm_config_fund=false \
npx --yes @zitadel/cli@alpha reset --force --non-interactive --json
) || true
fi
if [ -n "${VERDACCIO_PID:-}" ]; then kill "$VERDACCIO_PID" 2>/dev/null || true; fi
ci-success:
if: always()
runs-on: depot-ubuntu-24.04-4
timeout-minutes: 5
needs:
- openapi-lint
- go-unit-test
- go-integration-test-postgres
- go-integration-test-spanner
- node-check
- changeset-check
- node-e2e
- goreleaser-snapshot
- npm-pack-smoke
- go-smoke-test-embedded-postgres
- quickstart-smoke
- consumer-journey-e2e
steps:
- name: Check CI gate results
env:
NEEDS_JSON: ${{ toJson(needs) }}
run: |
node <<'NODE'
const needs = JSON.parse(process.env.NEEDS_JSON);
const allowedSkipped = new Set(["changeset-check"]);
const failed = Object.entries(needs).filter(([name, job]) => {
if (job.result === "success") return false;
if (job.result === "skipped" && allowedSkipped.has(name)) return false;
return true;
});
if (failed.length > 0) {
for (const [name, job] of failed) {
console.error(`${name}: ${job.result}`);
}
process.exit(1);
}
console.log("CI gate passed");
NODE
release-alpha-train:
if: always() && github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.detect-alpha-release.result == 'success' && needs.ci-success.result == 'success' && needs.detect-alpha-release.outputs.should_release == 'true'
runs-on: depot-ubuntu-24.04-8
needs: [detect-alpha-release, ci-success]
permissions:
contents: write
pull-requests: write
packages: write
id-token: write
steps:
# Mint a short-lived installation token for the release GitHub App so the
# changesets PR/commits trigger CI (GITHUB_TOKEN-authored ones do not).
- name: Generate a token for the release app
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.RELEASE_APP_ID }}
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- name: Set up pnpm
uses: pnpm/action-setup@v5
with:
run_install: false
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
registry-url: "https://registry.npmjs.org"
cache: pnpm
# Trusted publishing requires npm >= 11.5.1; the pinned pnpm delegates
# the actual publish to the npm CLI, so the runner's npm must be current.
- name: Update npm for trusted publishing (OIDC)
run: npm install -g npm@latest
- name: Install dependencies
run: corepack pnpm install --frozen-lockfile
- name: Build packages
run: corepack pnpm nx run-many -t build
- name: Prune empty changesets before publish decision
run: node scripts/release-alpha-train.mjs prune-empty-changesets
- name: Create release PR or publish to npm
id: changesets
uses: changesets/action@v1
with:
version: corepack pnpm changeset version
publish: corepack pnpm changeset publish
title: "chore: version packages"
commit: "chore: version packages"
createGithubReleases: false
env:
# App token (not GITHUB_TOKEN) so the Version Packages PR triggers CI.
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
# Empty so the action does not pass an undefined token; OIDC handles auth.
NPM_TOKEN: ""
# npm provenance is only supported for public source repositories.
# Keep trusted publishing via OIDC, but disable provenance until this
# repository is public.
NPM_CONFIG_PROVENANCE: "false"
- name: Restore changesets after publish decision
run: git restore -- .changeset
- name: Inspect alpha release train candidate
id: alpha-status
env:
PUBLISHED: ${{ steps.changesets.outputs.published }}
run: |
set -euo pipefail
alpha_env="$RUNNER_TEMP/alpha-release-status.env"
node scripts/release-alpha-train.mjs status --published "$PUBLISHED" --remote false | tee "$alpha_env"
cat "$alpha_env" >> "$GITHUB_OUTPUT"
- name: Login to GHCR
if: ${{ steps.alpha-status.outputs.should_complete == 'true' }}
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Prepare alpha release train
if: ${{ steps.alpha-status.outputs.should_complete == 'true' }}
id: alpha
env:
PUBLISHED: ${{ steps.changesets.outputs.published }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
alpha_env="$RUNNER_TEMP/alpha-release.env"
node scripts/release-alpha-train.mjs prepare --published "$PUBLISHED" --out-dir "$RUNNER_TEMP/alpha-release" | tee "$alpha_env"
cat "$alpha_env" >> "$GITHUB_OUTPUT"
- name: Refresh CLI npm dist-tags
if: ${{ steps.alpha.outputs.version != '' }}
env:
NPM_CONFIG_PROVENANCE: "false"
VERSION: ${{ steps.alpha.outputs.version }}
run: |
set -euo pipefail
version="$VERSION"
node --input-type=module - "$version" <<'NODE'
const version = process.argv[2];
if (!/^\d+\.\d+\.\d+-alpha\.\d+$/.test(version)) {
throw new Error(`expected an alpha CLI version, got ${version}`);
}
NODE
# Temporary public-alpha exception: the CLI is the tester entrypoint,
# so bare `npx @zitadel/cli` must reach the supported local workflow.
# Keep `alpha` as the canonical prerelease tag, and do not move
# `latest` for SDKs/components, Docker images, or GitHub Releases.
npm dist-tag add "@zitadel/cli@$version" alpha || echo "::warning::Unable to refresh @zitadel/cli@$version npm alpha dist-tag"
npm dist-tag add "@zitadel/cli@$version" latest || echo "::warning::Unable to promote @zitadel/cli@$version to npm latest dist-tag"
- name: Set up QEMU
if: ${{ steps.alpha.outputs.run_goreleaser == 'true' }}
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
if: ${{ steps.alpha.outputs.run_goreleaser == 'true' }}
uses: docker/setup-buildx-action@v4
- name: Create and push Go release tag
if: ${{ steps.alpha.outputs.create_tag == 'true' }}
env:
TAG: ${{ steps.alpha.outputs.tag }}
TITLE: ${{ steps.alpha.outputs.title }}
run: |
set -euo pipefail
git config user.name "zitadel-release"
git config user.email "noreply@zitadel.com"
git tag -a "$TAG" -m "$TITLE"
git push origin "$TAG"
- name: Check out existing Go release tag
if: ${{ steps.alpha.outputs.run_goreleaser == 'true' && steps.alpha.outputs.tag_exists == 'true' }}
env:
TAG: ${{ steps.alpha.outputs.tag }}
run: git checkout --detach "$TAG"
- name: Prune npm package tags for GoReleaser
if: ${{ steps.alpha.outputs.run_goreleaser == 'true' }}
run: |
set -euo pipefail
git tag -l '@zitadel/*' | while read -r tag; do
git tag -d "$tag"
done
- name: Run GoReleaser
if: ${{ steps.alpha.outputs.run_goreleaser == 'true' }}
uses: goreleaser/goreleaser-action@v7
with:
distribution: goreleaser
version: "~> v2"
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update GitHub Release notes
if: ${{ steps.alpha.outputs.update_release == 'true' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ steps.alpha.outputs.tag }}
TITLE: ${{ steps.alpha.outputs.title }}
NOTES_PATH: ${{ steps.alpha.outputs.notes_path }}
run: |
set -euo pipefail
gh release edit "$TAG" \
--draft \
--prerelease \
--latest=false \
--title "$TITLE" \
--notes-file "$NOTES_PATH"