Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE/promotion.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ The `Promotion gate` check directly depends on every constituent below and fails
| Exact-candidate clean install and startup | `Clean install and startup` | Pending |
| Real objects install, update, unload, delete | `Real objects install, update, unload, delete` | Pending |
| Aggregate | `Promotion gate` | Pending |
| Semantic version and notes | `Release plan` | Pending |

- [ ] The candidate SHA has not changed since every required check completed.
- [ ] The `Guard main branch source` and `Promotion gate` required contexts pass.
- [ ] The `Guard main branch source`, `Promotion gate`, and `Release plan` required contexts pass.
- [ ] The complete file and commit compare contains only reviewed work.
- [ ] PR conversations, review summaries, and all review threads have been read; actionable findings are addressed and required code-owner approvals exist.

Expand All @@ -47,6 +48,10 @@ List each unresolved issue and its disposition. Write `None` only after checking

Summarize behavioral changes. If no migration is required, state why.

### Release plan

Review the `Release Plan` workflow comment. Confirm the proposed semantic tag and deterministic notes describe the complete candidate, or confirm that the workflow reports a no-op. If the version is wrong, change the Conventional Commit history on `next` through a reviewed pull request before merging this promotion.

### Public-contract follow-ups

Link documentation and consumer follow-ups identified by the public-contract impact check. Write `None` only with a rationale.
Expand Down Expand Up @@ -102,4 +107,4 @@ Never force-push either persistent branch. Roll back with a reviewed revert comm

## Stable consumption boundary

Merging this promotion updates the Git-consumed stable `main` ref. It does not create a semantic tag or GitHub release. Any later tag is a separately approved action with its own release notes and exact-ref validation.
Merging this promotion updates the Git-consumed stable `main` ref and authorizes the reviewed release plan. When releasable commits exist, publication waits until every required workflow succeeds on the exact merge SHA, then creates the annotated tag and GitHub release automatically. A no-op plan creates neither. The signed manual tag path remains available for recovery.
100 changes: 100 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
name: Benchmark

# Non-blocking performance evidence (#553): every pull request into next is
# measured against its base, and the promotion pull request into main is
# measured against main. A regression above the thresholds is flagged in the
# job summary and the artifact; it never fails the job (ADR-0009: observed,
# not gated). Hosted runners vary, so compare only within one run, where the
# A/A control row shows the noise floor.

on:
pull_request:
branches: [next, main]
paths:
- "zi.zsh"
- "lib/**"
- "benchmarks/**"
- "tests/fixtures/package-manifests/**"
- ".github/workflows/benchmark.yml"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
compare:
name: Candidate versus baseline
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Check out candidate
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# A fork's head commit does not exist in this repository, so name the
# head repository explicitly; the checkout is read-only either way.
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.sha || github.sha }}
path: candidate
persist-credentials: false

- name: Check out baseline
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.base.sha || github.sha }}
path: baseline
persist-credentials: false

- name: Install Zsh and jq
run: sudo apt-get update && sudo apt-get install -yq zsh jq

- name: Measure baseline, candidate, and an A/A control
shell: bash
run: |
set -uo pipefail
# One invocation measures all three variants: within each round
# they run in a rotating order, with alternate cycles reversed, so
# every variant takes every position and drift on the runner is not
# correlated with a variant. The control is the baseline measured a
# second time. run.zsh exits 1 when a workload fails functionally,
# after writing every report, so that status is accepted here and
# the comparison step renders and returns it; usage and dependency
# errors (2) still fail this step. The step runs under the errexit
# that `shell: bash` inherits, so the status is captured on the
# command's own failure branch, which errexit does not act on.
status=0
zsh candidate/benchmarks/run.zsh \
--variant baseline=baseline --variant candidate=candidate --variant control=baseline \
--output-dir results || status=$?
if [[ "$status" -gt 1 ]]; then exit "$status"; fi

- name: Compare and publish the summary
shell: bash
run: |
set -euo pipefail
status=0
zsh candidate/benchmarks/compare.zsh --baseline results/baseline.json --candidate results/candidate.json \
--control results/control.json --output benchmark-comparison.json --markdown benchmark-comparison.md || status=$?
cat benchmark-comparison.md >> "$GITHUB_STEP_SUMMARY"
flagged="$(jq -r '.flagged | join(", ")' benchmark-comparison.json)"
if [[ -n "$flagged" ]]; then
echo "::notice title=Benchmark flag::Cases above the regression thresholds, for review: ${flagged}"
fi
# A functional failure means a workload no longer runs; that is a
# defect, not a timing question, and it fails the job.
exit "$status"

- name: Upload benchmark evidence
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: benchmark-${{ github.event.pull_request.head.sha || github.sha }}
path: |
results/
benchmark-comparison.json
benchmark-comparison.md
retention-days: 90
15 changes: 12 additions & 3 deletions .github/workflows/promotion-readiness.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.sha }}

- name: Install Zsh and archive tools
run: sudo apt-get update && sudo apt-get install -yq zsh zip unzip
- name: Install Zsh, jq, and archive tools
run: sudo apt-get update && sudo apt-get install -yq zsh jq zip unzip

- name: Check and compile Zsh sources
shell: bash
Expand Down Expand Up @@ -68,9 +68,18 @@ jobs:
if: ${{ hashFiles('tests/snippet-directory-mirror.zsh') != '' }}
run: zsh -f tests/snippet-directory-mirror.zsh

- name: Test release planning
run: zsh -f tests/release-plan.zsh

- name: Test promotion release verification
run: zsh -f tests/promotion-release-verification.zsh

- name: Test idempotent promotion publication
run: zsh -f tests/promotion-release-publication.zsh

zd:
name: ZD integration
uses: z-shell/zd/.github/workflows/test-native.yml@01c3477e48c0c31bb7225986bb1bac4270e151ff # z-shell/zd#121
uses: z-shell/zd/.github/workflows/test-native.yml@5d160597c909a23f03b7a07ff9d43793a106f3e8 # z-shell/zd#123
with:
zi_repo: ${{ github.event.pull_request.head.repo.full_name }}
zi_ref: ${{ github.event.pull_request.head.sha }}
Expand Down
75 changes: 75 additions & 0 deletions .github/workflows/release-plan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
name: Release Plan

on:
pull_request:
branches: [main]
types: [opened, reopened, synchronize, ready_for_review]
workflow_dispatch: {}

permissions:
contents: read
pull-requests: write

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
plan:
name: Release plan
runs-on: ubuntu-latest
steps:
- name: Check out the candidate
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0
fetch-tags: true
persist-credentials: false

- name: Install Zsh
run: sudo apt-get update && sudo apt-get install -yq zsh

- name: Compute release plan
id: release
if: "${{ github.event_name == 'workflow_dispatch' || (github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.head.ref == 'next') }}"
env:
RELEASE_NOTES_FILE: ${{ runner.temp }}/release-notes.md
RELEASE_PLAN_OUTPUT: ${{ runner.temp }}/release-plan.env
RELEASE_PLAN_BODY: ${{ runner.temp }}/release-plan.md
run: |
zsh -f scripts/release-plan.zsh HEAD > "$RELEASE_PLAN_BODY"
cat "$RELEASE_PLAN_BODY" >> "$GITHUB_STEP_SUMMARY"
cat "$RELEASE_PLAN_OUTPUT" >> "$GITHUB_OUTPUT"

- name: Record non-promotion result
if: "${{ github.event_name == 'pull_request' && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.head.ref != 'next') }}"
run: echo 'This pull request is not an internal next-to-main promotion; automatic publication does not apply.' >> "$GITHUB_STEP_SUMMARY"

- name: Update promotion pull request
if: "${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.head.ref == 'next' }}"
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
RELEASE_PLAN_BODY: ${{ runner.temp }}/release-plan.md
run: |
set -euo pipefail
marker='<!-- zi-release-plan -->'
body="${RUNNER_TEMP}/release-plan-comment.md"
{
echo "$marker"
cat "$RELEASE_PLAN_BODY"
echo
echo '_Merging this reviewed promotion authorizes publication after every required workflow succeeds on the exact merge SHA._'
} > "$body"
comment_id="$(gh api --paginate \
"repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" \
--jq ".[] | select(.user.login == \"github-actions[bot]\" and (.body | contains(\"${marker}\"))) | .id" | head -n 1)"
if [[ -n "$comment_id" ]]; then
gh api --method PATCH "repos/${GITHUB_REPOSITORY}/issues/comments/${comment_id}" \
-F body=@"$body" >/dev/null
else
gh api --method POST "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" \
-F body=@"$body" >/dev/null
fi
21 changes: 0 additions & 21 deletions .github/workflows/release-prepare.yml

This file was deleted.

70 changes: 63 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ name: Release
on:
push:
tags: ["v*.*.*"]
workflow_run:
workflows: [Zsh, ZD Integration, CodeQL, Trunk Code Quality]
types: [completed]

permissions:
actions: read
contents: write
permissions: {}

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: release-${{ github.event.workflow_run.head_sha || github.ref_name }}
cancel-in-progress: false

jobs:
publish:
name: Verify and publish
if: github.repository == 'z-shell/zi'
manual:
name: Verify and publish recovery tag
if: github.event_name == 'push' && github.repository == 'z-shell/zi'
runs-on: ubuntu-latest
permissions:
actions: read
contents: write
steps:
- name: Check out the tagged commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down Expand Up @@ -49,3 +53,55 @@ jobs:
--title "Zi $TAG" \
--generate-notes \
--latest

automatic:
name: Publish reviewed promotion
if: "${{ github.event_name == 'workflow_run' && github.repository == 'z-shell/zi' && github.event.workflow_run.head_branch == 'main' }}"
runs-on: ubuntu-latest
permissions:
actions: read
contents: write
pull-requests: read
steps:
- name: Check out the trusted main branch
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: refs/heads/main
fetch-depth: 0
fetch-tags: true

- name: Install Zsh
run: sudo apt-get update && sudo apt-get install -yq zsh

- name: Verify promotion and exact-SHA validation
id: verify
env:
GH_TOKEN: ${{ github.token }}
PROMOTION_SHA: ${{ github.event.workflow_run.head_sha }}
run: zsh -f scripts/verify-promotion-release.zsh

- name: Compute the authorized release plan
id: plan
if: steps.verify.outputs.ready == 'true'
env:
RELEASE_NOTES_FILE: ${{ runner.temp }}/release-notes.md
RELEASE_TARGET: ${{ github.event.workflow_run.head_sha }}
run: |
RELEASE_PLAN_OUTPUT="$GITHUB_OUTPUT" \
zsh -f scripts/release-plan.zsh \
"$RELEASE_TARGET" >> "$GITHUB_STEP_SUMMARY"

- name: Record no-op promotion
if: steps.verify.outputs.ready == 'true' && steps.plan.outputs.release != 'true'
run: echo 'The reviewed promotion contains no releasable Conventional Commits; no tag or release was created.' >> "$GITHUB_STEP_SUMMARY"

- name: Create annotated tag and release
if: steps.verify.outputs.ready == 'true' && steps.plan.outputs.release == 'true'
env:
GH_TOKEN: ${{ github.token }}
RELEASE_NOTES_FILE: ${{ runner.temp }}/release-notes.md
RELEASE_TAG: ${{ steps.plan.outputs.tag }}
RELEASE_TARGET: ${{ github.event.workflow_run.head_sha }}
run: |
zsh -f scripts/publish-promotion-release.zsh >> "$GITHUB_STEP_SUMMARY"
echo "Authorized by reviewed promotion #${{ steps.verify.outputs.promotion_pr }}." >> "$GITHUB_STEP_SUMMARY"
6 changes: 1 addition & 5 deletions .github/workflows/zd-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ name: ZD Integration
on:
push:
branches: [main, next]
paths:
- ".github/workflows/zd-integration.yml"
- "zi.zsh"
- "lib/**"
pull_request:
paths:
- ".github/workflows/zd-integration.yml"
Expand All @@ -24,7 +20,7 @@ permissions:

jobs:
zd-test:
uses: z-shell/zd/.github/workflows/test-native.yml@01c3477e48c0c31bb7225986bb1bac4270e151ff # z-shell/zd#121
uses: z-shell/zd/.github/workflows/test-native.yml@5d160597c909a23f03b7a07ff9d43793a106f3e8 # z-shell/zd#123
with:
zi_repo: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
zi_ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
Expand Down
Loading
Loading