1
- name : Hyperion - Java Client Publish Snapshots
1
+ name : Hyperion Java Client - CI/CD
2
+
3
+ # Required GitHub Secrets:
4
+ # - GITHUB_TOKEN: Automatically provided by GitHub for GitHub Packages
5
+ # - OSSRH_USERNAME: Sonatype OSSRH username for Maven Central
6
+ # - OSSRH_PASSWORD: Sonatype OSSRH password for Maven Central
7
+ # - GPG_KEY: Base64 encoded GPG private key (gpg --armor --export-secret-keys KEY_ID | base64 -w 0)
8
+ # - GPG_PASSPHRASE: GPG key passphrase
2
9
3
10
permissions :
4
11
contents : read
@@ -10,115 +17,290 @@ on:
10
17
- ' hyperion/java-client/**'
11
18
- ' hyperion/app/protos/**'
12
19
pull_request :
13
- branches : [main]
20
+ branches : [main, develop ]
14
21
paths :
15
22
- ' hyperion/java-client/**'
16
23
- ' hyperion/app/protos/**'
17
24
workflow_dispatch :
18
25
19
26
jobs :
20
- validate :
21
- name : Validate and Test
27
+ build :
28
+ name : Build & Test
22
29
runs-on : ubuntu-latest
30
+ outputs :
31
+ should-publish : ${{ steps.check.outputs.should-publish }}
32
+ version : ${{ steps.version.outputs.version }}
33
+ branch-name : ${{ steps.version.outputs.branch-name }}
34
+ is-snapshot : ${{ steps.version.outputs.is-snapshot }}
35
+
23
36
steps :
24
- - name : Checkout repository
37
+ - name : Checkout
25
38
uses : actions/checkout@v4
26
39
27
- - name : Set up JDK 17
40
+ - name : Setup JDK 17
28
41
uses : actions/setup-java@v4
29
42
with :
30
43
java-version : ' 17'
31
44
distribution : ' temurin'
32
45
33
- - name : Setup Gradle
34
- uses : gradle/ actions/setup-gradle @v4
46
+ - name : Cache Maven
47
+ uses : actions/cache @v4
35
48
with :
36
- gradle-version : wrapper
49
+ path : ~/.m2
50
+ key : ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
37
51
38
- - name : Build and test
52
+ - name : Determine version and publishing strategy
53
+ id : version
39
54
working-directory : hyperion/java-client
40
- run : ./gradlew build --no-daemon --parallel
41
-
42
- - name : Upload build artifacts
43
- uses : actions/upload-artifact@v4
44
- if : always()
45
- with :
46
- name : build-artifacts
47
- path : |
48
- hyperion/java-client/build/libs/
49
- hyperion/java-client/build/reports/
50
- retention-days : 7
55
+ run : |
56
+ # Get base version from pom.xml (always 1.1.0)
57
+ BASE_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
58
+ echo "📋 Base version from pom.xml: $BASE_VERSION"
59
+
60
+ # Get branch name (handle PR refs properly)
61
+ if [[ "${{ github.ref }}" == refs/pull/* ]]; then
62
+ BRANCH_NAME="${{ github.head_ref }}"
63
+ else
64
+ BRANCH_NAME="${{ github.ref_name }}"
65
+ fi
66
+ echo "🌿 Branch: $BRANCH_NAME"
67
+
68
+ # Determine version strategy based on branch
69
+ if [[ "$BRANCH_NAME" == "main" ]] || [[ "$BRANCH_NAME" == "develop" ]]; then
70
+ # Stable branches: use base version for releases
71
+ FINAL_VERSION="$BASE_VERSION"
72
+ IS_SNAPSHOT="false"
73
+ echo "🎯 Stable branch detected: will publish release version $FINAL_VERSION"
74
+ else
75
+ # Feature branches: use dynamic branch-based snapshots
76
+ # Use EXACT same sanitization as local Maven build
77
+ SANITIZED_BRANCH=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9]/-/g' | tr '[:upper:]' '[:lower:]')
78
+ FINAL_VERSION="${BASE_VERSION}-${SANITIZED_BRANCH}-SNAPSHOT"
79
+ IS_SNAPSHOT="true"
80
+ echo "🔨 Feature branch detected: will publish snapshot $FINAL_VERSION"
81
+ fi
82
+
83
+ echo "version=$FINAL_VERSION" >> $GITHUB_OUTPUT
84
+ echo "branch-name=$BRANCH_NAME" >> $GITHUB_OUTPUT
85
+ echo "is-snapshot=$IS_SNAPSHOT" >> $GITHUB_OUTPUT
86
+ echo "base-version=$BASE_VERSION" >> $GITHUB_OUTPUT
87
+
88
+ - name : Check publishing rules
89
+ id : check
90
+ run : |
91
+ BRANCH_NAME="${{ steps.version.outputs.branch-name }}"
92
+ EVENT="${{ github.event_name }}"
93
+
94
+ # Publish on push events (feature branches → snapshots, stable branches → releases)
95
+ if [[ "$EVENT" == "push" ]]; then
96
+ echo "should-publish=true" >> $GITHUB_OUTPUT
97
+ if [[ "${{ steps.version.outputs.is-snapshot }}" == "true" ]]; then
98
+ echo "✅ Will publish feature snapshot to GitHub Packages"
99
+ else
100
+ echo "✅ Will publish release to GitHub Packages + Maven Central"
101
+ fi
102
+ else
103
+ echo "should-publish=false" >> $GITHUB_OUTPUT
104
+ echo "ℹ️ PR: Build only, no publishing"
105
+ fi
106
+
107
+ - name : Build & Test
108
+ working-directory : hyperion/java-client
109
+ run : |
110
+ if [[ "${{ steps.version.outputs.is-snapshot }}" == "true" ]]; then
111
+ echo "🔨 Building feature branch with local dynamic versioning"
112
+ mvn clean compile test package --no-transfer-progress
113
+ else
114
+ echo "🎯 Building stable release with base version"
115
+ mvn clean compile test package -DskipLocalVersioning=true --no-transfer-progress
116
+ fi
51
117
52
- publish-snapshot :
53
- name : Publish Snapshot to GitHub Packages
54
- needs : validate
118
+ publish-snapshots :
119
+ name : Publish Snapshots
120
+ needs : build
55
121
runs-on : ubuntu-latest
56
-
122
+ if : needs.build.outputs.should-publish == 'true' && needs.build.outputs.is-snapshot == 'true'
123
+
57
124
steps :
58
- - name : Checkout repository
125
+ - name : Checkout
59
126
uses : actions/checkout@v4
60
127
61
- - name : Set up JDK 17
128
+ - name : Setup JDK 17
62
129
uses : actions/setup-java@v4
63
130
with :
64
131
java-version : ' 17'
65
132
distribution : ' temurin'
66
133
67
- - name : Setup Gradle
68
- uses : gradle/ actions/setup-gradle @v4
134
+ - name : Cache Maven
135
+ uses : actions/cache @v4
69
136
with :
70
- gradle-version : wrapper
137
+ path : ~/.m2
138
+ key : ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
139
+
140
+ - name : Configure Maven for GitHub Packages
141
+ run : |
142
+ mkdir -p ~/.m2
143
+ cat > ~/.m2/settings.xml << 'EOF'
144
+ <settings>
145
+ <servers>
146
+ <server>
147
+ <id>github</id>
148
+ <username>${{ github.actor }}</username>
149
+ <password>${{ secrets.GITHUB_TOKEN }}</password>
150
+ </server>
151
+ </servers>
152
+ </settings>
153
+ EOF
71
154
72
- - name : Set snapshot version
155
+ - name : Publish Snapshot to GitHub Packages
73
156
working-directory : hyperion/java-client
74
157
run : |
75
- # Extract current version and build meaningful snapshot version
76
- CURRENT_VERSION=$(grep "^version = " build.gradle | sed "s/version = '\(.*\)'/\1/")
77
- DATE=$(date -u +"%Y%m%d")
78
- COMMIT_SHA=${GITHUB_SHA:0:7}
79
-
80
- # Get meaningful branch name (handle PR refs properly)
81
- if [[ "$GITHUB_REF" == refs/pull/* ]]; then
82
- # For PRs, use the head branch name from the event
83
- BRANCH_NAME="${GITHUB_HEAD_REF}"
84
- else
85
- # For regular pushes, extract from ref
86
- BRANCH_NAME="${GITHUB_REF#refs/heads/}"
87
- fi
158
+ echo "📦 Publishing snapshot ${{ needs.build.outputs.version }} to GitHub Packages"
159
+ echo "🔨 Setting version to ${{ needs.build.outputs.version }} and deploying"
88
160
89
- # Sanitize branch name for version compatibility
90
- BRANCH_SANITIZED=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9._-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')
161
+ # Set the version to our calculated snapshot version
162
+ mvn versions:set -DnewVersion="${{ needs.build.outputs.version }}" -DgenerateBackupPoms=false
91
163
92
- # Remove existing -SNAPSHOT suffix if present
93
- if [[ "$CURRENT_VERSION" == *"-SNAPSHOT" ]]; then
94
- BASE_VERSION=${CURRENT_VERSION%-SNAPSHOT}
95
- else
96
- BASE_VERSION=$CURRENT_VERSION
97
- fi
164
+ # Deploy to GitHub Packages
165
+ mvn deploy -Pgithub --no-transfer-progress
166
+
167
+ publish-releases :
168
+ name : Publish Releases
169
+ needs : build
170
+ runs-on : ubuntu-latest
171
+ if : needs.build.outputs.should-publish == 'true' && needs.build.outputs.is-snapshot == 'false'
172
+
173
+ strategy :
174
+ fail-fast : false
175
+ matrix :
176
+ target :
177
+ - name : " Maven Central"
178
+ profile : " "
179
+ - name : " GitHub Packages"
180
+ profile : " -Pgithub"
181
+
182
+ steps :
183
+ - name : Checkout
184
+ uses : actions/checkout@v4
185
+
186
+ - name : Setup JDK 17
187
+ uses : actions/setup-java@v4
188
+ with :
189
+ java-version : ' 17'
190
+ distribution : ' temurin'
98
191
99
- # Build semantic snapshot version: base-branch-date-commit-SNAPSHOT
100
- NEW_VERSION="${BASE_VERSION}-${BRANCH_SANITIZED}-${DATE}-${COMMIT_SHA}-SNAPSHOT"
192
+ - name : Cache Maven
193
+ uses : actions/cache@v4
194
+ with :
195
+ path : ~/.m2
196
+ key : ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
101
197
102
- echo "NEW_VERSION=${NEW_VERSION}" >> $GITHUB_ENV
103
- echo "📦 Publishing version: ${NEW_VERSION}"
104
- echo "🌿 Branch: ${BRANCH_NAME}"
105
- echo "📅 Date: ${DATE}"
106
- echo "🔗 Commit: ${COMMIT_SHA}"
198
+ - name : Configure Maven
199
+ run : |
200
+ mkdir -p ~/.m2
201
+ cat > ~/.m2/settings.xml << 'EOF'
202
+ <settings>
203
+ <servers>
204
+ <server>
205
+ <id>central</id>
206
+ <username>${{ secrets.OSSRH_USERNAME }}</username>
207
+ <password>${{ secrets.OSSRH_PASSWORD }}</password>
208
+ </server>
209
+ <server>
210
+ <id>github</id>
211
+ <username>${{ github.actor }}</username>
212
+ <password>${{ secrets.GITHUB_TOKEN }}</password>
213
+ </server>
214
+ </servers>
215
+ </settings>
216
+ EOF
217
+
218
+ - name : Import GPG key
219
+ if : matrix.target.profile == ''
220
+ run : |
221
+ # Import GPG private key for Maven Central signing
222
+ echo "${{ secrets.GPG_KEY }}" | base64 -d | gpg --batch --import
107
223
108
- # Update version in build.gradle
109
- sed -i "s/version = '.*'/version = '${NEW_VERSION}'/" build.gradle
224
+ # Configure GPG for non-interactive use
225
+ mkdir -p ~/.gnupg
226
+ echo "use-agent" >> ~/.gnupg/gpg.conf
227
+ echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf
228
+ echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf
110
229
111
- - name : Publish to GitHub Packages
230
+ # Get the key ID automatically
231
+ GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format=long | grep -E "sec\s+[^/]+/([A-F0-9]{16})" | head -n1 | sed 's/.*\/\([A-F0-9]\{16\}\).*/\1/')
232
+ if [[ -z "$GPG_KEY_ID" ]]; then
233
+ echo "❌ Failed to detect GPG key ID"
234
+ echo "Available keys:"
235
+ gpg --list-secret-keys --keyid-format=long
236
+ exit 1
237
+ fi
238
+ echo "🔑 Detected GPG Key ID: $GPG_KEY_ID"
239
+ echo "GPG_KEY_ID=$GPG_KEY_ID" >> $GITHUB_ENV
240
+
241
+ - name : Publish Release to ${{ matrix.target.name }}
112
242
working-directory : hyperion/java-client
113
- env :
114
- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
115
- GITHUB_ACTOR : ${{ github.actor }}
116
- run : ./gradlew publishToGitHubPackages --no-daemon
117
-
118
- - name : Create release summary
119
243
run : |
120
- echo "## 📦 Package Published" >> $GITHUB_STEP_SUMMARY
244
+ echo "📦 Publishing release ${{ needs.build.outputs.version }} to ${{ matrix.target.name }}"
245
+
246
+ if [[ "${{ matrix.target.profile }}" == "" ]]; then
247
+ echo "🔐 Maven Central: Enabling GPG signing"
248
+ mvn deploy -Prelease \
249
+ -Dgpg.keyname="${GPG_KEY_ID}" \
250
+ -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" \
251
+ --no-transfer-progress
252
+ else
253
+ echo "📦 GitHub Packages: Skipping GPG signing"
254
+ mvn deploy ${{ matrix.target.profile }} --no-transfer-progress
255
+ fi
256
+ continue-on-error : ${{ matrix.target.profile == '-Pgithub' }}
257
+
258
+ summary :
259
+ name : Summary
260
+ needs : [build, publish-snapshots, publish-releases]
261
+ runs-on : ubuntu-latest
262
+ if : always()
263
+
264
+ steps :
265
+ - name : Create Summary
266
+ run : |
267
+ echo "## 🚀 Hyperion Java Client CI/CD" >> $GITHUB_STEP_SUMMARY
121
268
echo "" >> $GITHUB_STEP_SUMMARY
122
- echo "**Package:** \`de.tum.cit.aet.edutelligence:hyperion:${{ env.NEW_VERSION }}\`" >> $GITHUB_STEP_SUMMARY
269
+ echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
270
+ echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
271
+ echo "| **Version** | \`${{ needs.build.outputs.version }}\` |" >> $GITHUB_STEP_SUMMARY
272
+ echo "| **Branch** | \`${{ needs.build.outputs.branch-name }}\` |" >> $GITHUB_STEP_SUMMARY
273
+ echo "| **Type** | ${{ needs.build.outputs.is-snapshot == 'true' && '📦 Snapshot' || '🎯 Release' }} |" >> $GITHUB_STEP_SUMMARY
274
+ echo "| **Event** | \`${{ github.event_name }}\` |" >> $GITHUB_STEP_SUMMARY
275
+ echo "| **Published** | ${{ needs.build.outputs.should-publish == 'true' && '✅ Yes' || '❌ No' }} |" >> $GITHUB_STEP_SUMMARY
123
276
echo "" >> $GITHUB_STEP_SUMMARY
124
- echo "**Repository:** [GitHub Packages](https://github.com/ls1intum/edutelligence/packages)" >> $GITHUB_STEP_SUMMARY
277
+
278
+ if [[ "${{ needs.build.outputs.should-publish }}" == "true" ]]; then
279
+ echo "### 📦 Usage" >> $GITHUB_STEP_SUMMARY
280
+ echo '```xml' >> $GITHUB_STEP_SUMMARY
281
+ echo '<dependency>' >> $GITHUB_STEP_SUMMARY
282
+ echo ' <groupId>de.tum.cit.aet</groupId>' >> $GITHUB_STEP_SUMMARY
283
+ echo ' <artifactId>hyperion</artifactId>' >> $GITHUB_STEP_SUMMARY
284
+ echo " <version>${{ needs.build.outputs.version }}</version>" >> $GITHUB_STEP_SUMMARY
285
+ echo '</dependency>' >> $GITHUB_STEP_SUMMARY
286
+ echo '```' >> $GITHUB_STEP_SUMMARY
287
+
288
+ if [[ "${{ needs.build.outputs.is-snapshot }}" == "true" ]]; then
289
+ echo "" >> $GITHUB_STEP_SUMMARY
290
+ echo "### 🔨 Feature Branch Snapshot" >> $GITHUB_STEP_SUMMARY
291
+ echo "- Published to **GitHub Packages only**" >> $GITHUB_STEP_SUMMARY
292
+ echo "- Uses dynamic branch-based versioning: \`${{ needs.build.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
293
+ echo "- Perfect for testing in Artemis feature branches" >> $GITHUB_STEP_SUMMARY
294
+ echo "- No GPG signing required" >> $GITHUB_STEP_SUMMARY
295
+ else
296
+ echo "" >> $GITHUB_STEP_SUMMARY
297
+ echo "### 🎯 Stable Release" >> $GITHUB_STEP_SUMMARY
298
+ echo "- Published to **GitHub Packages + Maven Central**" >> $GITHUB_STEP_SUMMARY
299
+ echo "- Uses base version from pom.xml: \`${{ needs.build.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
300
+ echo "- **GPG signed** for Maven Central" >> $GITHUB_STEP_SUMMARY
301
+ echo "- Ready for production use" >> $GITHUB_STEP_SUMMARY
302
+ fi
303
+ else
304
+ echo "### ℹ️ Pull Request - Build Only" >> $GITHUB_STEP_SUMMARY
305
+ echo "Artifacts are built and tested but not published." >> $GITHUB_STEP_SUMMARY
306
+ fi
0 commit comments