Skip to content

Commit 3e94ddf

Browse files
authored
feat: Release automation (#111)
Using semantic-release in a cron job we publish a new devcontainer image every week with semantic versioning / conventional commits every week, if there are changes. If no changes or chore changes have been done no release will be made.
1 parent b5a7114 commit 3e94ddf

5 files changed

Lines changed: 160 additions & 91 deletions

File tree

.github/workflows/publish.yaml

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# *******************************************************************************
2+
# Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
#
4+
# See the NOTICE file(s) distributed with this work for additional
5+
# information regarding copyright ownership.
6+
#
7+
# This program and the accompanying materials are made available under the
8+
# terms of the Apache License Version 2.0 which is available at
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# SPDX-License-Identifier: Apache-2.0
12+
# *******************************************************************************
13+
name: Validate & Publish DevContainer
14+
description: This workflow is checking that for releases, updates do not break stuff and publishes the released container.
15+
on:
16+
push:
17+
tags:
18+
- v[0-9]+.[0-9]+.[0-9]+
19+
jobs:
20+
build:
21+
strategy:
22+
matrix:
23+
os: [arm64, amd64]
24+
include:
25+
- os: amd64
26+
name: DevContainer (amd64)
27+
runner: ubuntu-24.04
28+
- os: arm64
29+
name: DevContainer (arm64)
30+
runner: ubuntu-24.04-arm
31+
name: ${{ matrix.name }}
32+
runs-on: ${{ matrix.runner }}
33+
permissions:
34+
contents: read
35+
packages: write
36+
id-token: write
37+
steps:
38+
- uses: eclipse-score/more-disk-space@v1
39+
- name: Checkout (GitHub)
40+
uses: actions/checkout@v6
41+
- name: Login to GitHub Container Registry
42+
uses: docker/login-action@v4
43+
with:
44+
registry: ghcr.io
45+
username: ${{ github.actor }}
46+
password: ${{ secrets.GITHUB_TOKEN }}
47+
# Use .devcontainer from THIS repo for building and testing
48+
- name: Check, Build, Test, Publish
49+
uses: devcontainers/ci@v0.3
50+
with:
51+
# The .devcontainer is never published as pre-built container.
52+
# We want to only use it for building and testing the actual container, which resides in src/s-core-devcontainer.
53+
push: never
54+
runCmd: |
55+
set -eux pipefail
56+
57+
# Check
58+
pre-commit run --show-diff-on-failure --color=always --all-files || exit 1
59+
60+
# Create builder for multi-arch builds
61+
./scripts/create_builder.sh
62+
63+
# Build
64+
./scripts/build.sh --${{ matrix.os }} "${{ github.ref_name }}" "latest"
65+
66+
# Test
67+
./scripts/test.sh
68+
69+
# Publish
70+
# We do not use the push feature of devcontainers/ci here, since that would push the wrong container.
71+
# Instead, we use the publish script which pushes the correct container (residing in src/s-core-devcontainer).
72+
# manually login to ghcr.io for publishing
73+
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
74+
./scripts/publish.sh --${{ matrix.os }} "${{ github.ref_name }}" "latest"
75+
merge:
76+
name: Merge Labels
77+
needs: [build]
78+
runs-on: ubuntu-24.04
79+
permissions:
80+
contents: read
81+
packages: write
82+
id-token: write
83+
steps:
84+
- uses: eclipse-score/more-disk-space@v1
85+
- name: Checkout (GitHub)
86+
uses: actions/checkout@v6
87+
- name: Login to GitHub Container Registry
88+
uses: docker/login-action@v4
89+
with:
90+
registry: ghcr.io
91+
username: ${{ github.actor }}
92+
password: ${{ secrets.GITHUB_TOKEN }}
93+
# Use .devcontainer from THIS repo for building and testing
94+
- name: Merge
95+
uses: devcontainers/ci@v0.3
96+
with:
97+
# The .devcontainer is never published as pre-built container.
98+
# We want to only use it for building and testing the actual container, which resides in src/s-core-devcontainer.
99+
push: never
100+
runCmd: |
101+
set -eux pipefail
102+
103+
# Merge
104+
# We do not use the push feature of devcontainers/ci here, since that would push the wrong container.
105+
# Instead, we use the publish script which pushes the correct container (residing in src/s-core-devcontainer).
106+
# manually login to ghcr.io for publishing
107+
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
108+
./scripts/merge.sh "${{ github.ref_name }}" "latest"

.github/workflows/release.yaml

Lines changed: 26 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -10,99 +10,34 @@
1010
#
1111
# SPDX-License-Identifier: Apache-2.0
1212
# *******************************************************************************
13-
name: Validate & Publish DevContainer
14-
description: This workflow is checking that for releases, updates do not break stuff and publishes the released container.
13+
name: DevContainer Release
14+
description: This workflow creates a semantic version release when main changed since the last release tag.
1515
on:
16-
push:
17-
tags:
18-
- v[0-9]+.[0-9]+.[0-9]+
16+
schedule:
17+
- cron: '0 0 * * 1'
18+
workflow_dispatch:
19+
permissions:
20+
contents: read # for checkout
1921
jobs:
20-
build:
21-
strategy:
22-
matrix:
23-
os: [arm64, amd64]
24-
include:
25-
- os: amd64
26-
name: DevContainer (amd64)
27-
runner: ubuntu-24.04
28-
- os: arm64
29-
name: DevContainer (arm64)
30-
runner: ubuntu-24.04-arm
31-
name: ${{ matrix.name }}
32-
runs-on: ${{ matrix.runner }}
22+
release:
23+
if: github.ref == 'refs/heads/main'
3324
permissions:
34-
contents: read
35-
packages: write
36-
id-token: write
25+
contents: write # to be able to publish a GitHub release
26+
issues: write # to be able to comment on released issues
27+
pull-requests: write # to be able to comment on released pull requests
28+
name: release
29+
runs-on: ubuntu-latest
30+
container:
31+
image: mcr.microsoft.com/devcontainers/javascript-node:4-24
3732
steps:
38-
- uses: eclipse-score/more-disk-space@v1
39-
- name: Checkout (GitHub)
40-
uses: actions/checkout@v6
41-
- name: Login to GitHub Container Registry
42-
uses: docker/login-action@v4
33+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
4334
with:
44-
registry: ghcr.io
45-
username: ${{ github.actor }}
46-
password: ${{ secrets.GITHUB_TOKEN }}
47-
# Use .devcontainer from THIS repo for building and testing
48-
- name: Check, Build, Test, Publish
49-
uses: devcontainers/ci@v0.3
50-
with:
51-
# The .devcontainer is never published as pre-built container.
52-
# We want to only use it for building and testing the actual container, which resides in src/s-core-devcontainer.
53-
push: never
54-
runCmd: |
55-
set -eux pipefail
56-
57-
# Check
58-
pre-commit run --show-diff-on-failure --color=always --all-files || exit 1
59-
60-
# Create builder for multi-arch builds
61-
./scripts/create_builder.sh
62-
63-
# Build
64-
./scripts/build.sh --${{ matrix.os }} "${{ github.ref_name }}" "latest"
65-
66-
# Test
67-
./scripts/test.sh
68-
69-
# Publish
70-
# We do not use the push feature of devcontainers/ci here, since that would push the wrong container.
71-
# Instead, we use the publish script which pushes the correct container (residing in src/s-core-devcontainer).
72-
# manually login to ghcr.io for publishing
73-
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
74-
./scripts/publish.sh --${{ matrix.os }} "${{ github.ref_name }}" "latest"
75-
merge:
76-
name: Merge Labels
77-
needs: [build]
78-
runs-on: ubuntu-24.04
79-
permissions:
80-
contents: read
81-
packages: write
82-
id-token: write
83-
steps:
84-
- uses: eclipse-score/more-disk-space@v1
85-
- name: Checkout (GitHub)
86-
uses: actions/checkout@v6
87-
- name: Login to GitHub Container Registry
88-
uses: docker/login-action@v4
89-
with:
90-
registry: ghcr.io
91-
username: ${{ github.actor }}
92-
password: ${{ secrets.GITHUB_TOKEN }}
93-
# Use .devcontainer from THIS repo for building and testing
94-
- name: Merge
95-
uses: devcontainers/ci@v0.3
96-
with:
97-
# The .devcontainer is never published as pre-built container.
98-
# We want to only use it for building and testing the actual container, which resides in src/s-core-devcontainer.
99-
push: never
100-
runCmd: |
101-
set -eux pipefail
102-
103-
# Merge
104-
# We do not use the push feature of devcontainers/ci here, since that would push the wrong container.
105-
# Instead, we use the publish script which pushes the correct container (residing in src/s-core-devcontainer).
106-
# manually login to ghcr.io for publishing
107-
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
108-
./scripts/merge.sh "${{ github.ref_name }}" "latest"
35+
fetch-depth: 0
36+
fetch-tags: true
37+
# this should have been done by the checkout action, but it doesn't work in a container, see https://github.com/actions/checkout/issues/766
38+
- run: git config --global --add safe.directory $PWD
39+
# pinned version updated automatically by Dependabot.
40+
# details at https://semantic-release.gitbook.io/semantic-release/usage/installation#global-installation
41+
- run: npx semantic-release@25.0.1
42+
env:
43+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.releaserc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"branches": [
3+
"main"
4+
],
5+
"plugins": [
6+
"@semantic-release/commit-analyzer",
7+
"@semantic-release/release-notes-generator",
8+
"@semantic-release/github"
9+
]
10+
}

REUSE.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,8 @@ path = ["resources/reopen_in_container.png",
2929
]
3030
SPDX-FileCopyrightText = "Copyright (c) 2026 Contributors to the Eclipse Foundation"
3131
SPDX-License-Identifier = "Apache-2.0"
32+
33+
[[annotations]]
34+
path = [".releaserc"]
35+
SPDX-FileCopyrightText = "Copyright (c) 2026 Contributors to the Eclipse Foundation"
36+
SPDX-License-Identifier = "Apache-2.0"

docs/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,14 @@ It strengthens the supply chain by pinning versions and hashes, sourcing feature
9898
Pre-built images have a higer availability than the set of all tools which are installed (one download from a location controlled by S-CORE vs. many downloads from "everywhere").
9999
Pre-built images can be easily archived anywhere, e.g. for reproducibility of builds in real production use-cases.
100100
It also enforces a clear separation of concerns: general tooling is delivered through reusable features, S-CORE–specific logic lives in a dedicated feature, and image composition plus publishing are centralized.
101+
102+
## Release Automation
103+
104+
Releases are cut automatically once per week from `main`, but only if commits were added since the latest `v<major>.<minor>.<patch>` tag.
105+
The scheduled workflow creates the git tag and GitHub release, and the existing tag-triggered release workflow then builds, tests and publishes the matching container image.
106+
107+
The next semantic version is derived from commit messages since the previous release:
108+
109+
* breaking changes (`!` in the conventional commit header or `BREAKING CHANGE:` in the body) increment the major version
110+
* `feat` commits increment the minor version
111+
* every other commit increments the patch version so maintenance-only weeks still publish a new immutable image

0 commit comments

Comments
 (0)