Skip to content

Commit 21e02a2

Browse files
authored
Merge pull request #2868 from devitocodes/JDBetteridge/unique_ci_docker_tag
JDBetteridge/Composite actions
2 parents e147aaa + 55cae25 commit 21e02a2

13 files changed

Lines changed: 653 additions & 435 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Docker build action
2+
description: Composite action for building Devito Docker containers
3+
author: "Devito"
4+
5+
inputs:
6+
# The only supported GHA input type is string
7+
file:
8+
description: "Dockerfile containing build instructions"
9+
required: true
10+
default: Dockerfile
11+
tag:
12+
description: "Tag to add to the built image"
13+
required: true
14+
base:
15+
description: "Base docker image to build on top of"
16+
default: ""
17+
args:
18+
description: "Arguments to pass to `docker build`"
19+
required: true
20+
default: ""
21+
22+
outputs:
23+
unique:
24+
description: "Unique identifier for the CI run"
25+
value: ${{ steps.uniquetag.outputs.unique }}
26+
27+
runs:
28+
using: "composite"
29+
steps:
30+
- id: uniquetag
31+
name: "Generate unique CI tag"
32+
shell: bash
33+
run: |
34+
UNIQUE=$(echo "${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}" | cksum | cut -f 1 -d " ")
35+
echo "Unique ID: ${UNIQUE}"
36+
echo "unique=${UNIQUE}" >> "$GITHUB_OUTPUT"
37+
38+
- id: dockerbuild
39+
name: "Build docker container"
40+
shell: bash
41+
env:
42+
BASE: ${{ inputs.base }}
43+
run: |
44+
docker build \
45+
--pull \
46+
--file ${{ inputs.file }} \
47+
--tag ${{ inputs.tag }}_${{ steps.uniquetag.outputs.unique }} \
48+
${BASE:+--build-arg base=$BASE} \
49+
${{ inputs.args }} \
50+
.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Docker cleanup action
2+
description: Composite action for removing Docker images
3+
author: "Devito"
4+
5+
inputs:
6+
# The only supported GHA input type is string
7+
uid:
8+
description: "Unique identifier output from docker-build action"
9+
required: true
10+
tag:
11+
description: "Tag of the built image to use"
12+
required: true
13+
14+
runs:
15+
using: "composite"
16+
steps:
17+
- id: dockerclean
18+
name: "Cleanup docker image"
19+
shell: bash
20+
run: |
21+
docker image rm -f "${{ inputs.tag }}_${{ inputs.uid }}"
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: Docker run action
2+
description: Composite action for running commands in Docker containers
3+
author: "Devito"
4+
5+
inputs:
6+
# The only supported GHA input type is string
7+
uid:
8+
description: "Unique identifier output from docker-build action"
9+
required: true
10+
tag:
11+
description: "Tag of the built image to use"
12+
required: true
13+
name:
14+
description: "Name substring for docker to use when running the command"
15+
default: ""
16+
args:
17+
description: "Arguments to pass to `docker run`, `--init -t --rm` are always added"
18+
required: true
19+
default: ""
20+
env:
21+
description: "Environment variables to set inside the docker container, one environment variable per line"
22+
required: true
23+
default: ""
24+
command:
25+
description: "Command to execute inside of the docker container"
26+
required: true
27+
28+
runs:
29+
using: "composite"
30+
steps:
31+
- id: processenv
32+
name: Process environment variable list
33+
shell: bash
34+
env:
35+
ENV_INPUT: ${{ inputs.env }}
36+
run: |
37+
ENV_STRING=""
38+
# Read line by line with here string, safely handling spaces within the values
39+
while IFS= read -r LINE; do
40+
if [[ -n "$LINE" ]]; then
41+
ENV_STRING="$ENV_STRING --env $LINE"
42+
fi
43+
done <<< "$ENV_INPUT"
44+
# Remove the leading space from the first concatenation
45+
ENV_STRING="${ENV_STRING# }"
46+
echo "docker_environment_args=$ENV_STRING" >> "$GITHUB_OUTPUT"
47+
48+
- id: dockerrun
49+
name: "Run command ${{ inputs.command }} in ${{ inputs.tag }} docker container"
50+
shell: bash
51+
env:
52+
NAME: ${{ input.name }}
53+
run: |
54+
docker run \
55+
--init -t --rm \
56+
${{ inputs.args }} \
57+
--name "ci-${NAME:-${{ inputs.tag }}}-${{ inputs.uid }}" \
58+
--env-file=docker/coverage.env \
59+
${{ steps.processenv.outputs.docker_environment_args }} \
60+
"${{ inputs.tag }}_${{ inputs.uid }}" \
61+
${{ inputs.command }}

.github/actions/readme.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Devito Actions
2+
3+
The Devito actions can either be used from the Github interface:
4+
```yaml
5+
uses: devitocodes/devito/.github/actions/docker-build@main
6+
```
7+
8+
Or internally from within the repository:
9+
```yaml
10+
uses: ./.github/actions/docker-run
11+
```
12+
13+
## `docker-build`
14+
15+
Inputs:
16+
17+
- `file`: Dockerfile containing build instructions (default: `Dockerfile`)
18+
- `tag`: Tag to add to the built image
19+
- `base`: Base docker image to build on top of
20+
- `args`: Arguments to pass to `docker build`
21+
22+
Outputs:
23+
24+
- `unique`: Unique identifier for the CI run (ie: `${{ steps.build.outputs.unique }}`)
25+
26+
Example:
27+
28+
```yaml
29+
jobs:
30+
test:
31+
steps:
32+
- id: build
33+
name: Build docker image for Devito
34+
uses: ./.github/actions/docker-build
35+
with:
36+
file: docker/Dockerfile.devito
37+
tag: tag-related-to-test-config
38+
base: base-image-to-build-from
39+
args: "--more-docker-build-args"
40+
```
41+
42+
## `docker-run`
43+
44+
Inputs:
45+
46+
- `uid`: Unique identifier output from docker-build action
47+
- `tag`: Tag of the built image to use
48+
- `name`: Name substring for docker to use when running the command (optional)
49+
- `args`: Arguments to pass to `docker run`, `--init -t --rm` are always added
50+
- `env`: Environment variables to set inside the docker container, one environment variable per line
51+
-command: Command to execute inside of the docker container
52+
53+
### Notes
54+
55+
- The UID must be unique, easily obtained from build action
56+
- The tag must match built image, easily obtained from build action
57+
- If you provide a custom name `foo` the container name will be `ci-foo-UUUUUUUUUU` where UUUUUUUUUU is the UID
58+
- The default args `--init -t --rm` are _always_ added
59+
- Environment variables must be passed a single environment variable per line, best achieved with the (`|`) syntax in yaml
60+
- Only a single command is executed, not a list of commands. Using `;` or `&&` will result in subsequent commands being executed outside of the docker environment
61+
62+
Example:
63+
64+
```yaml
65+
jobs:
66+
test:
67+
steps:
68+
- name: Run a command in a previously built Docker container
69+
uses: ./.github/actions/docker-run
70+
with:
71+
uid: ${{ steps.build.outputs.unique }}
72+
tag: tag-related-to-test-config
73+
name: completely-optional-name
74+
args: "--more-docker-run-args"
75+
env: |
76+
FOO=value1
77+
BAR=value2
78+
command: |
79+
mpiexec -n 4 \
80+
python \
81+
my_complicated_script.py --arg1 -v
82+
```
83+
84+
## `docker-clean`
85+
86+
Inputs:
87+
88+
- `uid`: Unique identifier output from docker-build action
89+
- `tag`: Tag of the built image to use
90+
91+
### Notes
92+
93+
- UID must be unique, easily obtained from build action
94+
- Tag must match built image, easily obtained from build action
95+
- Use `if: always()` to always clean up the image, even if the workflow fails
96+
97+
Example:
98+
99+
```yaml
100+
jobs:
101+
test:
102+
steps:
103+
- name: Cleanup Docker image
104+
if: always()
105+
uses: ./.github/actions/docker-clean
106+
with:
107+
uid: ${{ steps.build.outputs.unique }}
108+
tag: tag-related-to-test-config
109+
```

.github/workflows/docker-devito.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ jobs:
178178
run: |
179179
docker run ${{ matrix.flag }} --rm -t --name "${CONTAINER_NAME}" \
180180
devitocodes/devito:${{ matrix.tag }}-dev \
181-
pytest ${{ matrix.test }}
181+
pytest -v ${{ matrix.test }}
182182
183183
deploy-devito-manifest:
184184
needs: deploy-devito
@@ -292,4 +292,4 @@ jobs:
292292
run: |
293293
docker run ${{ matrix.flag }} --rm -t --name "${CONTAINER_NAME}" \
294294
devitocodes/devito:${{ matrix.tag }}-dev \
295-
pytest ${{ matrix.test }}
295+
pytest -v ${{ matrix.test }}

.github/workflows/examples-mpi.yaml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ concurrency:
1414
cancel-in-progress: true
1515

1616
on:
17-
# Trigger the workflow on push or pull request,
18-
# but only for the main branch
17+
# Trigger the workflow on push or pull request, but only for the main branch
1918
push:
2019
branches:
2120
- main
@@ -72,15 +71,17 @@ jobs:
7271
ipcluster start --profile=mpi --engines=mpi -n 4 --daemonize
7372
# A few seconds to ensure workers are ready
7473
sleep 10
75-
py.test --nbval examples/mpi
74+
pytest -v --nbval examples/mpi
7675
ipcluster stop --profile=mpi
7776
7877
- name: Test seismic examples
7978
run: |
80-
mpirun ${{ matrix.mpiarg }} pytest examples/seismic/tti/tti_example.py
81-
mpirun ${{ matrix.mpiarg }} pytest examples/seismic/elastic/elastic_example.py
82-
mpirun ${{ matrix.mpiarg }} pytest examples/seismic/viscoacoustic/viscoacoustic_example.py
83-
mpirun ${{ matrix.mpiarg }} pytest examples/seismic/viscoelastic/viscoelastic_example.py
79+
mpirun ${{ matrix.mpiarg }} \
80+
pytest -v \
81+
examples/seismic/tti/tti_example.py \
82+
examples/seismic/elastic/elastic_example.py \
83+
examples/seismic/viscoacoustic/viscoacoustic_example.py \
84+
examples/seismic/viscoelastic/viscoelastic_example.py
8485
8586
- name: Test fwi examples with mpi
8687
run: |

.github/workflows/examples.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ concurrency:
88
cancel-in-progress: true
99

1010
on:
11-
# Trigger the workflow on push or pull request,
12-
# but only for the main branch
11+
# Trigger the workflow on push or pull request, but only for the main branch
1312
push:
1413
branches:
1514
- main
@@ -32,7 +31,7 @@ jobs:
3231
DEVITO_LANGUAGE: "openmp"
3332

3433
strategy:
35-
# Prevent all build to stop if a single one fails
34+
# Prevent cancellation if a single workflow fails
3635
fail-fast: false
3736

3837
steps:

.github/workflows/lint.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ concurrency:
77
cancel-in-progress: true
88

99
on:
10-
# Trigger the workflow on push or pull request,
11-
# but only for the main branch
10+
# Trigger the workflow on push or pull request, but only for the main branch
1211
push:
1312
branches:
1413
- main

0 commit comments

Comments
 (0)