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
1 change: 1 addition & 0 deletions .github/settings/actions-selected.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"github/codeql-action@*",
"actions-rust-lang/setup-rust-toolchain@*",
"astral-sh/setup-uv@*",
"rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18",
"codecov/codecov-action@*",
"zizmorcore/zizmor-action@*",
"taiki-e/cache-cargo-install-action@*",
Expand Down
15 changes: 15 additions & 0 deletions .github/settings/crates-io-environment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"wait_timer": 0,
"prevent_self_review": false,
"reviewers": [
{
"type": "User",
"id": 434849
}
],
"can_admins_bypass": false,
"deployment_branch_policy": {
"protected_branches": false,
"custom_branch_policies": true
}
}
4 changes: 4 additions & 0 deletions .github/settings/crates-io-tags.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "v*",
"type": "tag"
}
97 changes: 97 additions & 0 deletions .github/workflows/publish-crates.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: Publish to crates.io

on:
release:
types: [published]

permissions:
contents: read

# Serialize all uploads for this crate, including reruns. Never cancel an upload.
concurrency:
group: publish-crates-la-stack
cancel-in-progress: false

env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1

jobs:
verify:
if: >-
github.repository == 'acgetchell/la-stack' &&
github.event_name == 'release' && github.event.action == 'published' &&
!github.event.release.draft && !github.event.release.prerelease
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
contents: read
checks: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
fetch-depth: 0
persist-credentials: false

- name: Set up declared tools without caches
uses: ./.github/actions/setup-tools # zizmor: ignore[self-repository] actionlint 1.7.12 does not accept $/...
with:
cache: "false"

- name: Require reviewed release evidence
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: just release-gate "$RELEASE_TAG"

- name: Verify Cargo packaging without uploading
run: just release-package

publish:
needs: verify
runs-on: ubuntu-latest
timeout-minutes: 45
environment: crates-io
permissions:
contents: read
checks: read
id-token: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
fetch-depth: 0
persist-credentials: false

- name: Set up declared tools without caches
uses: ./.github/actions/setup-tools # zizmor: ignore[self-repository] actionlint 1.7.12 does not accept $/...
with:
cache: "false"

- name: Recheck evidence and registry absence after deployment approval
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
set -euo pipefail
just release-gate "$RELEASE_TAG"
uv run --locked --no-sync research-repo-tools release registry "$RELEASE_TAG" --expect absent

- name: Obtain a short-lived crates.io token
id: auth
uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5

# The verify job built default/exact packages without upload credentials.
# Repackage the same clean, revalidated commit without running build scripts.
- name: Package and upload verified source without building
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
run: uv run --locked --no-sync research-repo-tools toolchain run -- cargo publish --locked --package la-stack --registry crates-io --no-verify

- name: Check visibility even after a Cargo upload timeout
if: ${{ !cancelled() && steps.auth.outcome == 'success' }}
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: just release-verify "$RELEASE_TAG"
9 changes: 5 additions & 4 deletions .github/workflows/release-benchmarks.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Release Benchmarks

# Attach full Criterion baselines to a draft before publishing the release.
# Attach full Criterion baselines for maintainer review before publication.
# Release jobs publish durable artifacts, so they intentionally do not restore
# or save dependency caches.

Expand Down Expand Up @@ -182,7 +182,7 @@ jobs:
with:
name: ${{ needs.release-baseline.outputs.artifact-name }}

- name: Attach baseline and publish draft
- name: Attach baseline for review
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
Expand All @@ -196,7 +196,7 @@ jobs:
printf '%s\n' "$RELEASE_TARGET" > "$RUNNER_TEMP/release-target.json"
uvx --python 3.15 --from research-repo-tools==0.1.9 research-repo-tools \
--root "$RUNNER_TEMP" performance release-upload "$GH_REPO" "$RELEASE_TAG" \
"$GITHUB_WORKSPACE/$RELEASE_ASSET" --target "$RUNNER_TEMP/release-target.json" --publish
"$GITHUB_WORKSPACE/$RELEASE_ASSET" --target "$RUNNER_TEMP/release-target.json"

- name: Release baseline summary
env:
Expand All @@ -207,5 +207,6 @@ jobs:
{
echo "### Release Benchmark Baseline"
echo ""
echo "Published release with verified asset: \`$RELEASE_ASSET\`"
echo "Draft release with verified asset: \`$RELEASE_ASSET\`"
echo "Review the draft, then run \`just release-publish <tag>\` as the maintainer."
} >> "$GITHUB_STEP_SUMMARY"
15 changes: 8 additions & 7 deletions docs/BENCHMARKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -788,8 +788,9 @@ comparison is `docs/performance.md`, created by `just performance-release`.

Follow [Releasing](RELEASING.md#5-create-the-draft-github-release): create the
tagged stable release as a draft, dispatch the workflow with
`--ref "$TAG" -f tag="$TAG"`, and let the workflow upload and verify the archive before it
publishes the draft. Dispatch requires a stable `vX.Y.Z` tag and exactly one
`--ref "$TAG" -f tag="$TAG"`, and let the workflow upload and verify the archive.
Review the draft, then run `just release-publish "$TAG"` as the maintainer to
start the separate crates.io workflow. Dispatch requires a stable `vX.Y.Z` tag and exactly one
mutable draft with that tag as its title. The producer checks out the resolved
tag commit only when it matches the workflow's own commit. The dispatch ref
must be that same tag, which keeps execution in the tag's cache scope; the
Expand Down Expand Up @@ -846,7 +847,7 @@ measurements all stop publication. Only successful validation permits packaging
the single `criterion/` archive, including the inventory manifest, and uploading
the temporary Actions artifact. The separate publisher attaches that archive
as `la-stack-$TAG-criterion-baseline.tar.gz` to the draft, verifies its uploaded
state, size, and SHA-256 digest, and only then publishes the release.
state, size, and SHA-256 digest, and leaves the draft ready for review.

### Validate The Release Workflow

Expand All @@ -861,12 +862,12 @@ just doc-check

The Python suite executes the workflow's shell with the pinned installed CLI
and a simulated GitHub provider to prove captured-target handoff, commit-change
rejection and explicit publication. Generic provider failure matrices belong
rejection and preservation of the draft for review. Generic provider failure matrices belong
upstream. Archive fixtures retain scientific coverage and exact raw bytes.

Every hosted dispatch now requires a real release draft and authorizes its
publication; there is no producer-only manual mode. Use the
[release sequence](RELEASING.md#6-run-benchmarks-and-publish-the-draft) for a
Every hosted dispatch requires a real release draft and attaches verified
evidence for review. Use the
[release sequence](RELEASING.md#6-run-benchmarks-and-review-the-draft) for a
planned release. Record the successful run URL and both elapsed suite times
when validating a budget change. The estimates above still require this
representative hosted run; local tests and archive fixtures do not establish
Expand Down
Loading
Loading