Skip to content

Commit 3166a79

Browse files
authored
Chore: [AEA-0000] - workflow to update dev container (#87)
## Summary - Routine Change ### Details - workflow to update dev container
1 parent ac06e5f commit 3166a79

File tree

2 files changed

+192
-0
lines changed

2 files changed

+192
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
name: Update Dev Container Image version
2+
on:
3+
workflow_call:
4+
inputs:
5+
base_branch:
6+
required: false
7+
type: string
8+
default: main
9+
secrets:
10+
AUTOMERGE_APP_ID:
11+
required: true
12+
AUTOMERGE_PEM:
13+
required: true
14+
jobs:
15+
update_devcontainer_version:
16+
runs-on: ubuntu-22.04
17+
permissions:
18+
contents: read
19+
packages: read
20+
pull-requests: write
21+
steps:
22+
- name: Checkout code
23+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
24+
with:
25+
fetch-depth: 0
26+
- name: Load config value
27+
id: load-config
28+
run: >
29+
DEVCONTAINER_IMAGE=$(jq -r '.build.args.IMAGE_NAME'
30+
.devcontainer/devcontainer.json)
31+
32+
DEVCONTAINER_VERSION=$(jq -r '.build.args.IMAGE_VERSION'
33+
.devcontainer/devcontainer.json)
34+
35+
{
36+
echo "DEVCONTAINER_IMAGE=$DEVCONTAINER_IMAGE"
37+
echo "DEVCONTAINER_VERSION=$DEVCONTAINER_VERSION"
38+
} >> "$GITHUB_ENV"
39+
- name: Resolve latest devcontainer image version from GHCR
40+
id: resolve-version
41+
env:
42+
GH_TOKEN: "${{ github.token }}"
43+
run: >
44+
set -euo pipefail
45+
46+
47+
PACKAGE_NAME="eps-devcontainers/${DEVCONTAINER_IMAGE}"
48+
49+
ENCODED_PACKAGE_NAME=$(python3 -c 'import sys, urllib.parse;
50+
print(urllib.parse.quote(sys.argv[1], safe=""))' "$PACKAGE_NAME")
51+
52+
53+
VERSIONS_JSON=$(gh api \
54+
-H "Accept: application/vnd.github+json" \
55+
"/orgs/NHSDigital/packages/container/${ENCODED_PACKAGE_NAME}/versions?per_page=100")
56+
57+
LATEST_VIA_LATEST_TAG=$(jq -r '
58+
[ .[]
59+
| select((.metadata.container.tags // []) | index("latest"))
60+
]
61+
| sort_by(.created_at)
62+
| reverse
63+
| .[0].metadata.container.tags // []
64+
| map(select(test("^v")))
65+
| .[0] // empty
66+
' <<< "$VERSIONS_JSON")
67+
68+
69+
LATEST_V_TAG=$(jq -r '
70+
[ .[]
71+
| {created_at, tags: (.metadata.container.tags // [])}
72+
]
73+
| sort_by(.created_at)
74+
| reverse
75+
| map(.tags[]? | select(test("^v")))
76+
| .[0] // empty
77+
' <<< "$VERSIONS_JSON")
78+
79+
80+
RESOLVED_VERSION="$LATEST_VIA_LATEST_TAG"
81+
82+
if [[ -z "$RESOLVED_VERSION" ]]; then
83+
RESOLVED_VERSION="$LATEST_V_TAG"
84+
fi
85+
86+
87+
if [[ -z "$RESOLVED_VERSION" ]]; then
88+
echo "No version tag matching ^v found for package ${PACKAGE_NAME}" >&2
89+
exit 1
90+
fi
91+
92+
93+
echo "Resolved latest version: ${RESOLVED_VERSION}"
94+
95+
echo "LATEST_DEVCONTAINER_VERSION=${RESOLVED_VERSION}" >>
96+
"$GITHUB_ENV"
97+
98+
echo "latest_version=${RESOLVED_VERSION}" >> "$GITHUB_OUTPUT"
99+
- name: Update devcontainer version in config
100+
run: >
101+
set -euo pipefail
102+
103+
104+
TARGET_VERSION='${{ steps.resolve-version.outputs.latest_version }}'
105+
106+
if [[ "$TARGET_VERSION" == "$DEVCONTAINER_VERSION" ]]; then
107+
echo "IMAGE_VERSION is already up to date (${DEVCONTAINER_VERSION})"
108+
exit 0
109+
fi
110+
111+
112+
python3 - <<'PY'
113+
114+
import json
115+
116+
from pathlib import Path
117+
118+
119+
config_file = Path('.devcontainer/devcontainer.json')
120+
121+
config = json.loads(config_file.read_text())
122+
123+
config['build']['args']['IMAGE_VERSION'] = '${{
124+
steps.resolve-version.outputs.latest_version }}'
125+
126+
config_file.write_text(json.dumps(config, indent=2) + '\n')
127+
128+
PY
129+
130+
131+
echo "Updated IMAGE_VERSION from ${DEVCONTAINER_VERSION} to
132+
${LATEST_DEVCONTAINER_VERSION}"
133+
- name: Create GitHub App Token
134+
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf
135+
id: generate-token
136+
with:
137+
app-id: "${{ secrets.AUTOMERGE_APP_ID }}"
138+
private-key: "${{ secrets.AUTOMERGE_PEM }}"
139+
- name: Create Pull Request
140+
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0
141+
with:
142+
token: "${{ steps.generate-token.outputs.token }}"
143+
commit-message: Update devcontainer image version to ${{ steps.resolve-version.outputs.latest_version }}
144+
title: "Upgrade: [dependabot] - Update devcontainer image version to ${{ steps.resolve-version.outputs.latest_version }}"
145+
body: "This PR updates the devcontainer image version to ${{ steps.resolve-version.outputs.latest_version }}."
146+
add-paths: .devcontainer/devcontainer.json
147+
sign-commits: true
148+
base: "${{ inputs.base_branch }}"
149+
delete-branch: true
150+
branch: update-devcontainer-version

README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The workflows that are available to use are
1212
- [Get Repo Config](#get-repo-config)
1313
- [Quality Checks](#quality-checks)
1414
- [Quality Checks - Dev Container Version](#quality-checks---dev-container-version)
15+
- [Update Dev Container Version](#update-dev-container-version)
1516
- [Tag Release](#tag-release)
1617
- [Tag Release - Devcontainer Version](#tag-release---devcontainer-version)
1718

@@ -250,6 +251,47 @@ jobs:
250251
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
251252
```
252253

254+
## Update Dev Container Version
255+
This workflow updates `.devcontainer/devcontainer.json` with the latest published `v*` version for your configured devcontainer image from GHCR, then opens (or updates) a pull request with that change.
256+
257+
#### Requirements
258+
259+
- `.devcontainer/devcontainer.json` must include `build.args.IMAGE_NAME` and `build.args.IMAGE_VERSION`.
260+
- `AUTOMERGE_APP_ID` and `AUTOMERGE_PEM` secrets must be configured so the workflow can create a GitHub App token for PR creation.
261+
262+
#### Inputs
263+
264+
- `base_branch`: Target branch for the pull request. Default: `main`.
265+
266+
#### Secret Inputs
267+
268+
- `AUTOMERGE_APP_ID`: GitHub App ID used to generate an installation token.
269+
- `AUTOMERGE_PEM`: GitHub App private key used to generate an installation token.
270+
271+
#### Outputs
272+
273+
None
274+
275+
#### Example
276+
277+
To use this workflow in your repository, call it from another workflow file:
278+
279+
```yaml
280+
name: Update Devcontainer Version
281+
282+
on:
283+
workflow_dispatch:
284+
285+
jobs:
286+
update_devcontainer_version:
287+
uses: NHSDigital/eps-common-workflows/.github/workflows/update-dev-container-version.yml@f5c8313a10855d0cc911db6a9cd666494c00045a
288+
with:
289+
base_branch: main
290+
secrets:
291+
AUTOMERGE_APP_ID: ${{ secrets.AUTOMERGE_APP_ID }}
292+
AUTOMERGE_PEM: ${{ secrets.AUTOMERGE_PEM }}
293+
```
294+
253295
## Tag Release
254296
This workflow uses the semantic-release npm package to generate a new version tag, changelog, and GitHub release for a repo.
255297

0 commit comments

Comments
 (0)