Skip to content
Open
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
93 changes: 76 additions & 17 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,30 @@ name: Release
# Workflow Settings
# ------------------------------------------------------------------------------
#
# Tag-driven release pipeline: validate the tag against the workspace
# version, run the full test suite, verify crates package cleanly
# (publish dry run - crates.io publishing stays manual), publish the
# container image to GHCR, and create the GitHub release.
# Tag-driven release pipeline in two phases:
#
# Phase 1 (version tag push): validate the tag against the workspace
# version, run the full test suite, verify crates package cleanly
# (publish dry run), then cut a DRAFT pre-release. Nothing is pushed to
# any registry yet.
#
# Phase 2 (a maintainer publishes the draft): publishing the draft --
# whether left as a pre-release or promoted to a full release -- fires
# the `release: published` event, which builds and pushes the container
# image to GHCR and publishes the crates to crates.io. crates.io
# publishing is a real publish when the RUST_CRATES_PUBLISH_TOKEN secret
# is configured, and a dry run otherwise.
#

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Critical] Unexpected change: this entire release workflow redesign (2-phase process, draft releases, crates.io publishing) is unrelated to the Alpine version bump. This should not be in a Dependabot PR. The PR should only change alpine:3.23 to alpine:3.24 in the Containerfile.

# In other words, cutting the final release stays in human hands: the tag
# push only prepares a reviewable draft, and no artifacts are emitted until
# a maintainer publishes it.

on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
release:
types: [published]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand All @@ -25,10 +40,11 @@ env:

jobs:
# ----------------------------------------------------------------------------
# Validate the tag matches Cargo.toml
# Phase 1 (tag push): validate the tag matches Cargo.toml
# ----------------------------------------------------------------------------

validate:
if: github.event_name == 'push'
runs-on: ubuntu-24.04
timeout-minutes: 45
permissions:
Expand All @@ -54,10 +70,11 @@ jobs:
echo "version=$TAG_VERSION" >> "$GITHUB_OUTPUT"

# ----------------------------------------------------------------------------
# Run the full test suite
# Phase 1 (tag push): run the full test suite
# ----------------------------------------------------------------------------

test:
if: github.event_name == 'push'
needs: [validate]
runs-on: ubuntu-24.04
timeout-minutes: 45
Expand All @@ -75,10 +92,11 @@ jobs:
run: make test

# ----------------------------------------------------------------------------
# Verify crates package cleanly (publish dry run)
# Phase 1 (tag push): verify crates package cleanly (publish dry run)
# ----------------------------------------------------------------------------

publish-dry-run:
if: github.event_name == 'push'
needs: [validate]
runs-on: ubuntu-24.04
timeout-minutes: 45
Expand All @@ -98,43 +116,84 @@ jobs:
run: make publish-dry-run

# ----------------------------------------------------------------------------
# Build and publish container image
# Phase 1 (tag push): cut the draft pre-release
#
# A maintainer must review and publish this draft to trigger Phase 2.
# ----------------------------------------------------------------------------

container:
draft-release:
if: github.event_name == 'push'
needs: [validate, test, publish-dry-run]
runs-on: ubuntu-24.04
timeout-minutes: 45
permissions:
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Create draft pre-release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.ref_name }}
run: gh release create "$TAG" --generate-notes --prerelease --draft

# ----------------------------------------------------------------------------
# Phase 2 (draft published): build and publish the container image
# ----------------------------------------------------------------------------

container:
if: github.event_name == 'release'
runs-on: ubuntu-24.04
timeout-minutes: 45
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ github.event.release.tag_name }}

- name: Build and publish container
uses: ./.github/actions/ghcr-publish
with:
image-name: ${{ github.repository }}

# ----------------------------------------------------------------------------
# Create GitHub release
# Phase 2 (draft published): publish crates to crates.io
#
# Real publish when RUST_CRATES_PUBLISH_TOKEN is configured, dry run
# otherwise.
# ----------------------------------------------------------------------------

github-release:
needs: [validate, container]
crates-publish:
if: github.event_name == 'release'
needs: [container]
runs-on: ubuntu-24.04
timeout-minutes: 45
permissions:
contents: write
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ github.event.release.tag_name }}

- name: Set up Rust
uses: ./.github/actions/setup-rust
with:
cache-suffix: publish

- name: Generate release notes
- name: Publish crates
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.ref_name }}
run: gh release create "$TAG" --generate-notes
CARGO_REGISTRY_TOKEN: ${{ secrets.RUST_CRATES_PUBLISH_TOKEN }}
run: |
if [ -n "$CARGO_REGISTRY_TOKEN" ]; then
echo "RUST_CRATES_PUBLISH_TOKEN detected; publishing to crates.io"
make publish
else
echo "RUST_CRATES_PUBLISH_TOKEN not set; performing publish dry run"
make publish-dry-run
fi
2 changes: 1 addition & 1 deletion Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
# Stage 2: Runtime
# ------------------------------------------------------------------------------

FROM alpine:3.23
FROM alpine:3.24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Critical] This is the ONLY expected change for this PR: alpine:3.23alpine:3.24. All other changes in this PR (workflow redesign, Makefile additions) are unrelated and should not be included in a Dependabot bump.


LABEL org.opencontainers.image.source="https://github.com/praxis-proxy/conventions" \
org.opencontainers.image.description="Conventions probe binary" \
Expand Down
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ifneq ($(V),)
endif

.PHONY: all build release check clean \
test mutants lint lint-extra fmt doc audit semver publish-dry-run \
test mutants lint lint-extra fmt doc audit semver publish-dry-run publish \
coverage coverage-check \
check-prereqs check-prereqs-extra check-prereqs-audit check-prereqs-nightly \
require-container-engine \
Expand Down Expand Up @@ -150,6 +150,16 @@ publish-dry-run:
done
cargo package -p $(firstword $(PUBLISH_CRATES))

# Real crates.io publish, in dependency order. Requires a crates.io token

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Critical] Unexpected change: new publish target and documentation are unrelated to the Alpine version bump. This build system change should be in a separate PR with proper review, not bundled with a dependency update.

# in CARGO_REGISTRY_TOKEN (set from the RUST_CRATES_PUBLISH_TOKEN secret in
# CI). `cargo publish` blocks until each crate is available in the index
# before the next one publishes.
publish:
@for crate in $(PUBLISH_CRATES); do \
echo "publishing $$crate"; \
cargo publish -p "$$crate"; \
done

# -------------------------------------------------------------------
# Container
# -------------------------------------------------------------------
Expand Down Expand Up @@ -235,6 +245,7 @@ help:
@echo " audit cargo audit + cargo deny"
@echo " semver cargo semver-checks"
@echo " publish-dry-run package + verify release crates"
@echo " publish publish release crates to crates.io"
@echo " coverage HTML coverage report"
@echo " coverage-check fail if lines < 90%% or regions < 80%%"
@echo ""
Expand Down
Loading