This repository was archived by the owner on Oct 13, 2026. It is now read-only.
Repository navigation
130 lines (116 loc) · 5.59 KB
/
Copy pathrelease.yml
File metadata and controls
130 lines (116 loc) · 5.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# SPDX-FileCopyrightText: 2026 ourPLCC contributors
# SPDX-License-Identifier: GPL-3.0-or-later
name: Release
on:
push:
branches: [main]
# These grants applied to GITHUB_TOKEN, which semantic-release no longer
# uses — it authenticates with the App token now. The only remaining use of
# GITHUB_TOKEN is the GHCR login, so packages:write is all that is needed.
permissions: {}
jobs:
release:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
# A static PAT rots silently: this one expired and only surfaced months
# later, failing checkout on the next push to main. App installation
# tokens are minted per run and expire in about an hour, so there is
# nothing long-lived to go stale.
- name: Generate release bot token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
# On main the only reason to build is to feed a release — CI already
# verified the code on the PR. Infra-only merges (ci:, docs:, chore:)
# release nothing, so building them spends minutes to produce an image
# that is then thrown away. Ask semantic-release first; this publishes
# nothing.
#
# Path filtering cannot answer this: a releasing commit that touches
# only docs would skip the build and then have no image to publish.
# The release decision is what matters, not the diff.
- name: Would this commit release? (dry run)
id: plan
uses: cycjimmy/semantic-release-action@v4
with:
dry_run: true
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
- name: Report plan
run: |
echo "will_release=${{ steps.plan.outputs.new_release_published }}"
echo "version=${{ steps.plan.outputs.new_release_version }}"
# Guarded with != 'false' rather than == 'true' so an empty or
# unexpected output still builds. Skipping a build that a release needs
# would leave the publish step with no image; an extra build only costs
# time. The build still precedes the real release, so a broken image
# cannot be published.
- name: Log in to GHCR
if: steps.plan.outputs.new_release_published != 'false'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and test devcontainer image
if: steps.plan.outputs.new_release_published != 'false'
uses: devcontainers/ci@v0.3
with:
imageName: ghcr.io/ourplcc/plcc-devcontainer
push: never
runCmd: bash test/test-env.sh
- name: Run semantic-release
id: semantic
uses: cycjimmy/semantic-release-action@v4
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
# The two runs see the same commits and should never disagree, but if
# they did the consequence would be silent and bad: no image was built,
# and the publish step's `FROM ...:latest` would pull the *previous*
# release's image and push it under the new version tags. Fail loudly
# instead of shipping stale content under a fresh version.
- name: Fail if the dry run and the real release disagreed
if: steps.semantic.outputs.new_release_published == 'true' && steps.plan.outputs.new_release_published == 'false'
run: |
echo "::error::semantic-release published ${{ steps.semantic.outputs.new_release_version }}, but the dry run predicted no release, so no image was built. Refusing to publish."
exit 1
- name: Read PLCC version
if: steps.semantic.outputs.new_release_published == 'true'
id: plcc_version
run: |
echo "version=$(jq -r '.features["./features/plcc"].version' .devcontainer/devcontainer.json)" \
>> "$GITHUB_OUTPUT"
- name: Apply OCI labels and push all tags
if: steps.semantic.outputs.new_release_published == 'true'
# devcontainers/ci built the image locally as ghcr.io/ourplcc/plcc-devcontainer:latest.
# We re-tag it with OCI labels and push with all floating version tags.
env:
VERSION: ${{ steps.semantic.outputs.new_release_version }}
PLCC_VERSION: ${{ steps.plcc_version.outputs.version }}
run: |
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MAJOR_MINOR=$(echo "$VERSION" | cut -d. -f1-2)
REPO="https://github.com/ourPLCC/plcc-devcontainer"
# TODO: update org.opencontainers.image.licenses to GPL-3.0-or-later after REUSE migration
printf 'FROM %s\nLABEL org.opencontainers.image.version="%s"\nLABEL org.opencontainers.image.source="%s"\nLABEL org.opencontainers.image.description="%s"\nLABEL org.opencontainers.image.licenses="%s"\nLABEL org.plcc.version="%s"\n' \
"ghcr.io/ourplcc/plcc-devcontainer:latest" \
"$VERSION" "$REPO" \
"Prebuilt devcontainer image with PLCC, Java, and Python" \
"MIT" "$PLCC_VERSION" \
> Dockerfile.labels
docker buildx build \
-f Dockerfile.labels \
-t "ghcr.io/ourplcc/plcc-devcontainer:$VERSION" \
-t "ghcr.io/ourplcc/plcc-devcontainer:$MAJOR" \
-t "ghcr.io/ourplcc/plcc-devcontainer:$MAJOR_MINOR" \
-t "ghcr.io/ourplcc/plcc-devcontainer:latest" \
--push .