Repository navigation
176 lines (166 loc) · 8.66 KB
/
Copy pathrelease-java.yml
File metadata and controls
176 lines (166 loc) · 8.66 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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
name: Release Java (laya-java)
# Tag a commit laya-java-v0.1.0 and push it; this runs the model-free tests, verifies the version
# matches the tag, builds the jars and publishes them to Maven Central.
#
# SET UP ONCE, and only the project owner can do it -- none of this is in the repository:
# 1. Verify the `com.convaiinnovations` namespace at https://central.sonatype.com. Maven Central
# will not accept a groupId whose domain or GitHub org has not been proven.
# 2. Create a Central portal user token and add it as MAVEN_CENTRAL_USERNAME and
# MAVEN_CENTRAL_PASSWORD in the repository secrets.
# 3. Create a PGP key, publish the public half to a keyserver, and add the ASCII-armoured
# private half as LAYA_SIGNING_KEY with its passphrase as LAYA_SIGNING_PASSWORD. Central
# rejects unsigned artifacts.
#
# Until those exist this workflow cannot run, and `build.gradle.kts` is written so that nothing
# else is affected: signing activates only when a key is present, so `./gradlew build` and
# `publishToMavenLocal` work for anyone.
on:
push:
tags: ["laya-java-v*"]
workflow_dispatch:
#
# SUPPLY CHAIN: `laya-java/gradle/wrapper/gradle-wrapper.jar` is a binary that executes at build
# time, which makes it the one file here a reviewer cannot read. Every job below that runs
# `./gradlew` validates it against Gradle's published checksums first -- not just the first job,
# because each job checks out the tree again and runs the jar again, so validating one of them
# leaves the others executing an unverified binary. The jar in the tree today is the genuine
# 8.10.2 wrapper (sha256 2db75c40...8046, verified locally against Gradle's published value).
# The distribution the wrapper then downloads is pinned by `distributionSha256Sum` in
# `gradle-wrapper.properties`.
permissions:
contents: read
jobs:
build:
name: Build & verify artifacts
runs-on: ubuntu-latest
timeout-minutes: 25
defaults:
run:
working-directory: laya-java
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
# Validate the wrapper jar BEFORE anything can execute it. See this file's
# header for why every job that runs ./gradlew needs this, not just one.
- uses: gradle/actions/wrapper-validation@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: temurin
java-version: "17"
cache: gradle
- name: Version matches tag
if: startsWith(github.ref, 'refs/tags/laya-java-v')
run: |
tag="${GITHUB_REF_NAME#laya-java-v}"
echo "tag=$tag"
# The build takes its version from a Gradle property, so the tag IS the version and
# there is no second copy to drift from it.
echo "layaJavaVersion=$tag" >> gradle.properties
grep layaJavaVersion gradle.properties
# The model-free suite only: a release runner has no checkpoint, so the parity factories
# abort. They are the Java lane's job, on every commit, and a release is cut from a commit
# that lane already covered.
- name: Model-free tests
run: ./gradlew --no-daemon test
# 1007 of the 1025 registered tests run without a checkpoint. This floor has been raised
# as the model-free suite grew -- 440 left 191 of slack, 625 left 60 -- because a floor
# that does not bind is not a gate: under 625 the whole confidence-gate family of 26
# tests could have vanished from this lane with the gate still green.
#
# These lines sit ABOVE `run:`, not inside it. A `>` block folds to one line and `#` is
# not a comment inside a YAML scalar, so a comment written in there reaches the shell and
# silences the rest of the folded line: it took `--min-tests 625 --allow-aborted` off this
# command, dropping the floor to the script's default of 1 instead of raising it to 625,
# and losing `--allow-aborted` on a runner whose parity factories abort. A `|` block keeps
# the newlines so the `#` really is a shell comment there, which is why the broken and the
# correct form look identical in a diff. `scripts/check_workflow_folding.py` now fails the
# build on it rather than relying on a reader spotting it.
- name: The suite was not vacuous
run: >
python3 scripts/check_test_results.py laya-java/build/test-results/test
--min-tests 1007 --allow-aborted
- name: Build the jars
run: ./gradlew --no-daemon build -x test
- name: Install to the local repository, and show what a consumer would get
run: |
./gradlew --no-daemon publishToMavenLocal
find ~/.m2/repository/com/convaiinnovations -type f | sort
cat ~/.m2/repository/com/convaiinnovations/laya-java/*/laya-java-*.pom
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: laya-java-artifacts
path: |
laya-java/laya-java/build/libs/*.jar
laya-java/laya-java-client/build/libs/*.jar
central:
name: Publish to Maven Central
needs: build
runs-on: ubuntu-latest
timeout-minutes: 25
# A manual gate, as the npm lane has: the one irreversible step in the pipeline, since a
# version published to Central can never be replaced.
environment: maven-central
defaults:
run:
working-directory: laya-java
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
# Validate the wrapper jar BEFORE anything can execute it. See this file's
# header for why every job that runs ./gradlew needs this, not just one.
- uses: gradle/actions/wrapper-validation@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: temurin
java-version: "17"
cache: gradle
- name: Refuse to publish anything but a tag
run: |
# Central is append-only: a version published once can never be replaced. On a
# workflow_dispatch from a branch, GITHUB_REF_NAME is the BRANCH, so the version became
# the branch name -- `:main` -- and the snapshot guard did not match it. The build job's
# version check is guarded by this same condition and was simply skipped, so the two
# jobs disagreed about what was being released.
case "$GITHUB_REF" in
refs/tags/laya-java-v*) : ;;
*)
echo "::error::refusing to publish from $GITHUB_REF; tag the release as" \
"laya-java-vX.Y.Z and run this on the tag"
exit 1
;;
esac
- name: Version from the tag
run: |
tag="${GITHUB_REF_NAME#laya-java-v}"
echo "layaJavaVersion=$tag" >> gradle.properties
- name: Refuse to publish a snapshot to Central
run: |
tag="${GITHUB_REF_NAME#laya-java-v}"
case "$tag" in
*-SNAPSHOT) echo "::error::$tag is a snapshot; Central takes releases only"; exit 1 ;;
esac
- name: Publish
env:
LAYA_SIGNING_KEY: ${{ secrets.LAYA_SIGNING_KEY }}
LAYA_SIGNING_PASSWORD: ${{ secrets.LAYA_SIGNING_PASSWORD }}
MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
run: |
# All four, not two. Without the passphrase the build calls useInMemoryPgpKeys(key,
# null) and uploads UNSIGNED artifacts, which Central rejects only after the upload --
# a much worse place to find out.
#
# A loop rather than four `test -n` lines. Written out, the four were 111 to 161 columns
# and no longer read as the parallel checks they are, and each one exited on the FIRST
# thing it found -- so a release missing two secrets cost two tagged runs to discover.
# This names all of them at once.
missing=""
for secret in LAYA_SIGNING_KEY LAYA_SIGNING_PASSWORD \
MAVEN_CENTRAL_USERNAME MAVEN_CENTRAL_PASSWORD; do
[ -n "${!secret:-}" ] || missing="$missing $secret"
done
if [ -n "$missing" ]; then
echo "::error::unset secret(s):$missing -- see this workflow's header for how each" \
"one is produced. Note the signing passphrase in particular: without it the" \
"bundle is built UNSIGNED and Central rejects it only after the upload."
exit 1
fi
./gradlew --no-daemon publishAllPublicationsToCentralRepository