diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e5b9e2..57e4710 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,10 +96,16 @@ jobs: if: always() runs-on: ubuntu-latest steps: - - name: Check passed or skipped - if: ${{ needs.check.result == 'success' || needs.check.result == 'skipped' }} - run: echo "CI check passed or skipped (markdown-only changes)." - - - name: Check failed - if: ${{ needs.check.result == 'failure' }} - run: exit 1 + - name: Report status + run: | + changes="${{ needs.changes.result }}" + check="${{ needs.check.result }}" + if [ "$changes" == "failure" ] || [ "$check" == "failure" ]; then + echo "::error::CI failed (changes=$changes, check=$check)" + exit 1 + fi + if [ "$changes" == "cancelled" ] || [ "$check" == "cancelled" ]; then + echo "::error::CI was cancelled (changes=$changes, check=$check)" + exit 1 + fi + echo "CI check passed or skipped (markdown-only changes)." diff --git a/.github/workflows/self-test.yml b/.github/workflows/self-test.yml index 26c2525..d36cd27 100644 --- a/.github/workflows/self-test.yml +++ b/.github/workflows/self-test.yml @@ -7,6 +7,7 @@ on: permissions: contents: read + pull-requests: read # dorny/paths-filter needs PR base/head on pull_request events concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -144,16 +145,17 @@ jobs: if: always() runs-on: ubuntu-latest steps: - - name: Self-test passed or skipped - if: ${{ - (needs.matrix.result == 'success' || needs.matrix.result == 'skipped') && - (needs.skip-checksum.result == 'success' || needs.skip-checksum.result == 'skipped') - }} - run: echo "Self-test passed or skipped (markdown-only changes)." - - - name: Self-test failed - if: ${{ - needs.matrix.result == 'failure' || - needs.skip-checksum.result == 'failure' - }} - run: exit 1 + - name: Report status + run: | + changes="${{ needs.changes.result }}" + matrix="${{ needs.matrix.result }}" + skip="${{ needs.skip-checksum.result }}" + if [ "$changes" == "failure" ] || [ "$matrix" == "failure" ] || [ "$skip" == "failure" ]; then + echo "::error::Self-test failed (changes=$changes, matrix=$matrix, skip-checksum=$skip)" + exit 1 + fi + if [ "$changes" == "cancelled" ] || [ "$matrix" == "cancelled" ] || [ "$skip" == "cancelled" ]; then + echo "::error::Self-test was cancelled (changes=$changes, matrix=$matrix, skip-checksum=$skip)" + exit 1 + fi + echo "Self-test passed or skipped (markdown-only changes)." diff --git a/src/main.ts b/src/main.ts index 25368ab..abfcde5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -18,6 +18,16 @@ async function run(): Promise { const checkLatest = core.getBooleanInput('check-latest'); const skipChecksum = core.getBooleanInput('skip-checksum'); + // Summary state collected during the run and written at the end (NFR-5). + const summary = { + version: '', + asset: '', + source: 'go-task/task GitHub Releases', + cache: 'miss', + checksum: 'n/a', + path: '', + }; + // Mask the token so it can never leak into logs/summaries (NFR-1). if (token) { core.setSecret(token); @@ -31,6 +41,7 @@ async function run(): Promise { } const asset = resolveAsset(process.platform, process.arch, archOverride || undefined); + summary.asset = asset.assetName; core.debug(`Target asset: ${asset.assetName}`); // 1. Resolve the concrete version (FR-1). For a range with check-latest=false, @@ -47,10 +58,12 @@ async function run(): Promise { }); core.info(`Resolved go-task version: ${version}`); } + summary.version = version; // 2. Tool-cache lookup (FR-7). let toolDir = tc.find(TOOL_NAME, version, asset.arch); const cacheHit = Boolean(toolDir); + summary.cache = cacheHit ? 'hit' : 'miss'; if (cacheHit) { core.info(`Restored task ${version} from tool cache.`); @@ -67,6 +80,7 @@ async function run(): Promise { // 4. Checksum verification (FR-5). if (skipChecksum) { + summary.checksum = 'skipped'; core.warning('Checksum verification skipped (skip-checksum=true).'); } else { const expected = await withRetry(() => fetchChecksum(tag, asset.assetName, token || undefined), { @@ -80,6 +94,7 @@ async function run(): Promise { ); } verifyChecksum(archivePath, expected); + summary.checksum = 'verified (SHA256)'; core.info('Checksum verified (SHA256).'); } @@ -90,6 +105,7 @@ async function run(): Promise { // 6. Ensure executable + expose on PATH (FR-6/FR-8). const binPath = path.join(toolDir, asset.binaryName); + summary.path = binPath; if (process.platform !== 'win32') { try { fs.chmodSync(binPath, 0o755); @@ -104,6 +120,20 @@ async function run(): Promise { core.setOutput('task-path', binPath); core.setOutput('cache-hit', String(cacheHit)); core.info(`task ${version} is ready at ${binPath}`); + + // Emit a job summary after the fixed pipeline completes (NFR-5). + await core.summary + .addHeading('Setup Task') + .addTable([ + [{ data: 'Item', header: true }, { data: 'Value', header: true }], + ['Version', summary.version], + ['Asset', summary.asset], + ['Source', summary.source], + ['Cache', summary.cache], + ['Checksum', summary.checksum], + ['Executable', summary.path], + ]) + .write(); } run().catch((err: unknown) => {