diff --git a/action.yml b/action.yml index bf02ac1..02a77e6 100644 --- a/action.yml +++ b/action.yml @@ -73,6 +73,39 @@ inputs: description: Token broker URL. Empty uses the default in action/oidc.sh. required: false default: "" + features: + description: >- + Cargo features passed as `--features` to the gate, the baseline + measurement, and spec generation. A bench target with + `required-features` needs them here. + required: false + default: "" + changelog-features: + description: >- + Features for `report changelog`, which decide what the API surface + contains. Empty uses `features`. + required: false + default: "" + changelog-packages: + description: >- + Space-separated packages whose API surface `report changelog` diffs. + Empty uses `packages`; set it when crates without a bench target + still ship an API. + required: false + default: "" + regen-run: + description: >- + Shell run on the default branch after the built-in regeneration, for + derived files the inputs above do not cover (an `sdk gen`, a rendered + report). `$SOOTHFAST` names the cargo-soothfast this step installed. + Whatever it changes under `regen-paths` lands in the same pull + request; `regen-paths` is required with it. + required: false + default: "" + regen-paths: + description: Space-separated pathspecs `regen-run` may change. + required: false + default: "" outputs: version: @@ -144,7 +177,7 @@ runs: shell: bash env: GATE: ${{ inputs.gate }} - REGEN: ${{ inputs.changelog == 'true' || inputs.spec != '' }} + REGEN: ${{ inputs.changelog == 'true' || inputs.spec != '' || inputs.regen-run != '' }} PACKAGES: ${{ inputs.packages }} RUSTDOC_TOOLCHAIN: ${{ inputs.rustdoc-toolchain }} GH_TOKEN: ${{ inputs.token }} @@ -161,6 +194,7 @@ runs: GH_TOKEN: ${{ inputs.token }} PR_NUMBER: ${{ github.event.pull_request.number }} BROKER: ${{ inputs.broker }} + FEATURES: ${{ inputs.features }} run: "$GITHUB_ACTION_PATH/action/gate.sh" - name: Upload triage artifacts if: steps.gate.outputs.failed == 'true' @@ -186,6 +220,11 @@ runs: BASELINE: ${{ inputs.baseline }} CHANGELOG: ${{ inputs.changelog }} SPEC: ${{ inputs.spec }} + FEATURES: ${{ inputs.features }} + CHANGELOG_FEATURES: ${{ inputs.changelog-features }} + CHANGELOG_PACKAGES: ${{ inputs.changelog-packages }} + REGEN_RUN: ${{ inputs.regen-run }} + REGEN_PATHS: ${{ inputs.regen-paths }} run: "$GITHUB_ACTION_PATH/action/regen.sh" # Minted after everything that compiles the tree has run. - name: Mint a soothfast-bot token diff --git a/action/gate.sh b/action/gate.sh index 482661a..4a2cb94 100755 --- a/action/gate.sh +++ b/action/gate.sh @@ -5,11 +5,14 @@ # upload still happen first. Output is untrusted (the PR's own binaries wrote # it) and the comment is authored by a write-access identity, so nothing in # it may escape the code fence. -# Inputs: CLI PACKAGES BASE_REF GH_TOKEN PR_NUMBER, BROKER (optional). +# Inputs: CLI PACKAGES BASE_REF GH_TOKEN PR_NUMBER, BROKER and FEATURES +# (optional). # Output: failed (true|false). set -euo pipefail read -ra pkgs <<<"$PACKAGES" +features=() +[ -n "${FEATURES:-}" ] && features=(--features "$FEATURES") failed=false out_dir="${RUNNER_TEMP:-/tmp}/soothfast-gate" mkdir -p "$out_dir" @@ -17,7 +20,7 @@ mkdir -p "$out_dir" echo '## soothfast gate' for pkg in "${pkgs[@]}"; do out="${out_dir}/${pkg}.txt" - "$CLI" gate -p "$pkg" --against-ref "origin/${BASE_REF}" 2>&1 | tee "$out" >&2 || failed=true + "$CLI" gate -p "$pkg" --against-ref "origin/${BASE_REF}" "${features[@]}" 2>&1 | tee "$out" >&2 || failed=true echo "### ${pkg}" echo '```' # shellcheck disable=SC2016 # literal backticks, nothing to expand diff --git a/action/regen.sh b/action/regen.sh index 2dcc308..9aeecfb 100755 --- a/action/regen.sh +++ b/action/regen.sh @@ -1,35 +1,52 @@ #!/usr/bin/env bash # Regenerate derived files on the default branch: a fresh baseline for every -# package, then CHANGELOG.md against the latest tag and any generate-mode -# specs. -# Inputs: CLI PACKAGES BASELINE CHANGELOG (true|false) SPEC (package list). +# package, then CHANGELOG.md against the latest tag, any generate-mode specs, +# and whatever REGEN_RUN produces under REGEN_PATHS. +# Inputs: CLI PACKAGES BASELINE CHANGELOG (true|false) SPEC (package list), +# FEATURES, CHANGELOG_FEATURES, CHANGELOG_PACKAGES, REGEN_RUN, REGEN_PATHS +# (all optional). # Outputs: paths (pathspecs for land.sh), changed (true when any of them # differs from HEAD, so a no-op run never mints a token). set -euo pipefail read -ra pkgs <<<"$PACKAGES" paths=() +features=() +[ -n "${FEATURES:-}" ] && features=(--features "$FEATURES") +changelog_features=("${features[@]}") +[ -n "${CHANGELOG_FEATURES:-}" ] && changelog_features=(--features "$CHANGELOG_FEATURES") if [ "$CHANGELOG" = true ]; then for pkg in "${pkgs[@]}"; do - "$CLI" measure -p "$pkg" --save-baseline "$BASELINE" + "$CLI" measure -p "$pkg" --save-baseline "$BASELINE" "${features[@]}" done + read -ra changelog_pkgs <<<"${CHANGELOG_PACKAGES:-$PACKAGES}" args=() - for pkg in "${pkgs[@]}"; do args+=(-p "$pkg"); done + for pkg in "${changelog_pkgs[@]}"; do args+=(-p "$pkg"); done prev=$(git describe --tags --abbrev=0 2>/dev/null || true) if [ -n "$prev" ]; then args+=(--against-ref "$prev"); fi - "$CLI" report changelog "${args[@]}" --baseline "$BASELINE" + "$CLI" report changelog "${args[@]}" --baseline "$BASELINE" "${changelog_features[@]}" paths+=(CHANGELOG.md) fi if [ -n "$SPEC" ]; then read -ra specs <<<"$SPEC" for pkg in "${specs[@]}"; do - "$CLI" spec gen -p "$pkg" + "$CLI" spec gen -p "$pkg" "${features[@]}" done paths+=('*.yaml' '*.yml' '*.json') fi +if [ -n "${REGEN_RUN:-}" ]; then + if [ -z "${REGEN_PATHS:-}" ]; then + echo "::error::regen-run needs regen-paths, or nothing it changes can land" + exit 1 + fi + SOOTHFAST="$CLI" bash -euo pipefail -c "$REGEN_RUN" + read -ra extra <<<"$REGEN_PATHS" + paths+=("${extra[@]}") +fi + changed=false if [ "${#paths[@]}" -gt 0 ] && [ -n "$(git status --porcelain -- "${paths[@]}")" ]; then changed=true diff --git a/docs/ci.md b/docs/ci.md index caaae74..b249c43 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -114,10 +114,15 @@ installed on is refused. | Input | Default | Meaning | |---|---|---| -| `packages` | every package with a bench target named `soothfast` | Space-separated packages to gate and measure. The same list feeds `report changelog`; pass it explicitly when the crates whose API ships differ from the ones with benches. | +| `packages` | every package with a bench target named `soothfast` | Space-separated packages to gate and measure. `report changelog` uses the same list unless `changelog-packages` says otherwise. | | `gate` | `true` | Run the gate on pull requests. | | `changelog` | `true` | Regenerate `CHANGELOG.md` on default-branch pushes. | | `spec` | none | Space-separated packages whose `mode = "generate"` specs to regenerate. | +| `features` | none | Cargo features for the gate, the baseline measurement, and spec generation. A bench target with `required-features` needs them here. | +| `changelog-packages` | `packages` | Packages whose API surface `report changelog` diffs. Set it when a crate without a bench target still ships an API. | +| `changelog-features` | `features` | Features for `report changelog`, which decide what the API surface diff contains. Set it wider than `features` when gating under the full feature set is too heavy. | +| `regen-run` | none | Shell run on the default branch after the built-in regeneration, for derived files the inputs above do not cover. `$SOOTHFAST` is the `cargo-soothfast` this step installed, so `"$SOOTHFAST" sdk gen -p mylib` works whether the CLI came from the install or from `binary`. Requires `regen-paths`. | +| `regen-paths` | none | Space-separated pathspecs `regen-run` may change; they land in the same pull request. Required with `regen-run`; without it the step fails rather than discarding the changes. | | `baseline` | `base` | Baseline name the regeneration measures into. | | `rustdoc-toolchain` | the nightly the release was tested with | Toolchain for rustdoc JSON. A floating `nightly` can change the JSON format under the API diff. | | `version` | from `Cargo.lock` | `cargo-soothfast` version to install. |