Skip to content

Commit b25ddad

Browse files
feat: add change_matrix output for CI matrix fan-out support
1 parent 5ae13fa commit b25ddad

File tree

5 files changed

+57
-4
lines changed

5 files changed

+57
-4
lines changed

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ Dockerfile
8585
| ---------------- | -------------------------------------------------------------------------------------------------------------------------- |
8686
| `new_version` | Highest CPython patch identified during the run. |
8787
| `files_changed` | JSON array of files rewritten. |
88+
| `change_matrix` | JSON object suitable for `strategy.matrix` fan-out (entries contain `file` and `new_version`). |
8889
| `skipped_reason` | Machine-readable reason when no PR is created (`already_latest`, `multiple_tracks_detected`, `pre_release_guarded`, etc.). |
8990
9091
---
@@ -147,6 +148,32 @@ with:
147148

148149
When the keywords are provided, the action fetches the GitHub release notes for the resolved tag (or uses the optional `RELEASE_NOTES_SNAPSHOT` offline input) and skips the run unless at least one keyword is present.
149150

151+
### Matrix fan-out for CI
152+
153+
Use the `change_matrix` output to drive follow-up jobs that need to iterate over the files touched by the upgrade:
154+
155+
```yaml
156+
jobs:
157+
bump-python:
158+
runs-on: ubuntu-latest
159+
steps:
160+
- uses: actions/checkout@v4
161+
- id: bump
162+
uses: casperkristiansson/python-version-patch-pr@v0
163+
164+
targeted-tests:
165+
needs: bump-python
166+
if: ${{ needs.bump-python.outputs.skipped_reason == '' }}
167+
strategy:
168+
matrix: ${{ fromJSON(needs.bump-python.outputs.change_matrix) }}
169+
runs-on: ubuntu-latest
170+
steps:
171+
- uses: actions/checkout@v4
172+
- run: npm test -- ${{ matrix.file }}
173+
```
174+
175+
Each matrix entry exposes `matrix.file` and `matrix.new_version`, enabling you to scope lint or test jobs to the files rewritten during the patch.
176+
150177
### Renovate/Dependabot coexistence
151178

152179
If Renovate or Dependabot also try to bump CPython patch versions, they will race with this action

action.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ outputs:
3737
description: Resolved CPython patch version (for example 3.13.5).
3838
files_changed:
3939
description: JSON array listing files that were updated.
40+
change_matrix:
41+
description: JSON object suitable for GitHub Actions matrix with changed files and new version.
4042
skipped_reason:
4143
description: Machine-readable reason describing why no update was applied.
4244
runs:

docs/tasks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ Use Context7 MCP for up to date documentation.
255255
Input `security_keywords` to gate bumps by release notes.
256256
Verify: Mock notes trigger gate.
257257

258-
43. [ ] **Matrix output for CI**
258+
43. [x] **Matrix output for CI**
259259
Output JSON of changed files and new version.
260260
Verify: Example consumes output.
261261

src/index.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@ export async function run(): Promise<void> {
250250
const rawReleaseNotesSnapshot = loadJsonSnapshot('RELEASE_NOTES_SNAPSHOT');
251251
if (rawReleaseNotesSnapshot !== undefined) {
252252
if (typeof rawReleaseNotesSnapshot !== 'object' || rawReleaseNotesSnapshot === null) {
253-
throw new Error('RELEASE_NOTES_SNAPSHOT must be a JSON object mapping versions or tags to release note strings.');
253+
throw new Error(
254+
'RELEASE_NOTES_SNAPSHOT must be a JSON object mapping versions or tags to release note strings.',
255+
);
254256
}
255257

256258
const entries = Object.entries(rawReleaseNotesSnapshot as Record<string, unknown>);
@@ -319,15 +321,27 @@ export async function run(): Promise<void> {
319321

320322
summarizeResult(result);
321323

324+
const matrixOutput =
325+
result.status === 'success'
326+
? {
327+
include: result.filesChanged.map((file) => ({
328+
file,
329+
new_version: result.newVersion,
330+
})),
331+
}
332+
: { include: [] as Array<Record<string, string>> };
333+
322334
if (result.status === 'success') {
323335
core.setOutput('new_version', result.newVersion);
324336
core.setOutput('files_changed', JSON.stringify(result.filesChanged));
337+
core.setOutput('change_matrix', JSON.stringify(matrixOutput));
325338
core.setOutput('skipped_reason', '');
326339
return;
327340
}
328341

329342
core.setOutput('new_version', result.newVersion ?? '');
330343
core.setOutput('files_changed', JSON.stringify(result.filesChanged ?? []));
344+
core.setOutput('change_matrix', JSON.stringify(matrixOutput));
331345
core.setOutput('skipped_reason', result.reason);
332346
} catch (error) {
333347
if (error instanceof Error) {

tests/index.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,12 @@ describe('run', () => {
101101
'files_changed',
102102
JSON.stringify(['Dockerfile']),
103103
);
104-
expect(mockSetOutput).toHaveBeenNthCalledWith(3, 'skipped_reason', '');
104+
expect(mockSetOutput).toHaveBeenNthCalledWith(
105+
3,
106+
'change_matrix',
107+
JSON.stringify({ include: [{ file: 'Dockerfile', new_version: '3.13.1' }] }),
108+
);
109+
expect(mockSetOutput).toHaveBeenNthCalledWith(4, 'skipped_reason', '');
105110
expect(mockWarning).not.toHaveBeenCalled();
106111
});
107112

@@ -161,7 +166,12 @@ describe('run', () => {
161166

162167
expect(mockSetOutput).toHaveBeenNthCalledWith(1, 'new_version', '');
163168
expect(mockSetOutput).toHaveBeenNthCalledWith(2, 'files_changed', '[]');
164-
expect(mockSetOutput).toHaveBeenNthCalledWith(3, 'skipped_reason', 'no_matches_found');
169+
expect(mockSetOutput).toHaveBeenNthCalledWith(
170+
3,
171+
'change_matrix',
172+
JSON.stringify({ include: [] }),
173+
);
174+
expect(mockSetOutput).toHaveBeenNthCalledWith(4, 'skipped_reason', 'no_matches_found');
165175
});
166176

167177
it('reports failures when unexpected errors occur', async () => {

0 commit comments

Comments
 (0)