Skip to content

Release

Release #130

Workflow file for this run

# Copyright 2026 Goldman Sachs
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: Release
env:
CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }}
CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }}
CI_GPG_PASSPHRASE: ${{ secrets.CI_GPG_PASSPHRASE }}
DOCKER_USERNAME: finos
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
on:
workflow_dispatch:
inputs:
releaseVersion:
description: "New release version"
required: true
jobs:
build:
name: Prepare Release Artifacts
runs-on: ubuntu-latest-16-cores
outputs:
testMatrix: ${{ steps.testMatrix.outputs.testMatrix }}
steps:
- name: Checkout repo
uses: actions/checkout@v6
with:
token: ${{ secrets.FINOS_GITHUB_TOKEN }}
- name: Configure git
run: |
git config --global user.email "37706051+finos-admin@users.noreply.github.com"
git config --global user.name "FINOS Administrator"
- name: Set up Maven Central
uses: actions/setup-java@v5
with:
distribution: "zulu"
java-version: "11"
server-id: central
server-username: CI_DEPLOY_USERNAME
server-password: CI_DEPLOY_PASSWORD
gpg-private-key: ${{ secrets.CI_GPG_PRIVATE_KEY }}
gpg-passphrase: CI_GPG_PASSPHRASE
- name: Collect Workflow Telemetry
uses: runforesight/workflow-telemetry-action@v1
with:
theme: dark
- name: Compute next development version
run: |
releaseVersion=${{ github.event.inputs.releaseVersion }}
n=${releaseVersion//[!0-9]/ }
a=(${n//\./ })
nextPatch=$((${a[2]} + 1))
developmentVersion="${a[0]}.${a[1]}.${nextPatch}-SNAPSHOT"
echo "DEVELOPMENT_VERSION=${developmentVersion}" >> $GITHUB_ENV
- name: Cache Maven dependencies
uses: actions/cache@v5
env:
cache-name: cache-mvn-deps
with:
path: ~/.m2/repository
# Keep the restore-keys list narrow on purpose.
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
- name: Download deps and plugins
run: mvn de.qaware.maven:go-offline-maven-plugin:resolve-dependencies
- name: Prepare release
run: mvn -B -e release:prepare -Darguments='-B -e' -DpreparationGoals=clean -DreleaseVersion=${{ github.event.inputs.releaseVersion }} -DdevelopmentVersion=${{ env.DEVELOPMENT_VERSION }} -P release
- name: Checkout Release Tag
uses: actions/checkout@v6
with:
ref: ${{ github.event.repository.name }}-${{ github.event.inputs.releaseVersion }}
token: ${{ secrets.FINOS_GITHUB_TOKEN }}
fetch-depth: 1
persist-credentials: true
- name: Purge stale legend-engine artifacts from local Maven repo
run: rm -rf ~/.m2/repository/org/finos/legend/engine
- name: Build Release Tag
run: mvn -B -e -T5 -DskipTests -Dorg.slf4j.simpleLogger.showThreadName=true install -P release,docker,pct-cloud-test
env:
MAVEN_OPTS: -Xmx36g
- name: Upload build output
uses: actions/upload-artifact@v7
with:
name: build-output
# Upload per-module target/ directories produced by the release-tag
# build. Test jobs re-checkout the release tag from git.
path: |
~/**/target/
!~/**/target/*.jar
retention-days: 1
overwrite: true
include-hidden-files: true
if-no-files-found: error
- name: Upload m2 repository
uses: actions/upload-artifact@v7
with:
name: m2-repo
path: ~/.m2/repository/org/finos/legend/engine/
retention-days: 1
overwrite: true
if-no-files-found: error
- name: Purge engine artifacts before cache save
# actions/cache's post-job save snapshots ~/.m2/repository at the
# end of the job. We don't want the just-built engine jars in that
# snapshot.
if: always()
run: rm -rf ~/.m2/repository/org/finos/legend/engine
- name: Set Test Matrix
id: testMatrix
run: echo "testMatrix=$(jq -c . < .github/workflows/resources/modulesToTest.json)" >> $GITHUB_OUTPUT
- name: Upload CI Event
if: always()
uses: actions/upload-artifact@v7
with:
name: event-file
path: ${{ github.event_path }}
test:
name: Run Unit Tests
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Checkout Release Tag
uses: actions/checkout@v6
with:
ref: ${{ github.event.repository.name }}-${{ github.event.inputs.releaseVersion }}
fetch-depth: 1
persist-credentials: false
- name: Before Test
uses: ./.github/workflows/actions/before-test
- name: Excluded Modules
id: modulesToExclude
run: echo EXCLUSION_MODULES=`jq -c '.include | map(.modules) | flatten | map("!org.finos.legend.engine:" + .) | join(",")' ./.github/workflows/resources/modulesToTest.json` >> $GITHUB_OUTPUT
- name: Test
env:
MAVEN_OPTS: "-Xmx1g"
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
mvn -B -e surefire:test -pl ${{ steps.modulesToExclude.outputs.EXCLUSION_MODULES }} -P release,docker,pct-cloud-test -T2 -DargLine="-Xmx6g" -Dsurefire.reports.directory=${GITHUB_WORKSPACE}/surefire-reports-aggregate
- name: Upload Test Results
uses: actions/upload-artifact@v7
with:
name: test-results
path: ${{ github.workspace }}/surefire-reports-aggregate/*.xml
test-modules:
name: Test Module - ${{ matrix.name }}
runs-on: ubuntu-latest
needs:
- build
strategy:
fail-fast: false
matrix: ${{fromJson(needs.build.outputs.testMatrix)}}
steps:
- name: Checkout Release Tag
uses: actions/checkout@v6
with:
ref: ${{ github.event.repository.name }}-${{ github.event.inputs.releaseVersion }}
fetch-depth: 1
persist-credentials: false
- name: Before Test
uses: ./.github/workflows/actions/before-test
- name: Included Modules
id: modulesToInclude
env:
MODULES: ${{ toJSON(matrix.modules) }}
run: |
echo INCLUSION_MODULES=`jq -c 'map("org.finos.legend.engine:" + .) | join(",")' <<< $MODULES` >> $GITHUB_OUTPUT
- name: Test
env:
MAVEN_OPTS: "-Xmx1g"
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
mvn -B -e surefire:test -pl ${{ steps.modulesToInclude.outputs.INCLUSION_MODULES }} -P release,docker,pct-cloud-test -T2 -DargLine="-Xmx6g" -Dsurefire.reports.directory=${GITHUB_WORKSPACE}/surefire-reports-aggregate
- name: Upload Test Results
uses: actions/upload-artifact@v7
with:
name: test-results-${{ matrix.name }}
path: ${{ github.workspace }}/surefire-reports-aggregate/*.xml
release:
name: Create and Publish Release Bundle
runs-on: ubuntu-latest
needs:
- build
- test
- test-modules
steps:
- name: Checkout Release Tag
uses: actions/checkout@v4
with:
ref: ${{ github.event.repository.name }}-${{ github.event.inputs.releaseVersion }}
fetch-depth: 1
persist-credentials: false
- name: Download m2 repository for publishing
uses: actions/download-artifact@v8
with:
name: m2-repo
path: ~/.m2/repository/org/finos/legend/engine
- name: Create bundle to publish
env:
RELEASE_VERSION: ${{ github.event.inputs.releaseVersion }}
run: |
# Defensive guard: keep only directories whose name is exactly the
# release version under each artifact path. Should be a no-op when
# the build job already purged stale artifacts, but protects the
# publish step against any future regression that lets prior-release
# jars slip into ~/.m2/repository/org/finos/legend/engine.
find ~/.m2/repository/org/finos/legend/engine -mindepth 2 -type d \
-regextype posix-extended \
-regex '.*/[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.+-]+)?$' \
! -name "$RELEASE_VERSION" -prune -exec rm -rf {} +
mkdir -p central-staging/org/finos/legend
cp -R ~/.m2/repository/org/finos/legend/engine central-staging/org/finos/legend
find central-staging -type f \( -name "*.xml" -o -name "*.repositories" \) -delete
find central-staging -type f ! -name "*.md5" ! -name "*.sha1" ! -name "*.sha256" ! -name "*.sha512" ! -name "*.asc" | while read -r file; do
md5sum "$file" | awk '{print $1}' > "$file.md5"
sha1sum "$file" | awk '{print $1}' > "$file.sha1"
sha256sum "$file" | awk '{print $1}' > "$file.sha256"
sha512sum "$file" | awk '{print $1}' > "$file.sha512"
done
mkdir central-publishing
cd central-staging && zip -r ../central-publishing/central-bundle.zip org
- name: Publish bundle
working-directory: central-publishing
run: |
token=$(printf "$CI_DEPLOY_USERNAME:$CI_DEPLOY_PASSWORD" | base64)
httpCode=$(curl -s -o response.json -w "%{http_code}" -X POST -H "Authorization: Bearer $token" --form bundle=@central-bundle.zip https://central.sonatype.com/api/v1/publisher/upload?publishingType=AUTOMATIC)
if [[ "$httpCode" == 2* ]]; then
deploymentId=$(cat response.json)
echo "Uploaded bundle. Deployment id is: $deploymentId"
echo "DEVELOPMENT_ID=${deploymentId}" >> $GITHUB_ENV
else
echo "Failed to upload bundle. Got status code $httpCode"
echo "Got the following response body:"
cat response.json
exit 1
fi
- name: Verify deployment status
run: |
token=$(printf "$CI_DEPLOY_USERNAME:$CI_DEPLOY_PASSWORD" | base64)
deploymentId=${{ env.DEVELOPMENT_ID }}
deploymentState=""
while [ "$deploymentState" != "PUBLISHED" ]; do
sleep 1m
response=$(curl -s -X POST -H "Authorization: Bearer $token" https://central.sonatype.com/api/v1/publisher/status?id=$deploymentId)
deploymentState=$(echo "$response" | jq -r '.deploymentState')
echo "Deployment state for id $deploymentId is $deploymentState"
if [[ "$deploymentState" == "FAILED" ]]; then
echo "The deployment failed with the following response"
echo "$response"
exit 1
fi
done