11name : Release Publish
22
33on :
4- push :
5- tags :
6- - " *.*.*" # e.g. 2.2.0
4+ pull_request :
5+ types : [closed]
6+ branches : [main]
7+
8+ concurrency :
9+ group : release-publish
10+ cancel-in-progress : false
711
812jobs :
913 release :
14+ name : Create & Publish Release
15+ if : github.event.pull_request.merged == true
1016 runs-on : ubuntu-latest
1117 permissions :
1218 contents : write
1319 packages : write
1420
1521 steps :
16- - uses : actions/checkout@v4
22+ - name : Checkout (full history & tags)
23+ uses : actions/checkout@v4
1724 with :
1825 fetch-depth : 0
1926
20- - name : Derive version from tag
21- id : rel
27+ - name : Fetch all tags
28+ run : |
29+ git fetch --tags --quiet
30+ echo "Existing tags:"
31+ git tag -l | sort -V | tail -n 20 || true
32+
33+ - name : Derive release version (with Hotfix fallback)
34+ id : version
35+ shell : bash
2236 run : |
23- TAG="${GITHUB_REF_NAME}" # e.g. 2.2.0
24- VERSION="${TAG}" # e.g. VERSION=2.2.0
25- echo "version=$VERSION" >> "$GITHUB_OUTPUT"
37+ set -euo pipefail
38+
39+ RAW_VERSION=$(grep -m1 '<version>' pom.xml | sed -E 's/.*<version>([^<]+)<\/version>.*/\1/')
40+ if [[ -z "${RAW_VERSION}" ]]; then
41+ echo "Could not extract version from pom.xml"
42+ exit 1
43+ fi
44+
45+ # Strip -SNAPSHOT suffix if present.
46+ BASE_VERSION="${RAW_VERSION%-SNAPSHOT}"
47+
48+ echo "Base version from pom: ${BASE_VERSION}"
49+
50+ # Determine if base version tag already exists.
51+ if git rev-parse -q --verify "refs/tags/${BASE_VERSION}" >/dev/null; then
52+ echo "Tag ${BASE_VERSION} already exists. Deriving Hotfix version..."
53+ i=1
54+ while git rev-parse -q --verify "refs/tags/${BASE_VERSION}-Hotfix-${i}" >/dev/null; do
55+ i=$((i+1))
56+ done
57+ FINAL_VERSION="${BASE_VERSION}-Hotfix-${i}"
58+ echo "Using hotfix version: ${FINAL_VERSION}"
59+ echo "hotfix=true" >> "$GITHUB_OUTPUT"
60+ echo "hotfix_index=${i}" >> "$GITHUB_OUTPUT"
61+ else
62+ FINAL_VERSION="${BASE_VERSION}"
63+ echo "Using base version: ${FINAL_VERSION}"
64+ echo "hotfix=false" >> "$GITHUB_OUTPUT"
65+ fi
66+
67+ echo "raw_version=${RAW_VERSION}" >> "$GITHUB_OUTPUT"
68+ echo "base_version=${BASE_VERSION}" >> "$GITHUB_OUTPUT"
69+ echo "version=${FINAL_VERSION}" >> "$GITHUB_OUTPUT"
2670
2771 - name : Set up JDK 23 (generate settings.xml)
2872 uses : actions/setup-java@v4
@@ -40,31 +84,92 @@ jobs:
4084 restore-keys : |
4185 maven-${{ runner.os }}-
4286
43- - name : Set release version (remove -SNAPSHOT)
87+ - name : Set release version in pom.xml
4488 run : |
45- mvn -B -s $GITHUB_WORKSPACE/settings.xml versions:set -DnewVersion="${{ steps.rel.outputs.version }}" -DgenerateBackupPoms=false
89+ set -e
90+ mvn -B -s $GITHUB_WORKSPACE/settings.xml versions:set -DnewVersion="${{ steps.version.outputs.version }}" -DgenerateBackupPoms=false
91+ echo "Effective pom version line:"
4692 grep -m1 '<version>' pom.xml
4793
48- - name : Deploy Release
94+ - name : Commit version change (if modified)
95+ run : |
96+ set -e
97+ if ! git diff --quiet; then
98+ git config user.name "github-actions[bot]"
99+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
100+ git add pom.xml
101+ git commit -m "chore(release): set version ${{ steps.version.outputs.version }}"
102+ git push origin HEAD:main
103+ else
104+ echo "No changes to commit."
105+ fi
106+
107+ - name : Build (package)
108+ run : mvn -B -s $GITHUB_WORKSPACE/settings.xml package
109+
110+ - name : Deploy Release to GitHub Packages
49111 env :
50112 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
51113 run : mvn -B -s $GITHUB_WORKSPACE/settings.xml -DskipTests deploy
52114
53- - name : Collect artifacts
115+ - name : Verify built artifacts
54116 run : |
117+ set -e
118+ echo "Contents of target/:"
55119 ls -1 target
56- cp target/*.jar main-artifact.jar || true
120+ # Capture a primary jar (non sources/javadoc) for convenience
121+ MAIN_JAR=$(ls target/*.jar | grep -v '\-sources\.jar$' | grep -v '\-javadoc\.jar$' | head -n1 || true)
122+ if [[ -z "$MAIN_JAR" ]]; then
123+ echo "ERROR: No main artifact jar found."
124+ exit 1
125+ fi
126+ cp "$MAIN_JAR" main-artifact.jar
127+ echo "Selected main artifact: $MAIN_JAR"
128+
129+ - name : Create & Push Git Tag
130+ run : |
131+ set -e
132+ TAG="${{ steps.version.outputs.version }}"
133+ if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
134+ echo "Tag ${TAG} already exists unexpectedly (race condition?)."
135+ exit 1
136+ fi
137+ git config user.name "github-actions[bot]"
138+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
139+ git tag -a "${TAG}" -m "Release ${TAG}"
140+ git push origin "${TAG}"
57141
58142 - name : Create GitHub Release
59143 uses : softprops/action-gh-release@v2
60144 with :
61- tag_name : ${{ github.ref_name }}
62- name : " SingularityLib ${{ steps.rel .outputs.version }}"
145+ tag_name : ${{ steps.version.outputs.version }}
146+ name : " SingularityLib ${{ steps.version .outputs.version }}"
63147 generate_release_notes : true
64148 files : |
65149 target/*-sources.jar
66150 target/*-javadoc.jar
67151 main-artifact.jar
68152
69153 - name : Summary
70- run : echo "Published release ${{ steps.rel.outputs.version }}"
154+ run : |
155+ echo "Published release ${{ steps.version.outputs.version }}"
156+ echo "Hotfix: ${{ steps.version.outputs.hotfix }}"
157+
158+ - name : Bump to next snapshot
159+ if : always()
160+ run : |
161+ set -e
162+ CURRENT="${{ steps.version.outputs.version }}"
163+ # Basic semver increment of patch for next snapshot (ignoring hotfix tags)
164+ CORE="${CURRENT%%-Hotfix-*}"
165+ IFS='.' read -r MA MI PA <<< "$CORE"
166+ NEXT_PATCH=$((PA + 1))
167+ NEXT_VERSION="${MA}.${MI}.${NEXT_PATCH}-SNAPSHOT"
168+ mvn -B versions:set -DnewVersion="${NEXT_VERSION}" -DgenerateBackupPoms=false
169+ if ! git diff --quiet; then
170+ git config user.name "github-actions[bot]"
171+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
172+ git add pom.xml
173+ git commit -m "chore: prepare next development iteration ${NEXT_VERSION}"
174+ git push origin HEAD:main
175+ fi
0 commit comments