ci(docker): resolve the release phase and classify changes in one job

`mode` and `detect` ran back to back on the same runner for ~3s and ~9s.
The classification steps now follow the phase in `mode`, gated on it
being a standalone run, so a release phase still skips classification;
`build` reads `needs.mode.outputs.build`.
This commit is contained in:
Maciej Lisiewski committed 2026-11-06 02:16:09 +01:00
1 parent 55d08c7c6b
commit e25d00652a
1 file changed
+22 -21
+22 -21
View File
@@ -67,15 +67,28 @@ env:
CANDIDATE_COMMIT: ${{ inputs.commit || github.sha }}
jobs:
# Resolve the release phase. Release modes run only via workflow_call from
# the parent stable-release workflow, which passes the candidate commit.
# Resolve the release phase, then (outside release phases) classify the PR's
# changed files. Release modes run only via workflow_call from the parent
# stable-release workflow, which passes the candidate commit.
#
# Classification used to be a separate `detect` job that started right after
# this one on the same runner: a second billed minute for ~10s of work. Its
# steps are gated on the resolved phase instead, so a release phase still
# skips classification entirely (the parent already ran full CI and the tag
# dispatch has no meaningful PR diff to classify).
#
# ci.yml used to gate the docker call on its own ``detect`` outputs; now that
# this workflow triggers itself, it runs the same composite action. On push
# the classifier fails open (every lane true), so post-merge validation is
# never weakened.
mode:
name: Resolve release phase
name: Resolve release phase and affected areas
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 5
timeout-minutes: 10
outputs:
phase: ${{ steps.resolve.outputs.phase }}
release: ${{ steps.resolve.outputs.release }}
build: ${{ steps.gate.outputs.build }}
steps:
- id: resolve
env:
@@ -90,33 +103,21 @@ jobs:
*) echo "::error::Invalid release-phase input: $PHASE"; exit 1 ;;
esac
# Classify the PR's changed files. ci.yml used to gate the docker call on
# its own ``detect`` outputs; now that this workflow triggers itself, it
# runs the same composite action. On push and release the classifier fails
# open (every lane true), so post-merge validation is never weakened.
# Release phases skip classification entirely: the parent already ran full
# CI and the tag dispatch has no meaningful PR diff to classify.
detect:
name: Detect affected areas
needs: [mode]
if: needs.mode.outputs.release != 'true'
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 10
outputs:
build: ${{ steps.gate.outputs.build }}
steps:
- uses: useblacksmith/checkout@25227e61ff9dafe400e22fa487b673eac4e4409a # v1
if: steps.resolve.outputs.release != 'true'
with:
ref: ${{ inputs.commit }}
- name: Detect affected areas
id: classify
if: steps.resolve.outputs.release != 'true'
uses: ./.github/actions/detect-changes
with:
github-token: ${{ github.token }}
- name: Decide whether to build
id: gate
if: steps.resolve.outputs.release != 'true'
env:
# The docker lane is a slow lane: on a pull request it runs only
# for docker meta, the dependency manifests, PM and tests/docker
@@ -142,10 +143,10 @@ jobs:
# rebuilds — it downloads these exact artifacts.
build:
name: Build and test image (${{ matrix.variant }}/${{ matrix.arch }})
needs: [mode, detect]
needs: [mode]
if: >-
!cancelled() && needs.mode.result == 'success' &&
((needs.mode.outputs.release != 'true' && github.repository == 'NousResearch/hermes-agent' && needs.detect.outputs.build == 'true') || needs.mode.outputs.phase == 'test')
((needs.mode.outputs.release != 'true' && github.repository == 'NousResearch/hermes-agent' && needs.mode.outputs.build == 'true') || needs.mode.outputs.phase == 'test')
strategy:
fail-fast: false
matrix: