1+ .release-workflow :
2+ rules :
3+ # Only fire on SemVer release tags, e.g. v2.0.0 or v2.0.0-alpha.1.
4+ # NOTE: intentionally has no trailing `when: never` so it can be safely
5+ # `!reference`d into the build jobs' rule lists without short-circuiting them.
6+ - if : $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+/
7+ when : always
8+
9+ # ###############
10+ # Android APK #
11+ # ###############
12+
13+ release-android-apk :
14+ extends : .release-workflow
15+ stage : publish
16+ image : alpine:latest
17+ needs :
18+ - job : app-android-apk
19+ artifacts : true
20+ before_script :
21+ - apk add --no-cache curl
22+ script :
23+ - |
24+ APK_PACKAGE_URL="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/polycentric-android/${CI_COMMIT_TAG}/polycentric-${CI_COMMIT_TAG}.apk"
25+ echo "Uploading APK to ${APK_PACKAGE_URL}"
26+ curl -fsSL --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file apps/polycentric/polycentric.apk "$APK_PACKAGE_URL"
27+ echo "APK_PACKAGE_URL=${APK_PACKAGE_URL}" > apk.env
28+ artifacts :
29+ reports :
30+ dotenv : apk.env
31+
32+ # ###################
33+ # Container images #
34+ # ###################
35+
36+ .release-tag-image :
37+ extends : .release-workflow
38+ stage : release
39+ image :
40+ name : gcr.io/go-containerregistry/crane:debug
41+ entrypoint : ['']
42+ script :
43+ - crane auth login $CI_REGISTRY -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD
44+ - crane tag $CI_REGISTRY_IMAGE/$IMAGE:$CI_COMMIT_SHA $CI_COMMIT_TAG
45+
46+ release-tag-app-image :
47+ extends : .release-tag-image
48+ variables :
49+ IMAGE : app
50+ needs :
51+ - job : app-web-image
52+ artifacts : false
53+
54+ release-tag-server-image :
55+ extends : .release-tag-image
56+ variables :
57+ IMAGE : server
58+ needs :
59+ - job : server-image
60+ artifacts : false
61+
62+ # #########################
63+ # JS SDKs + React Native #
64+ # #########################
65+
66+ release-publish-npm :
67+ extends : .release-workflow
68+ stage : publish
69+ image : node:24-slim
70+ needs :
71+ - job : rs-core-uniffi-web-build
72+ artifacts : true
73+ - job : js-sdks-build
74+ artifacts : true
75+ - job : rn-sdk-build
76+ artifacts : true
77+ before_script :
78+ - apt-get update && apt-get install -y --no-install-recommends git
79+ - npm install -g pnpm@10.19.0
80+ - pnpm config set @polycentric:registry https://${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/
81+ - echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}" >> ~/.npmrc
82+ - echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> ~/.npmrc
83+ - pnpm install --frozen-lockfile
84+ script :
85+ - VERSION="${CI_COMMIT_TAG#v}"
86+ - echo "Publishing @polycentric packages at version ${VERSION}"
87+ # Keep prereleases (e.g. 2.0.0-alpha.1) off the `latest` dist-tag.
88+ - |
89+ DIST_TAG=latest
90+ if echo "$VERSION" | grep -q '-'; then
91+ DIST_TAG=$(echo "$VERSION" | sed -E 's/.*-([a-zA-Z]+).*/\1/')
92+ [ "$DIST_TAG" = "$VERSION" ] && DIST_TAG=next
93+ fi
94+ echo "Using npm dist-tag: ${DIST_TAG}"
95+ # Bump every @polycentric package to the release version.
96+ - pnpm -r --filter "@polycentric/*" exec npm version "${VERSION}" --no-git-tag-version --allow-same-version
97+ # Publish to the GitLab registry and to public npm. pnpm topologically
98+ # orders the packages and rewrites workspace:* -> ${VERSION} on publish.
99+ - |
100+ FILTERS="--filter @polycentric/rs-core-uniffi-web --filter @polycentric/js-storage-sqlite --filter @polycentric/js-core --filter @polycentric/js-browser --filter @polycentric/js-node --filter @polycentric/react-native"
101+
102+ echo "Publishing to the GitLab package registry"
103+ pnpm config set @polycentric:registry "https://${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/"
104+ pnpm $FILTERS -r publish --no-git-checks --access public --tag "$DIST_TAG"
105+
106+ if [ -n "$NPM_TOKEN" ]; then
107+ echo "Publishing to public npm (registry.npmjs.org)"
108+ pnpm config set @polycentric:registry "https://registry.npmjs.org/"
109+ pnpm $FILTERS -r publish --no-git-checks --access public --tag "$DIST_TAG"
110+ else
111+ echo "NPM_TOKEN is not set; skipping public npm publish" >&2
112+ fi
113+
114+ # ################
115+ # rs-core crate #
116+ # ################
117+
118+ release-publish-rs-core :
119+ extends : .release-workflow
120+ stage : publish
121+ image : $RUST_IMAGE
122+ variables :
123+ GIT_DEPTH : ' 1'
124+ script :
125+ - VERSION="${CI_COMMIT_TAG#v}"
126+ # Bump the crate versions and give the path dependency a version so the
127+ # crates package cleanly.
128+ - sed -i "s/^version = \".*\"/version = \"${VERSION}\"/" packages/rs-common/Cargo.toml packages/rs-core/Cargo.toml
129+ - sed -i "s#path = \"../rs-common\" }#path = \"../rs-common\", version = \"${VERSION}\" }#" packages/rs-core/Cargo.toml
130+ - mkdir -p target/package
131+ - cargo package -p polycentric-common --no-verify --allow-dirty || true
132+ - cargo package -p polycentric-core --no-verify --allow-dirty || true
133+ # Fall back to a source tarball if cargo could not package the crate.
134+ - |
135+ if ! ls target/package/*.crate >/dev/null 2>&1; then
136+ echo "cargo package produced no .crate; falling back to a source tarball" >&2
137+ tar czf "target/package/polycentric-core-${VERSION}.crate" packages/rs-core packages/rs-common
138+ fi
139+ - |
140+ BASE_URL="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/polycentric-rs-core/${VERSION}"
141+ for crate in target/package/*.crate; do
142+ fname=$(basename "$crate")
143+ echo "Uploading ${fname}"
144+ curl -fsSL --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file "$crate" "${BASE_URL}/${fname}"
145+ done
146+ echo "RS_CORE_PACKAGE_URL=${BASE_URL}/polycentric-core-${VERSION}.crate" > rs-core.env
147+ artifacts :
148+ reports :
149+ dotenv : rs-core.env
150+
151+ # ############
152+ # Changelog #
153+ # ############
154+
155+ release-changelog :
156+ extends : .release-workflow
157+ stage : publish
158+ image : alpine:latest
159+ before_script :
160+ - apk add --no-cache curl jq
161+ script :
162+ - ' curl -H "PRIVATE-TOKEN: $CI_API_TOKEN" "$CI_API_V4_URL/projects/$CI_PROJECT_ID/repository/changelog?version=$CI_COMMIT_TAG" | jq -r .notes > release_notes.md'
163+ - cat release_notes.md
164+ artifacts :
165+ paths :
166+ - release_notes.md
167+ expire_in : 1 week
168+
169+ # ############################
170+ # Create the GitLab Release #
171+ # ############################
172+
173+ release :
174+ extends : .release-workflow
175+ stage : release
176+ image : registry.gitlab.com/gitlab-org/release-cli:latest
177+ script :
178+ - echo "Creating release"
179+ needs :
180+ - job : release-changelog
181+ artifacts : true
182+ - job : release-android-apk
183+ artifacts : true
184+ - job : release-publish-rs-core
185+ artifacts : false
186+ - job : release-publish-npm
187+ artifacts : false
188+ - job : release-tag-app-image
189+ artifacts : false
190+ - job : release-tag-server-image
191+ artifacts : false
192+ release :
193+ tag_name : $CI_COMMIT_TAG
194+ name : ' $CI_COMMIT_TAG'
195+ ref : ' $CI_COMMIT_SHA'
196+ description : release_notes.md
197+ assets :
198+ links :
199+ - name : ' Android APK ($CI_COMMIT_TAG)'
200+ url : ' $APK_PACKAGE_URL'
201+ link_type : package
0 commit comments