Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experiment with job-context action #3

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
a8b859d
Implement action
omus Aug 12, 2024
fe50061
fixup! Implement action
omus Aug 12, 2024
4f7723f
Experiment with job-name action
omus Aug 13, 2024
d429748
fixup! Experiment with job-name action
omus Aug 13, 2024
db03235
Debug
omus Aug 13, 2024
f60b798
fixup
omus Aug 13, 2024
9bc93ce
Test matrix support
omus Aug 13, 2024
5f2729b
Iterate
omus Aug 13, 2024
95479c0
Determine when matrix values are automatically added
omus Aug 13, 2024
89f7997
Another test
omus Aug 13, 2024
18c9f49
Feature complete
omus Aug 13, 2024
d863637
Fix integration tests
omus Aug 13, 2024
f1a45c9
Iterating
omus Aug 13, 2024
944a4cb
fixup
omus Aug 13, 2024
b9134b6
fixup
omus Aug 13, 2024
cf1d51e
Make proper tests
omus Aug 13, 2024
937536a
fixup
omus Aug 13, 2024
aea824d
fixup
omus Aug 13, 2024
b482108
Iterate
omus Aug 13, 2024
a833347
Debug
omus Aug 13, 2024
f297fca
Proper hypen support
omus Aug 13, 2024
09a77e5
Debug
omus Aug 13, 2024
1d01525
fixup
omus Aug 13, 2024
5e8b351
Test missing github.job
omus Aug 13, 2024
fda45db
Test missing github.job
omus Aug 13, 2024
a03a728
Test
omus Aug 13, 2024
8e5814c
Test
omus Aug 13, 2024
88dddf9
Fail when path doesn't exist
omus Aug 13, 2024
9523837
Order
omus Aug 13, 2024
a89cae0
Try event name
omus Aug 13, 2024
6a6784a
Update tests
omus Aug 13, 2024
f27f876
Update tests
omus Aug 13, 2024
45c6846
fixup
omus Aug 13, 2024
abdd272
Improve tests
omus Aug 13, 2024
d3637ac
fixup! Improve tests
omus Aug 13, 2024
a893399
Debug
omus Aug 13, 2024
bbb7233
Ensure graceful failure
omus Aug 13, 2024
550caee
fixup
omus Aug 13, 2024
8b638b7
fixup
omus Aug 13, 2024
5c3681f
Refactor
omus Aug 13, 2024
d971623
fixup! Refactor
omus Aug 13, 2024
af3df40
fixup! Refactor
omus Aug 13, 2024
45b4337
Debug
omus Aug 13, 2024
8d24c7f
fixup! Refactor
omus Aug 13, 2024
9fa3041
fixup! Refactor
omus Aug 13, 2024
15f3cf4
Cleanup
omus Aug 13, 2024
0784029
Rename to job-context
omus Aug 13, 2024
21b194f
fixup
omus Aug 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
271 changes: 271 additions & 0 deletions .github/workflows/integration-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
---
name: Integration Tests
on:
pull_request:
paths:
- "action.yaml"
- ".github/workflows/integration-tests.yaml"

jobs:
setup-simple:
name: Setup Simple
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
strategy:
fail-fast: false
matrix:
index:
- 1
- 2
outputs:
results-json: ${{ steps.matrix-output.outputs.json }}
steps:
- uses: actions/checkout@v4
# Slow down on job to ensure that this is the last run
- if: ${{ strategy.job-index == 0 }}
run: sleep 5
# Keep `id` the same between `setup-simple` and `setup-complex`
# to ensure we can separate output per job.
- uses: ./
id: matrix-output
with:
yaml: |
index: ${{ matrix.index }}

test-simple:
name: Test Simple
needs: setup-simple
runs-on: ubuntu-latest
steps:
- name: Output JSON
run: |
if [[ "${output_json}" != "${expected_json}" ]]; then
cat <<<"${output_json}" >"output"
cat <<<"${expected_json}" >"expected"
diff output expected | cat -te
exit 1
fi
env:
output_json: ${{ needs.setup-simple.outputs.results-json }}
expected_json: |-
[
{
"index": 1
},
{
"index": 2
}
]

setup-complex:
name: Setup Complex
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
strategy:
fail-fast: false
matrix:
build:
- name: App One
repo: user/app1
- name: App Two
repo: user/app2
version:
- "1.0"
- "2.0"
outputs:
results-json: ${{ steps.matrix-output.outputs.json }}
steps:
- uses: actions/checkout@v4
# Keep `id` the same between `setup-simple` and `setup-complex`
# to ensure we can separate output per job.
- uses: ./
id: matrix-output
with:
yaml: |
name: ${{ matrix.build.name }}
repo: ${{ matrix.build.repo }}
version_string: "${{ matrix.version }}"
version_number: ${{ matrix.version }}

test-complex:
name: Test Complext
needs: setup-complex
runs-on: ubuntu-latest
steps:
- name: Output JSON
run: |
if [[ "${output_json}" != "${expected_json}" ]]; then
cat <<<"${output_json}" >"output"
cat <<<"${expected_json}" >"expected"
diff output expected | cat -te
exit 1
fi
env:
output_json: ${{ needs.setup-complex.outputs.results-json }}
expected_json: |-
[
{
"name": "App One",
"repo": "user/app1",
"version_string": "1.0",
"version_number": 1
},
{
"name": "App One",
"repo": "user/app1",
"version_string": "2.0",
"version_number": 2
},
{
"name": "App Two",
"repo": "user/app2",
"version_string": "1.0",
"version_number": 1
},
{
"name": "App Two",
"repo": "user/app2",
"version_string": "2.0",
"version_number": 2
}
]

test-empty:
name: Test Empty
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
steps:
- uses: actions/checkout@v4
- uses: ./
id: matrix-output
continue-on-error: true
with:
yaml: ""
- name: Action failed
if: ${{ steps.matrix-output.outcome == 'success' }}
run: exit 1

test-job-name:
name: Job Name
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
steps:
- uses: actions/checkout@v4
- uses: ./job-context/
id: job-context
- name: Matches expected name
run: '[[ "${output}" == "${expected}" ]] || exit 1'
env:
output: ${{ steps.job-context.outputs.job-name }}
expected: "Job Name"

test-job-name-matrix:
name: Job Name
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
strategy:
fail-fast: false
matrix:
build:
- name: App One
repo: user/app1
- name: App Two
repo: user/app2
version:
- "1.0"
- "2.0"
steps:
- uses: actions/checkout@v4
- uses: ./job-context/
id: job-context
- name: Matches expected name
run: '[[ "${output}" == "${expected}" ]] || exit 1'
env:
output: ${{ steps.job-context.outputs.job-name }}
expected: "Job Name (${{ matrix.build.name }}, ${{ matrix.build.repo }}, ${{ matrix.version }})"
- name: Matches GitHub API name
run: |
jobs="$(gh api -X GET "/repos/{owner}/{repo}/actions/runs/${run_id:?}/attempts/${run_attempt:?}/jobs")"
if [[ $(jq --arg name "$job_name" '.jobs | map(select(.name == $name)) | length' <<<"${jobs}") -ne 1 ]]; then
jq '.jobs[].name' <<<"${jobs}"
exit 1
fi
env:
GH_TOKEN: ${{ github.token }}
run_id: ${{ github.run_id }}
run_attempt: ${{ github.run_attempt }}
job_name: ${{ steps.job-context.outputs.job-name }}

test-job-name-matrix-expr:
# TODO: Using `github.job` with any expressions results in it being empty
name: ${{ github.event_name }} - ${{ matrix.dne }} - ${{ matrix.index }} - ${{ strategy.job-index }}
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
strategy:
fail-fast: false
matrix:
index:
- 1
- 2
steps:
- uses: actions/checkout@v4
- uses: ./job-context/
id: job-context
- name: Matches expected name
run: '[[ "${output}" == "${expected}" ]] || exit 1'
env:
output: ${{ steps.job-context.outputs.job-name }}
expected: ${{ github.event_name }} - - ${{ matrix.index }} - ${{ strategy.job-index }}
- name: Matches GitHub API name
run: |
jobs="$(gh api -X GET "/repos/{owner}/{repo}/actions/runs/${run_id:?}/attempts/${run_attempt:?}/jobs")"
if [[ $(jq --arg name "$job_name" '.jobs | map(select(.name == $name)) | length' <<<"${jobs}") -ne 1 ]]; then
jq '.jobs[].name' <<<"${jobs}"
exit 1
fi
env:
GH_TOKEN: ${{ github.token }}
run_id: ${{ github.run_id }}
run_attempt: ${{ github.run_attempt }}
job_name: ${{ steps.job-context.outputs.job-name }}

test-job-name-ambiguous:
name: ${{ github.job }}
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
strategy:
fail-fast: false
matrix:
index:
- 1
- 2
steps:
- uses: actions/checkout@v4
- uses: ./job-context/
id: job-context
- name: Matches expected name
run: '[[ "${output}" == "${expected}" ]] || exit 1'
env:
output: ${{ steps.job-context.outputs.job-name }}
expected: ${{ github.job }}
- name: Matches multiple jobs
run: |
[[ $(jq length <<<"${job_ids}") -eq 2 ]] || exit 1
[[ -z "${job_id}" ]] || exit 1
env:
job_ids: ${{ steps.job-context.outputs.job-ids }}
job_id: ${{ steps.job-context.outputs.job-id }}
77 changes: 75 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,75 @@
# matrix-output
Collect outputs from each matrix job
# Matrix Output

Collect outputs from each matrix job. Currently, setting output for matrix jobs will cause outputs of earlier completed jobs to be overwritten by jobs completed later (see [discussion](https://github.com/orgs/community/discussions/26639)). This action allows the output from each matrix job to be collected into a JSON list to be utilized by dependent jobs.

## Examples

```yaml
# CI.yaml
jobs:
build:
name: Build ${{ matrix.build.name }}
# These permissions are needed to:
# - Use `matrix-output`: https://github.com/beacon-biosignals/matrix-output#permissions
permissions:
actions: read
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
build:
- name: App One
repo: user/app1
- name: App Two
repo: user/app2
outputs:
json: ${{ steps.matrix-output.outputs.json }}
steps:
- uses: docker/build-push-action@v6
id: build-push
with:
tags: ${{ matrix.build.repo }}:latest
push: true
- uses: beacon-biosignals/matrix-output@v1
id: matrix-output
with:
yaml: |
name: ${{ matrix.build.name }}
image: ${{ matrix.build.repo }}@${{ steps.build-push.outputs.digest }}

test:
name: Test ${{ matrix.build.name }}
needs: build
runs-on: ubuntu-latest
container:
image: ${{ matrix.build.image }}
strategy:
fail-fast: false
matrix:
build: ${{ fromJSON(needs.build.outputs.json) }}
steps:
...
```

## Inputs

The `matrix-output` action supports the following inputs:

| Name | Description | Required | Example |
|:-----------------|:------------|:---------|:--------|
| `yaml` | A string representing a YAML data. Typically, a simple dictionary of key/value pairs. | Yes | <pre><code class="language-yaml">name: ${{ matrix.name }}&#10;...</code></pre> |

## Outputs

| Name | Description | Example |
|:-------|:------------|:--------|
| `json` | A string representing a JSON list of dictionaries. Each dictionary in the list contains the output for a single job from the job matrix. The order of this list corresponds to the job index (i.e. `strategy.job-index`). | <pre><code class="language-json">[&#10; {&#10; "name": "Server.jl",&#10; ...&#10; },&#10; {&#10; "name": "Client.jl",&#10; ...&#10; }&#10;]</code></pre> |

## Permissions

The follow [job permissions](https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs) are required to run this action:

```yaml
permissions:
action: read
```
Loading
Loading