Skip to content

Commit 2b6c60e

Browse files
committed
[ci] publish releases with artifacts
* before this, CI built packages but didn’t create a release with downloadable .deb's, now it does, for both amd64 and arm64 architectures and three Debian versions: bookworm, trixie and sid. * in order to make the .deb versioning better, version detection has been changed - on tagged commits, packages use the tag verbatim; otherwise the prevous logic is preserved. * tag matching on master is derived from VERSION (major.minor) instead of hard‑coded. This yields versions that align with release tags and clearer pre‑release identifiers.
1 parent 308862e commit 2b6c60e

3 files changed

Lines changed: 160 additions & 47 deletions

File tree

.github/workflows/ci.yml

Lines changed: 124 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ on:
1010
check_suite:
1111
types: [rerequested]
1212

13+
permissions:
14+
contents: read # to fetch code (actions/checkout)
15+
1316
jobs:
1417

1518
rip-and-test:
@@ -29,6 +32,7 @@ jobs:
2932
set -x
3033
sudo apt-get install -y eatmydata
3134
eatmydata ./scripts/travis-install-build-deps.sh
35+
sudo eatmydata apt --quiet --yes upgrade
3236
cd src
3337
eatmydata ./autogen.sh
3438
eatmydata ./configure --with-realtime=uspace --disable-check-runtime-deps
@@ -54,6 +58,7 @@ jobs:
5458
sudo apt-get install -y eatmydata
5559
eatmydata ./scripts/travis-install-build-deps.sh
5660
sudo eatmydata apt-get install -y clang
61+
sudo eatmydata apt --quiet --yes upgrade
5762
cd src
5863
eatmydata ./autogen.sh
5964
CC=clang CXX=clang++ eatmydata ./configure --with-realtime=uspace --disable-check-runtime-deps
@@ -77,6 +82,7 @@ jobs:
7782
run: |
7883
./scripts/travis-install-build-deps.sh
7984
sudo apt-get install -y eatmydata
85+
sudo eatmydata apt --quiet --yes upgrade
8086
cd src
8187
eatmydata ./autogen.sh
8288
eatmydata ./configure --with-realtime=uspace --disable-check-runtime-deps --enable-build-documentation=html
@@ -86,11 +92,11 @@ jobs:
8692
# Note that the package build covers html docs
8793
8894
package-arch:
89-
runs-on: ubuntu-latest
95+
runs-on: ${{ matrix.runner }}
9096
strategy:
9197
matrix:
92-
image: ["debian:bullseye", "debian:bookworm", "debian:sid"]
93-
98+
runner: ["ubuntu-24.04", "ubuntu-24.04-arm"]
99+
image: ["debian:bullseye", "debian:bookworm", "debian:trixie", "debian:sid"]
94100
container:
95101
image: ${{ matrix.image }}
96102
# IPC_OWNER is needed for shmget IPC_CREAT
@@ -108,7 +114,8 @@ jobs:
108114
set -e
109115
set -x
110116
apt-get --quiet update
111-
apt-get --yes --quiet install eatmydata
117+
apt-get --yes --quiet install eatmydata curl
118+
eatmydata apt --quiet --yes upgrade
112119
# Install stuff needed to check out the linuxcnc repo and turn it into a debian source package.
113120
eatmydata apt-get --yes --quiet install --no-install-suggests git lsb-release python3 devscripts
114121
@@ -118,25 +125,6 @@ jobs:
118125
# our build system to determine the version from tags
119126
fetch-depth: 0
120127

121-
- name: Add linuxcnc.org deb archive
122-
env:
123-
DEBIAN_FRONTEND: noninteractive
124-
run: |
125-
case "${{matrix.image}}" in
126-
debian:sid|debian:bookworm)
127-
exit 0
128-
;;
129-
*)
130-
;;
131-
esac
132-
set -e
133-
set -x
134-
eatmydata apt-get --yes --quiet install --no-install-recommends gpg software-properties-common
135-
eatmydata gpg --homedir="${PWD}/gnupg" --output /etc/apt/trusted.gpg.d/linuxcnc-deb-archive.gpg --export 3CB9FD148F374FEF
136-
DIST=$(echo ${{matrix.image}} | cut -d : -f 2)
137-
eatmydata add-apt-repository "deb http://linuxcnc.org $DIST base"
138-
eatmydata apt-get --quiet update
139-
140128
- name: Build architecture-specific Debian packages
141129
env:
142130
DEBEMAIL: emc-developers@lists.sourceforge.net
@@ -165,12 +153,37 @@ jobs:
165153
eatmydata adduser testrunner sudo
166154
chmod 0777 $(find tests/ -type d) # make test dirs world-writable for the testrunner
167155
su -c "eatmydata ./scripts/runtests -p ./tests" testrunner
156+
- name: Gather build artifacts
157+
run: |
158+
set -e
159+
set -x
160+
ARCH=$(dpkg --print-architecture)
161+
DIST=$(echo ${{ matrix.image }} | cut -d : -f 2)
162+
OUTDIR="artifacts/${DIST}/${ARCH}"
163+
mkdir -p "$OUTDIR"
164+
cp -v ../*.deb ../*.changes ../*.buildinfo "$OUTDIR" || true
165+
(cd "$OUTDIR" && sha256sum * > SHA256SUMS.txt)
166+
echo "DIST=$DIST" >> "$GITHUB_ENV"
167+
echo "ARCH=$ARCH" >> "$GITHUB_ENV"
168+
- name: Compute artifact metadata
169+
id: meta
170+
run: |
171+
echo "dist=$(echo ${{ matrix.image }} | cut -d : -f 2)" >> $GITHUB_OUTPUT
172+
echo "arch=$(dpkg --print-architecture)" >> $GITHUB_OUTPUT
173+
174+
- name: Upload build artifacts
175+
uses: actions/upload-artifact@v4
176+
with:
177+
name: linuxcnc-${{ steps.meta.outputs.dist }}-${{ steps.meta.outputs.arch }}
178+
path: artifacts/${{ steps.meta.outputs.dist }}/${{ steps.meta.outputs.arch }}
179+
if-no-files-found: error
180+
168181

169182
package-indep:
170-
runs-on: ubuntu-latest
183+
runs-on: ubuntu-24.04
171184
strategy:
172185
matrix:
173-
image: ["debian:bullseye", "debian:bookworm", "debian:sid"]
186+
image: ["debian:bullseye", "debian:bookworm", "debian:trixie", "debian:sid"]
174187
container:
175188
image: ${{ matrix.image }}
176189
# IPC_OWNER is needed for shmget IPC_CREAT
@@ -189,7 +202,8 @@ jobs:
189202
set -e
190203
set -x
191204
apt-get --quiet update
192-
apt-get --yes --quiet install eatmydata
205+
apt-get --yes --quiet install eatmydata curl
206+
eatmydata apt --quiet --yes upgrade
193207
# Install stuff needed to check out the linuxcnc repo and turn it into a debian source package.
194208
eatmydata apt-get --yes --quiet install --no-install-suggests git lsb-release python3 devscripts
195209
@@ -204,7 +218,7 @@ jobs:
204218
DEBIAN_FRONTEND: noninteractive
205219
run: |
206220
case "${{matrix.image}}" in
207-
debian:sid|debian:bookworm)
221+
debian:sid|debian:bookworm|debian:trixie)
208222
exit 0
209223
;;
210224
*)
@@ -240,3 +254,86 @@ jobs:
240254
set -e
241255
set -x
242256
eatmydata apt-get --yes --quiet install ../*.deb
257+
- name: Gather build artifacts
258+
run: |
259+
set -e
260+
set -x
261+
DIST=$(echo ${{ matrix.image }} | cut -d : -f 2)
262+
ARCH=all
263+
OUTDIR="artifacts/${DIST}/${ARCH}"
264+
mkdir -p "$OUTDIR"
265+
cp -v ../*.deb ../*.changes ../*.buildinfo "$OUTDIR" || true
266+
(cd "$OUTDIR" && sha256sum * > SHA256SUMS.txt)
267+
echo "DIST=$DIST" >> "$GITHUB_ENV"
268+
echo "ARCH=$ARCH" >> "$GITHUB_ENV"
269+
- name: Compute artifact metadata
270+
id: meta
271+
run: |
272+
echo "dist=$(echo ${{ matrix.image }} | cut -d : -f 2)" >> $GITHUB_OUTPUT
273+
echo "arch=all" >> $GITHUB_OUTPUT
274+
275+
- name: Upload build artifacts
276+
uses: actions/upload-artifact@v4
277+
with:
278+
name: linuxcnc-${{ steps.meta.outputs.dist }}-${{ steps.meta.outputs.arch }}
279+
path: artifacts/${{ steps.meta.outputs.dist }}/${{ steps.meta.outputs.arch }}
280+
if-no-files-found: error
281+
282+
release:
283+
name: Release packages
284+
needs:
285+
- package-arch
286+
- package-indep
287+
if: (github.event_name == 'release' && github.event.action == 'published') || startsWith(github.ref, 'refs/tags/')
288+
permissions:
289+
contents: write
290+
runs-on: ubuntu-24.04
291+
steps:
292+
- name: Download artifacts
293+
uses: actions/download-artifact@v4
294+
with:
295+
path: release_artifacts
296+
- name: Prepare upload assets
297+
run: |
298+
set -e
299+
mkdir -p upload
300+
echo "Downloaded artifacts layout:" && find release_artifacts -maxdepth 3 -print | sed 's/^/ /'
301+
for d in release_artifacts/*; do
302+
[ -d "$d" ] || continue
303+
name=$(basename "$d")
304+
# Expect name like linuxcnc-bookworm-amd64 or linuxcnc-trixie-all
305+
dist=${name#linuxcnc-}
306+
dist=${dist%-*}
307+
arch=${name##*-}
308+
echo "Processing artifact: $name (dist=$dist arch=$arch)"
309+
# Copy .deb files with distro suffix (arch is already in Debian filename)
310+
for f in "$d"/*.deb; do
311+
[ -f "$f" ] || continue
312+
base=$(basename "$f")
313+
base_no_ext="${base%.deb}"
314+
dest="upload/${base_no_ext}_${dist}.deb"
315+
echo " + $base -> $(basename "$dest")"
316+
cp "$f" "$dest"
317+
done
318+
done
319+
320+
echo "Upload dir contents:" && ls -l upload | sed 's/^/ /'
321+
# Single combined checksums file for all assets, deterministic order
322+
if ls upload/*.deb >/dev/null 2>&1; then
323+
(
324+
cd upload
325+
: > SHA256SUMS.txt
326+
# sort file list for stable output
327+
for f in $(ls -1 *.deb | LC_ALL=C sort); do
328+
sha256sum "$f" >> SHA256SUMS.txt
329+
done
330+
echo "Preview of SHA256SUMS.txt:" && sed -n '1,200p' SHA256SUMS.txt | sed 's/^/ /'
331+
)
332+
fi
333+
- name: Create GitHub Release and upload assets
334+
uses: softprops/action-gh-release@v2
335+
with:
336+
files: |
337+
upload/*
338+
env:
339+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

scripts/get-version-from-git

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
#!/bin/bash
22

3-
if [ ! -z "$EMC2_HOME" ]; then
4-
source $EMC2_HOME/scripts/githelper.sh
3+
if [ -n "$EMC2_HOME" ]; then
4+
source "$EMC2_HOME"/scripts/githelper.sh
55
else
6-
source $(git rev-parse --show-toplevel)/scripts/githelper.sh
6+
source "$(git rev-parse --show-toplevel)"/scripts/githelper.sh
77
fi
88

9-
githelper $1
9+
githelper "$1"
1010

1111
if [ "$DEB_COMPONENT" = "scratch" ]; then
12-
# unknown branches get the VERSION file, plus the branch name (with any
13-
# characters that are invalid in debian version numbers replaced with
14-
# dashes '-'), plus the HEAD commit SHA1
15-
echo v$(git show HEAD:VERSION | cut -d ' ' -f 1)~${GIT_BRANCH//[^-.+:~a-z0-9]/-}~$(git show --pretty=format:%h HEAD | head -1)
12+
DESCRIBE=$(git describe --tags --exact-match 2>/dev/null)
13+
if [ -n "$DESCRIBE" ]; then
14+
echo "$DESCRIBE"
15+
else
16+
DESCRIBE=$(git describe --tags 2>/dev/null)
17+
if [ -n "$DESCRIBE" ]; then
18+
echo "$DESCRIBE"
19+
else
20+
BR=$(printf '%s' "$GIT_BRANCH" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^-.+:~a-z0-9]/-/g; s/-{2,}/-/g; s/^-//; s/-$//')
21+
echo "v$(git show HEAD:VERSION | cut -d ' ' -f 1)~${BR:-head}~$(git show --pretty=format:%h HEAD | head -1)"
22+
fi
23+
fi
1624
else
1725
# known branches get the "describe" of the most recent signed git tag,
1826
# or of the most recent unsigned tag if no signed tags are found

scripts/githelper.sh

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,23 @@
1212
# Sets GIT_TAG to the most recent signed tag (this will fall back to the
1313
# most recent tag of any kind if no signed tag is found).
1414
#
15+
# shellcheck shell=bash
1516

1617

1718
function githelper() {
1819
if [ -z "$1" ]; then
19-
GIT_BRANCH=$(git branch | egrep '^\*' | cut -d ' ' -f 2)
20-
if [ "$GIT_BRANCH" = "(no" ]; then
21-
echo "'git branch' says we're not on a branch, pass one in as an argument" > /dev/null 1>&2
22-
return
20+
GIT_BRANCH=$(git symbolic-ref -q --short HEAD 2>/dev/null)
21+
if [ -z "$GIT_BRANCH" ]; then
22+
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
2323
fi
2424
else
2525
GIT_BRANCH="$1"
2626
fi
2727

2828
case $GIT_BRANCH in
2929
master)
30-
GIT_TAG_GLOB="v2.10.*"
30+
MM=$(git show HEAD:VERSION | sed -E 's/^([0-9]+)\.([0-9]+).*/\1.\2/')
31+
GIT_TAG_GLOB="v${MM}.*"
3132
DEB_COMPONENT="master"
3233
;;
3334
# release branches have names matching "number.number", which is awkward to express as a glob
@@ -45,46 +46,53 @@ function githelper() {
4546
;;
4647
*)
4748
GIT_TAG_GLOB="*"
49+
# Disable unused variable warnings on DEB_COMPONENT
50+
# shellcheck disable=SC2034
4851
DEB_COMPONENT="scratch"
4952
;;
5053
esac
5154

5255

5356
# use the gnupg keyring from our git repo to verify signatures on the release tags
54-
export GNUPGHOME=$(git rev-parse --show-toplevel)/gnupg
57+
GNUPGHOME=$(git rev-parse --show-toplevel)/gnupg
58+
export GNUPGHOME
5559

5660
NEWEST_SIGNED_TAG_UTIME=-1
5761
NEWEST_UNSIGNED_TAG_UTIME=-1
5862
for TAG in $(git tag -l "$GIT_TAG_GLOB"); do
59-
if ! git cat-file tag $TAG > /dev/null 2> /dev/null; then
63+
if ! git cat-file tag "$TAG" > /dev/null 2> /dev/null; then
6064
continue
6165
fi
6266

63-
TAG_UTIME=$(git cat-file tag $TAG | grep tagger | awk '{print $(NF-1)-$NF*36}')
67+
TAG_UTIME=$(git cat-file tag "$TAG" | grep tagger | awk '{print $(NF-1)-$NF*36}')
6468

6569
if git tag -v "$TAG" > /dev/null 2> /dev/null; then
6670
# it's a valid signed tag
67-
if [ $TAG_UTIME -gt $NEWEST_SIGNED_TAG_UTIME ]; then
71+
if [ "$TAG_UTIME" -gt "$NEWEST_SIGNED_TAG_UTIME" ]; then
6872
NEWEST_SIGNED_TAG=$TAG
6973
NEWEST_SIGNED_TAG_UTIME=$TAG_UTIME
7074
fi
7175
else
7276
# unsigned tag
73-
if [ $TAG_UTIME -gt $NEWEST_UNSIGNED_TAG_UTIME ]; then
77+
if [ "$TAG_UTIME" -gt "$NEWEST_UNSIGNED_TAG_UTIME" ]; then
7478
NEWEST_UNSIGNED_TAG=$TAG
7579
NEWEST_UNSIGNED_TAG_UTIME=$TAG_UTIME
7680
fi
7781
fi
7882

7983
done
8084

81-
if [ $NEWEST_SIGNED_TAG_UTIME -gt -1 ]; then
85+
if [ "$NEWEST_SIGNED_TAG_UTIME" -gt -1 ]; then
86+
# Disable unused variable warnings on GIT_TAG
87+
# shellcheck disable=SC2034
8288
GIT_TAG="$NEWEST_SIGNED_TAG"
8389
return
8490
fi
8591

86-
if [ $NEWEST_UNSIGNED_TAG_UTIME -gt -1 ]; then
92+
if [ "$NEWEST_UNSIGNED_TAG_UTIME" -gt -1 ]; then
8793
echo "no signed tags found, falling back to unsigned tags" > /dev/null 1>&2
94+
# Disable unused variable warnings on GIT_TAG
95+
# shellcheck disable=SC2034
8896
GIT_TAG="$NEWEST_UNSIGNED_TAG"
8997
return
9098
fi

0 commit comments

Comments
 (0)