Files
openprose__prose/.github/workflows/cli-release-check.yml
2026-05-18 20:49:51 -07:00

287 lines
8.0 KiB
YAML

name: CLI Release Check
on:
pull_request:
paths:
- "tools/cli/**"
- ".github/workflows/cli-release-check.yml"
- ".github/workflows/cli-real-harness-smoke.yml"
- ".github/workflows/cli-skills-smoke.yml"
- ".github/workflows/openprose-smoke.yml"
- ".github/workflows/release.yml"
- ".github/scripts/openprose-smoke/**"
- "scripts/release-preflight.sh"
- "scripts/bump-version.sh"
- ".version-bump.json"
push:
branches:
- main
paths:
- "tools/cli/**"
- ".github/workflows/cli-release-check.yml"
- ".github/workflows/cli-real-harness-smoke.yml"
- ".github/workflows/cli-skills-smoke.yml"
- ".github/workflows/openprose-smoke.yml"
- ".github/workflows/release.yml"
- ".github/scripts/openprose-smoke/**"
- "scripts/release-preflight.sh"
- "scripts/bump-version.sh"
- ".version-bump.json"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: cli-release-check-${{ github.ref }}
cancel-in-progress: true
jobs:
lint-shell-and-actions:
name: Lint shell and workflow files
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go for actionlint
uses: actions/setup-go@v5
with:
go-version: stable
cache: false
- name: Install actionlint
run: go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.7
- name: Lint GitHub Actions workflows
run: actionlint .github/workflows/cli-*.yml .github/workflows/plugin-manifest.yml .github/workflows/openprose-smoke.yml .github/workflows/release.yml
- name: Check installer shell syntax
run: bash -n tools/cli/install.sh
- name: Check release helper syntax
run: node --check tools/cli/scripts/build-release-tarball.mjs
- name: Check harness smoke helper syntax
run: node --check tools/cli/scripts/smoke-harness.mjs
- name: Check release shell syntax
run: |
bash -n scripts/bump-version.sh
bash -n scripts/release-preflight.sh
- name: OpenProse versions in sync
run: ./scripts/bump-version.sh --check
node-checks:
name: Node ${{ matrix.node-version }} checks
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
node-version:
- 18
- 20
- 22
defaults:
run:
working-directory: tools/cli
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: npm
cache-dependency-path: tools/cli/package-lock.json
- name: Install dependencies
run: npm ci
- name: Typecheck
run: npm run typecheck
- name: Test
run: npm test
- name: Build
run: npm run build
- name: Smoke built CLI
run: |
set -euo pipefail
node dist/index.js --help
node dist/index.js help
node dist/index.js run hello.prose.md --harness mock
PROSE_HARNESS=mock node dist/index.js status
npm-package-smoke:
name: npm package smoke
runs-on: ubuntu-latest
timeout-minutes: 20
defaults:
run:
working-directory: tools/cli
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: tools/cli/package-lock.json
- name: Install dependencies
run: npm ci
- name: Pack npm artifact
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/npm-pack"
npm pack --pack-destination "$RUNNER_TEMP/npm-pack" --json | tee npm-pack.json
- name: Validate npm package manifest
run: |
node --input-type=module <<'EOF'
import { readFileSync } from "node:fs";
const [pack] = JSON.parse(readFileSync("npm-pack.json", "utf8"));
const paths = new Set(pack.files.map((file) => file.path));
const required = ["package.json", "README.md", "LICENSE", "dist/index.js", "dist/index.d.ts"];
const forbiddenPrefixes = ["src/", "tests/", "node_modules/"];
for (const path of required) {
if (!paths.has(path)) {
throw new Error(`npm package is missing ${path}`);
}
}
for (const path of paths) {
if (forbiddenPrefixes.some((prefix) => path.startsWith(prefix))) {
throw new Error(`npm package includes ${path}`);
}
if (path.endsWith(".map")) {
throw new Error(`npm package includes sourcemap ${path}`);
}
}
EOF
- name: Smoke npm package artifact
run: |
set -euo pipefail
pack_file="$(node --input-type=module <<'EOF'
import { readFileSync } from "node:fs";
const [pack] = JSON.parse(readFileSync("npm-pack.json", "utf8"));
console.log(`${process.env.RUNNER_TEMP}/npm-pack/${pack.filename}`);
EOF
)"
prefix="$RUNNER_TEMP/npm-prefix"
npm install --global --prefix "$prefix" "$pack_file"
"$prefix/bin/prose" --version
"$prefix/bin/prose" run hello.prose.md --harness mock
import_dir="$RUNNER_TEMP/npm-import-smoke"
mkdir -p "$import_dir"
cd "$import_dir"
npm init -y
npm install "$pack_file"
node --input-type=module -e "await import('@openprose/prose-cli')"
- name: Dry-run npm publish
run: npm publish --dry-run
- name: Upload npm package metadata
uses: actions/upload-artifact@v4
with:
name: cli-npm-pack
path: tools/cli/npm-pack.json
if-no-files-found: error
release-tarball-smoke:
name: Release tarball smoke on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 25
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
defaults:
run:
working-directory: tools/cli
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: tools/cli/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Build and smoke release tarball
run: |
set -euo pipefail
release_dir="$RUNNER_TEMP/prose-release"
install_dir="$RUNNER_TEMP/prose-install"
bin_dir="$RUNNER_TEMP/prose-bin"
npm run release:tarball -- --out-dir "$release_dir" --skip-build
env \
PROSE_VERSION="$(node -p 'require("./package.json").version')" \
PROSE_BASE_URL="file://$release_dir" \
PROSE_INSTALL_DIR="$install_dir" \
PROSE_BIN_DIR="$bin_dir" \
sh install.sh
"$bin_dir/prose" --version
"$bin_dir/prose" run hello.prose.md --harness mock
- name: Upload release tarball
uses: actions/upload-artifact@v4
with:
name: cli-release-${{ runner.os }}-${{ runner.arch }}
path: ${{ runner.temp }}/prose-release/*
if-no-files-found: error
production-audit:
name: Production dependency audit
runs-on: ubuntu-latest
timeout-minutes: 15
defaults:
run:
working-directory: tools/cli
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: tools/cli/package-lock.json
- name: Install dependencies
run: npm ci
- name: Audit production dependencies
run: npm run audit:policy