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

Initial action implemention #1

Merged
merged 78 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from 76 commits
Commits
Show all changes
78 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
7839ee4
Use once per job
omus Aug 13, 2024
a14de77
fixup! Use once per job
omus Aug 13, 2024
b56e5a8
Re-runs can cause extra uploads
omus Aug 13, 2024
f52de76
Always download artifacts
omus Aug 13, 2024
55f56ac
Typo
omus Aug 13, 2024
03229d8
Add race condition test
omus Aug 13, 2024
9ac2cc7
Ensure artifact name is present
omus Aug 13, 2024
32aae82
Test re-run non-failed scenario
omus Aug 13, 2024
e254786
Create job-context action
omus Aug 13, 2024
94ae218
Use job-id in artifact
omus Aug 13, 2024
580e723
fixup! Create job-context action
omus Aug 13, 2024
466c693
fixup! Create job-context action
omus Aug 13, 2024
df70a91
fixup! Use job-id in artifact
omus Aug 13, 2024
b2b42fd
Clone hotfix
omus Aug 13, 2024
232e023
fixup! Clone hotfix
omus Aug 13, 2024
dabf4aa
fixup! Clone hotfix
omus Aug 13, 2024
14e66b3
fixup! Clone hotfix
omus Aug 13, 2024
babf07a
fixup! Clone hotfix
omus Aug 13, 2024
b3dfd9f
Embed job-id in artifact
omus Aug 14, 2024
1cdd475
fixup! Embed job-id in artifact
omus Aug 14, 2024
4708d15
Completed job calculation
omus Aug 14, 2024
318fa17
fixup! Completed job calculation
omus Aug 14, 2024
cb042e8
fixup! Completed job calculation
omus Aug 14, 2024
ac39c9c
Iterating
omus Aug 14, 2024
0d77b77
Experiment
omus Aug 14, 2024
1fb0f5c
fixup
omus Aug 14, 2024
88a3f91
Iterate
omus Aug 14, 2024
ac86c14
Update race condition test
omus Aug 14, 2024
e9ed398
Iterate
omus Aug 14, 2024
ee6b449
Wait step
omus Aug 14, 2024
1543679
fixup
omus Aug 14, 2024
e3c1fa9
Only write output on final job
omus Aug 14, 2024
b648f37
fixup
omus Aug 14, 2024
6057379
New wait attempt
omus Aug 15, 2024
db50d33
Create empty file
omus Aug 15, 2024
7ae8c82
fixup
omus Aug 15, 2024
322ec8d
fixup
omus Aug 15, 2024
baa1e5d
fixup
omus Aug 15, 2024
a7f38d2
fixup
omus Aug 15, 2024
6148172
Debug re-run
omus Aug 15, 2024
5578a13
Jobs API call rework
omus Aug 15, 2024
831af4d
fixup! Jobs API call rework
omus Aug 15, 2024
b5edfa9
fixup! Jobs API call rework
omus Aug 15, 2024
6fef98a
Add design documentation
omus Aug 15, 2024
eb81926
Use separate step for executed jobs
omus Aug 15, 2024
ba490b2
fixup! Use separate step for executed jobs
omus Aug 15, 2024
d0e33c1
Refactor
omus Aug 16, 2024
0c95ee0
Debug
omus Aug 16, 2024
a437729
fixup! Debug
omus Aug 16, 2024
4daa16a
Iterate
omus Aug 16, 2024
6686137
Debug
omus Aug 16, 2024
251102f
Debug
omus Aug 16, 2024
ec4b61a
Refactor jq join
omus Aug 16, 2024
089a526
fixup
omus Aug 16, 2024
253d9d1
Reduced debug logging
omus Aug 16, 2024
03f370f
Wait timing fix
omus Aug 16, 2024
a0b2d0d
Reduced debug logging
omus Aug 16, 2024
d4b97af
Make setup-complext pass
omus Aug 16, 2024
19cbf66
fixup
omus Aug 16, 2024
85b4eb2
Iterate on job-context
omus Aug 16, 2024
ce8da14
Use revised job-context
omus Aug 16, 2024
12594ff
fixup
omus Aug 16, 2024
d5745be
fixup
omus Aug 16, 2024
058ddcc
fixup
omus Aug 16, 2024
bd7ffad
fixup
omus Aug 16, 2024
50db99d
Update integration tests
omus Aug 16, 2024
a39c495
fixup
omus Aug 16, 2024
8596e79
Bug fix
omus Aug 16, 2024
4c8c049
Iterating on job-context
omus Aug 16, 2024
19ffc29
Use argjson instead of tonumber
omus Aug 16, 2024
d3aac25
Documentation updates
omus Aug 16, 2024
c5de515
Use external job-context
omus Aug 16, 2024
7c8e495
Create LICENSE
omus Aug 27, 2024
8ce78d3
Use tagged version of job-context
omus Sep 19, 2024
48365ab
Add branding
omus Oct 10, 2024
eaf8dd4
Add reasons for permission requirements
omus Oct 10, 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
233 changes: 233 additions & 0 deletions .github/workflows/integration-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
---
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 }}
debug: true

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 }}
debug: true

test-complex:
name: Test Complex
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: ""
debug: true
- name: Action failed
if: ${{ steps.matrix-output.outcome != 'failure' }}
run: exit 1

test-duplicate:
name: Test Duplicate
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
steps:
- uses: actions/checkout@v4
- uses: ./
id: matrix-output1
continue-on-error: true
with:
yaml: |
demo: 1
debug: true
- uses: ./
id: matrix-output2
continue-on-error: true
with:
yaml: |
demo: 2
debug: true
- name: Action failed
if: ${{ steps.matrix-output1.outcome != 'success' || steps.matrix-output2.outcome != 'failure' }}
run: exit 1

setup-race-condition:
name: Setup Race Condition
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
- if: ${{ strategy.job-index == 0 }}
run: sleep 5
- uses: ./
id: matrix-output
with:
yaml: |
index: ${{ matrix.index }}
debug: true
- if: ${{ strategy.job-index == 1 }}
run: sleep 30

test-race-condition:
name: Test Race Condition
needs: setup-race-condition
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-race-condition.outputs.results-json }}
expected_json: |-
[
{
"index": 1
},
{
"index": 2
}
]
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 Beacon Biosignals

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
88 changes: 86 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,86 @@
# 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.

## Requirements

The `matrix-output` action requires that each job in the job matrix uses a distinct job name which is unique within the workflow file. By default job matrix job names are distinct (e.g. `name: Build` -> `Build (App One, user/app1)`) so this only a problem if you accidentally specify the same job name for multiple matrix jobs. If the job name is not unique within the workflow this action will fail and report the ambiguous job name.

Additionally, the `matrix-output` action is intended to only be used once within a job. Attempting to utilize this action multiple times within the same job will cause the second use of this action to fail.

Finally, it is highly recommended that the `matrix-output` is either the last step in the job or the near the end of the job. If you choose to have this action run before other slow running actions you may see some extended runtimes for the last few running jobs in the matrix. In order to guarantee correct output we require that the last running job has a complete set of outputs from all other jobs in the matrix. To ensure the last running job has a complete set of outputs we have those jobs wait for other jobs with an incomplete set of outputs.

## 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
# !!! Important: In order to reduce delays we highly recommend that the
# `matrix-output` action is either the last step in a job or close to the end.
- 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:
actions: read
contents: read
```
Loading
Loading