diff --git a/.github/scripts/rebase-plan.js b/.github/scripts/rebase-plan.js index 600caa8..c64ecf7 100644 --- a/.github/scripts/rebase-plan.js +++ b/.github/scripts/rebase-plan.js @@ -166,7 +166,7 @@ const summarize = ({ train, jobs, skipped, unknown }) => { // thing the run cannot do itself. const STATUS_LABEL = { rebased: 'Rebased', 'up-to-date': 'Already up to date', skipped: 'Skipped' }; -const summarizeResults = ({ train, results, dryRun }) => { +const summarizeResults = ({ train, results, dryRun, unknown = [] }) => { const by = status => results.filter(r => r.status === status); const manual = results.filter(r => ['conflict', 'blocked', 'error'].includes(r.status)); const row = r => `| ${r.project} | \`${r.branch}\` | ${r.base ? `\`${r.base}\`` : ''} | ${r.detail || ''} |`; @@ -187,6 +187,9 @@ const summarizeResults = ({ train, results, dryRun }) => { } else { lines.push(':white_check_mark: Every branch was rebased cleanly or was already up to date.', ''); } + if (unknown.length) { + lines.push(`:warning: Not in the train, ignored: ${unknown.map(p => `\`${p}\``).join(', ')}`, ''); + } for (const status of ['rebased', 'up-to-date', 'skipped']) { const rows = by(status); if (!rows.length) continue; @@ -202,6 +205,11 @@ module.exports = { isHotfix, lineOf, parseTrainYml, isCloudProject, buildPlan, s // `projects` is a comma separated list, blank for every spring-cloud project in the train. // Writes `matrix` (a {include:[...]} object) and `has_work` to $GITHUB_OUTPUT and a report to // $GITHUB_STEP_SUMMARY, when those are set. +// +// The plan only goes to the step summary when there is nothing to rebase. Otherwise the +// results job writes the one summary, so it is the first thing on the run page rather than +// the second; the plan stays in this job's log, and any ignored project names are passed on +// as the `unknown` output for the results job to report. if (require.main === module) { const [train, projectsArg = ''] = process.argv.slice(2); if (!train) { @@ -219,10 +227,13 @@ if (require.main === module) { const report = summarize({ train, ...plan }); process.stdout.write(report + '\n'); - if (process.env.GITHUB_STEP_SUMMARY) fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, report + '\n'); + if (process.env.GITHUB_STEP_SUMMARY && !plan.jobs.length) { + fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, report + '\n'); + } if (process.env.GITHUB_OUTPUT) { fs.appendFileSync(process.env.GITHUB_OUTPUT, - `matrix=${JSON.stringify({ include: plan.jobs })}\nhas_work=${plan.jobs.length > 0}\n`); + `matrix=${JSON.stringify({ include: plan.jobs })}\nhas_work=${plan.jobs.length > 0}\n` + + `unknown=${plan.unknown.join(',')}\n`); } } catch (err) { process.stderr.write(`${err.message}\n`); diff --git a/.github/scripts/rebase-summary.js b/.github/scripts/rebase-summary.js index 14255f1..31d6aa6 100644 --- a/.github/scripts/rebase-summary.js +++ b/.github/scripts/rebase-summary.js @@ -3,7 +3,7 @@ // Writes the final report of rebase-release-branches.yml from the result-*.jsonl files the // rebase jobs uploaded. // -// node rebase-summary.js +// node rebase-summary.js [ignored,projects] // // Exits 1 only when a job reported an error (a push that was rejected, a clone that failed). // Conflicts do not fail the run: they are the expected "do this by hand" outcome and are @@ -13,7 +13,7 @@ const fs = require('fs'); const path = require('path'); const { summarizeResults } = require('./rebase-plan'); -const [train, dryRun, dir] = process.argv.slice(2); +const [train, dryRun, dir, ignored = ''] = process.argv.slice(2); if (!train || !dir) { process.stderr.write('usage: rebase-summary.js \n'); process.exit(2); @@ -31,7 +31,8 @@ const walk = d => { }; if (fs.existsSync(dir)) walk(dir); -const report = summarizeResults({ train, results, dryRun: dryRun === 'true' }); +const report = summarizeResults({ train, results, dryRun: dryRun === 'true', + unknown: ignored.split(',').filter(Boolean) }); process.stdout.write(report + '\n'); if (process.env.GITHUB_STEP_SUMMARY) fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, report + '\n'); diff --git a/.github/workflows/rebase-release-branches.yml b/.github/workflows/rebase-release-branches.yml index ff423c0..8bd3e5d 100644 --- a/.github/workflows/rebase-release-branches.yml +++ b/.github/workflows/rebase-release-branches.yml @@ -61,6 +61,7 @@ jobs: outputs: matrix: ${{ steps.plan.outputs.matrix }} has_work: ${{ steps.plan.outputs.has_work }} + unknown: ${{ steps.plan.outputs.unknown }} steps: - name: Checkout uses: actions/checkout@v4 @@ -130,7 +131,11 @@ jobs: path: ${{ runner.temp }}/result.jsonl if-no-files-found: ignore + # The only job that writes a step summary when there is work (the plan only does when there + # is none), so its report is the first thing on the run page. The name is what GitHub puts in + # the heading, as " summary". summary: + name: Rebase results needs: [plan, rebase] if: ${{ always() && needs.plan.outputs.has_work == 'true' }} runs-on: ubuntu-latest @@ -148,4 +153,5 @@ jobs: env: TRAIN: ${{ inputs.spring_release_train }} DRY_RUN: ${{ inputs.dry_run }} - run: node .github/scripts/rebase-summary.js "$TRAIN" "$DRY_RUN" results + IGNORED: ${{ needs.plan.outputs.unknown }} + run: node .github/scripts/rebase-summary.js "$TRAIN" "$DRY_RUN" results "$IGNORED"