diff --git a/.github/workflows/job.release.yml b/.github/workflows/job.release.yml new file mode 100644 index 0000000000..1159a023a9 --- /dev/null +++ b/.github/workflows/job.release.yml @@ -0,0 +1,310 @@ +# +# Copyright (c) 2025 Elide Technologies, Inc. +# +# Licensed under the MIT license (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://opensource.org/license/mit/ +# +# 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 + +"on": + workflow_dispatch: + inputs: + test: + description: "Test Mode" + type: boolean + default: true + +# Do not add `ELIDE_VERSION` here like other workflows, or it may interfere with the release version override. +env: + RUST_BACKTRACE: full + SCCACHE_DIRECT: "true" + RUSTC_WRAPPER: "sccache" + BUILDLESS_APIKEY: ${{ secrets.BUILDLESS_APIKEY }} + +permissions: + contents: read + +jobs: + ## + ## Job: Library Build + ## + release: + name: "Release: Native Build (${{ matrix.os }}, ${{ matrix.arch || 'amd64' }})" + runs-on: ${{ matrix.runner }} + + strategy: + fail-fast: false + matrix: + include: + - runner: minimax-arm64-1 + arch: arm64 + labs: false + tag: linux-arm64 + - runner: macsandbox-arm64-1 + arch: arm64 + labs: false + tag: darwin-arm64 + - runner: ci-agent-01 + arch: amd64 + labs: false + tag: linux-amd64 + - runner: unclemax-win1 + arch: amd64 + labs: false + tag: windows-amd64 + permissions: + contents: write + id-token: write + + defaults: + run: + shell: bash + + outputs: + elide-version: ${{ steps.get-version.outputs.test }} + + steps: + - name: "Setup: Job Mode" + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "TEST_MODE=${{ inputs.test }}" >> $GITHUB_ENV + else + echo "TEST_MODE=true" >> $GITHUB_ENV + fi + + - name: "Setup: Harden Runner" + uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + with: + disable-sudo: false + egress-policy: audit + - name: "Setup: Checkout" + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + submodules: true + persist-credentials: false + token: ${{ secrets.GITHUB_TOKEN }} + - name: "Setup: Cache Restore" + id: cache-restore + uses: buildjet/cache/restore@3e70d19e31d6a8030aeddf6ed8dbe601f94d09f4 # v4.0.2 + with: + key: elide-v3-build-${{ hashFiles('gradle/elide.versions.toml') }} + path: | + tools/elide-build/build/**/*.* + packages/*/build/**/*.* + target/ + target/x86_64-unknown-linux-gnu/debug/*.a + target/x86_64-unknown-linux-gnu/debug/*.so + third_party/sqlite/install/ + restore-keys: | + elide-v3-build-${{ hashFiles('gradle/elide.versions.toml') }} + elide-v3- + - name: "Setup: Packages" + if: contains(matrix.runner, 'ubuntu') || contains(matrix.runner, 'linux') + run: sudo apt-get update && sudo apt-get install -y build-essential libssl-dev + - name: "Setup: Rust" + uses: actions-rust-lang/setup-rust-toolchain@fb51252c7ba57d633bc668f941da052e410add48 # v1.13.0 + with: + toolchain: stable + cache: true # handled by sccache + cache-key: "elide-rust-v1-{{ hashFiles('Cargo.lock') }}" + - name: "Setup: SCCache" + uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9 + - name: "Setup: Rust Caching" + run: echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV + - name: "Setup: GraalVM (Java 25)" + uses: graalvm/setup-graalvm@7f488cf82a3629ee755e4e97342c01d6bed318fa # v1.3.5 + with: + distribution: "graalvm" + java-version: "25" + github-token: ${{ secrets.GITHUB_TOKEN }} + - name: "Setup: Node" + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + with: + node-version: 23 + - name: "Setup: Bun" + uses: step-security/setup-bun@a961ff54612b97ac3259f517fb6a81be3b657a59 # v2.0.2 + with: + bun-version: "1.2.14" + - name: "Setup: PNPM" + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + with: + version: "10.6.2" + - name: "Setup: uv" + uses: astral-sh/setup-uv@7edac99f961f18b581bbd960d59d049f04c0002f # v6.4.1 + - name: "Setup: Dependencies" + run: | + echo "Setting up venv..." + uv venv + echo "Activating venv..." + . .venv/bin/activate + echo "Installing dependencies via Pip..." + uv pip install -r config/requirements.txt + echo PATH=$PATH >> $GITHUB_ENV + echo "Installing dependencies..." + pnpm install + - name: "Setup: Gradle" + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + id: gradlebuild + continue-on-error: ${{ matrix.mode == 'labs' }} + env: + CI: true + BUILDLESS_APIKEY: ${{ secrets.BUILDLESS_APIKEY }} + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + with: + cache-read-only: false + cache-encryption-key: ${{ secrets.GRADLE_CONFIGURATION_KEY }} + dependency-graph: disabled + gradle-home-cache-cleanup: true + gradle-home-cache-includes: binaryen + caches + jdks + native + native-build-tools + nodejs + notifications + wrapper + yarn + - name: "Setup: Gradle Settings" + run: cp -fv ./.github/workflows/gradle-ci.properties ~/.gradle/gradle.properties + - name: "Setup: Cosign" + uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0 + - name: "Build Environment" + run: file Makefile && make info CI=yes 2>&1 | tee build-info.txt + - name: "🛠️ Build: Image" + env: + CI: true + BUILDLESS_APIKEY: ${{ secrets.BUILDLESS_APIKEY }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + TEST_EXCEPTIONS: true + run: | + bash ./tools/scripts/release/native-build.sh --release --publish + - name: "Setup: Signing Keys" + run: | + cat <(echo -e "${{ secrets.SIGNING_KEY }}") | base64 -d | gpg --batch --import + gpg --list-secret-keys --keyid-format LONG + gpg --export-secret-keys > ~/.gnupg/secring.gpg + - name: "Get Version" + id: get-version + run: | + source ./tools/scripts/release/version-set.sh + echo "ELIDE_VERSION=$ELIDE_VERSION" >> $GITHUB_ENV + echo "ELIDE_VERSION=$ELIDE_VERSION" >> $GITHUB_OUTPUT + - name: "🛠 Release: Package" + run: bash ./tools/scripts/release/package-release.sh + env: + COSIGN_KEY: ${{ secrets.COSIGN_KEY }} + COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} + COSIGN_ARGS: "--key env://COSIGN_KEY" + - name: "🛠 Release: Stage" + run: + bash ./tools/scripts/release/stage-release.sh + - name: "🛠 Release: Push to Cloud" + if: ${{ env.TEST_MODE == 'false' }} + run: | + bash ./tools/scripts/release/push-to-cloud.sh + + + create_release: + name: "Release: Create Github Release" + runs-on: ubuntu-cipool + needs: release + + outputs: + release-id: ${{ steps.create_release.outputs.id }} + + permissions: + contents: write + id-token: write + + defaults: + run: + shell: bash + steps: + - name: release + uses: actions/create-release@v1 + id: create_release + if: ${{ env.TEST_MODE == 'false' }} + with: + draft: false + prerelease: false + release_name: ${{ needs.release.outputs.elide-version }} + tag_name: ${{ github.ref }} + env: + GITHUB_TOKEN: ${{ github.token }} + + upload_file_to_release: + name: "Release: Upload Artifacts to Github Release" + runs-on: ${{ matrix.runner }} + needs: [create_release, release] + + strategy: + fail-fast: false + matrix: + include: + - runner: minimax-arm64-1 + arch: arm64 + labs: false + tag: linux-arm64 + - runner: macsandbox-arm64-1 + arch: arm64 + labs: false + tag: darwin-arm64 + - runner: ci-agent-01 + arch: amd64 + labs: false + tag: linux-amd64 + - runner: unclemax-win1 + arch: amd64 + labs: false + tag: windows-amd64 + permissions: + contents: write + id-token: write + + steps: + - name: "Setup: Job Mode" + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "TEST_MODE=${{ inputs.test }}" >> $GITHUB_ENV + else + echo "TEST_MODE=true" >> $GITHUB_ENV + fi + + - name: "Upload Files to Release" + id: upload-artifacts + if: ${{ env.TEST_MODE == 'false' }} + uses: actions/github-script@v2 + env: + RELEASE_ID: ${{ needs.create_release.outputs.release-id }} + VERSION: ${{ needs.release.outputs.elide-version }} + PLATFORM: ${{ matrix.tag }} + with: + script: | + console.log('environment', process.versions); + const fs = require('fs').promises; + const { repo: { owner, repo }, sha } = context; + console.log({ owner, repo, sha }); + + const release_id = process.env.RELEASE_ID; + const version = process.env.VERSION; + const platform = process.env.PLATFORM; + const staging_path = './staging/release/${platform}/${version}; + + for (let file of await fs.readdir(staging_path)) { + console.log('uploading', file); + + await github.repos.uploadReleaseAsset({ + owner, repo, + release_id: release_id, + name: file, + data: await fs.readFile(`${staging_path}/${file}`) + }); + } diff --git a/tools/scripts/release/assemble-dist.sh b/tools/scripts/release-old/assemble-dist.sh similarity index 100% rename from tools/scripts/release/assemble-dist.sh rename to tools/scripts/release-old/assemble-dist.sh diff --git a/tools/scripts/release/build-apk.sh b/tools/scripts/release-old/build-apk.sh similarity index 100% rename from tools/scripts/release/build-apk.sh rename to tools/scripts/release-old/build-apk.sh diff --git a/tools/scripts/release/build-deb.sh b/tools/scripts/release-old/build-deb.sh similarity index 100% rename from tools/scripts/release/build-deb.sh rename to tools/scripts/release-old/build-deb.sh diff --git a/tools/scripts/release-old/build-publish-release.sh b/tools/scripts/release-old/build-publish-release.sh new file mode 100644 index 0000000000..1b7ef6f820 --- /dev/null +++ b/tools/scripts/release-old/build-publish-release.sh @@ -0,0 +1,222 @@ +#!/usr/bin/env bash + +set -euo pipefail +set +x + +# This script is meant to be run from the root of the Elide repository as a part of release pipeline. +# Several flags are supported: +# --dry: Skip unsafe commands, just print what would be done. Default mode. +# --release: Builds in local release mode. +# --publish: Publish the built artifacts to the remote repositories and package managers. +# --help: Show a help message. + +# +dry=true +publish=false +release=false + +stamp=false +clean=false +pgo=false +provenance=false +help=false +clean=true +thirdParty=true +nativeTask=nativeCompile +platform="$(uname -s | tr '[:upper:]' '[:lower:]')" +arch="$(uname -m | sed 's/x86_64/amd64/')" +libc="auto" + +publishTask=publishAllPublicationsToStageRepository +version="" +NPM_ARGS="" +GRADLE_PROPS="" +PACKAGE_ARGS="" +buildMode=dev + +if [[ "$@" == *"--help"* ]]; then + help=true + dev=false +fi + +# render help message and exit if requested. +if [[ "$help" == true ]]; then + echo "Usage: $0 [--dry] [--publish] [--release] [--version ] [--help]" + echo "" + echo "Performs a full release of Elide, including native binaries, Maven artifacts, and others." + echo "" + echo "Options:" + echo " --dry Dry run, skips unsafe commands (still builds, etc). Default mode." + echo " --release Build in local release mode." + echo " --publish Publish the built artifacts to the remote repository." + echo " --version Specify a version to release (default: read from .release)." + echo " --help Show this help message." + exit 0 +fi + +if [["$@" == *"--dry"*]]; then + dry=true +fi + +if [[ "$@" == *"--publish"* ]]; then + publish=true + release=true + dry=false +fi + + if [[ "$@" == *"--release"* ]]; then + release=true + clean=true +fi + +if [[ "$@" == *"--version"* ]]; then + version=$(echo "$@" | grep -oP '(?<=--version\s)[^\s]+') +fi + +if [[ "$release" == true ]]; then + stamp=true + publishTask=publishAllElidePublications + provenance=true + pgo=true + nativeTask=nativeOptimizedCompile + buildMode=release +fi + +if [[ "$dry" == true ]]; then + publishTask=publishAllPublicationsToStageRepository + provenance=false +fi + +# Build Options, NPM and Gradle +if [[ "$provenance" == true ]]; then + NPM_ARGS="$NPM_ARGS --provenance" + PACKAGE_ARGS="$PACKAGE_ARGS --provenance" +fi + +# in release mode, tell gradle to build the docs and enable signing +if [[ "$release" == true ]]; then + GRADLE_PROPS="$GRADLE_PROPS -Pelide.buildDocs=true -PenableSigning=true" + PACKAGE_ARGS="$PACKAGE_ARGS --release --stamp" + if [[ "$dry" != true ]]; then + GRADLE_PROPS="$GRADLE_PROPS -PenableSigstore=true" + fi +else + GRADLE_PROPS="$GRADLE_PROPS -Pelide.buildDocs=false -PenableSigning=false -PenableSigstore=false" +fi + +ELIDE_TOOLS_REPO="elide:elide-tools" +ELIDE_MAVEN_REPO="elide:elide-maven" +GRADLE_PROPS="-Pelide.release=$release -Pelide.buildMode=$buildMode -Pelide.stamp=$stamp -Pelide.pgo=$pgo $GRADLE_PROPS" +GRADLE_ARGS="--no-configuration-cache" +PUBLISH_TARGETS=":packages:core:$publishTask :packages:base:$publishTask :packages:test:$publishTask :packages:tooling:$publishTask :packages:builder:$publishTask :packages:graalvm:$publishTask :packages:server:$publishTask :packages:http:$publishTask :packages:graalvm-java:$publishTask :packages:graalvm-js:$publishTask :packages:graalvm-jvm:$publishTask :packages:graalvm-kt:$publishTask :packages:graalvm-llvm:$publishTask :packages:graalvm-py:$publishTask :packages:graalvm-rb:$publishTask :packages:graalvm-ts:$publishTask :packages:graalvm-wasm:$publishTask :packages:engine:$publishTask" + +## Perform a clean if needed +if [[ "$clean" == true ]]; then + echo "Cleaning previous build artifacts..." + set -x; + ./gradlew \ + $GRADLE_ARGS \ + $GRADLE_PROPS \ + clean; + set +x; +fi + +## Assemble libraries +set -x; +./gradlew \ + $GRADLE_ARGS \ + $GRADLE_PROPS \ + assemble; +set +x; + +## Build native image +set -x; + ./gradlew \ + $GRADLE_ARGS \ + $GRADLE_PROPS \ + :packages:cli:$nativeTask; +set +x; + +source ./tools/scripts/release/commons.sh + +## Build release packages +export ELIDE_VERSION="$version"; +export ELIDE_PLATFORM="$platform"; +export ELIDE_ARCH="$arch"; + +source ./tools/scripts/release/publish-release.sh --version=$version $PACKAGE_ARGS + +if [[ "$dry" != true ]]; then + set -x; + cd ./packages/cli/build/native/nativeOptimizedCompile/; + mkdir -p "release/${platform}-${arch}/$version;" + cp -fv elide-*.{tgz,txz,zip}* "release/${platform}-${arch}/$version/" + cp -fv elide.sbom.json "release/${platform}-${arch}/$version/" + cp -fv elide-build-report.html "release/${platform}-${arch}/$version/elide.build-report.html" + cd -; + mkdir -p staging/release + mv "packages/cli/build/native/nativeOptimizedCompile/release" "staging/" + tree -L 3 staging/ + echo "Release built." + set +x; +fi + +## Build build/m2 root into a zip +if [[ "$publish" == true ]]; then + echo "Building m2 zip..." + cd build/m2; + set -x; + rm -fv ../elide-m2.zip && zip -r ../elide-m2.zip . || { + echo "Failed to create m2 zip. Exiting." + exit 1 + }; + set +x; + cd -; +fi + +## I THINK?? +## if --publish is active, run rclone +if [[ "$publish" == true ]]; then + echo "Publishing Maven artifacts to Elide repository..." + if [[ "$dry" == true ]]; then + echo "Dry run: would publish to remote repository." + echo cd build/m2 && echo rclone copy --progress . $ELIDE_MAVEN_REPO/ + echo "Dry run: would publish npm types." + cd packages/types && npm publish --access public --dry $NPM_ARGS; + else + set -x; + cd build/m2 && rclone copy --progress . $ELIDE_MAVEN_REPO/ + set +x; + echo "Elide Maven updated." + set -x; + cd packages/types && npm publish --access public $NPM_ARGS; + set +x; + echo "Elide NPM libs updated." + fi +else + echo "Skipping publishing step." +fi + +echo "Release build completed successfully." + +echo "┌─────────────────────────────────────────────────┐" +echo "╵ Elide release receipt ╵" +echo "└─────────────────────────────────────────────────┘" +echo "- Version: $version" +echo "- Platform: $platform" +echo "- Architecture: $arch" +echo "- Tag: ${platform}-${arch}" +echo "- Mode: $buildMode" +echo "- Release: $release" +echo "- Stamp: $stamp" +echo "- Dry run: $dry" +echo "- Publish: $publish" +echo "- Provenance: $provenance" +echo "- LibC: $libc" +echo "- PGO: $pgo" +echo "- Clean: $clean" +echo "- Third-party: $thirdParty" + +echo "" +echo "Done." +exit 0 diff --git a/tools/scripts/release/build-release.sh b/tools/scripts/release-old/build-release.sh similarity index 98% rename from tools/scripts/release/build-release.sh rename to tools/scripts/release-old/build-release.sh index 6b516f2d2c..f80c1a7f95 100755 --- a/tools/scripts/release/build-release.sh +++ b/tools/scripts/release-old/build-release.sh @@ -14,7 +14,7 @@ # set -euo pipefail -source tools/scripts/release/commons.sh +source tools/scripts/release-old/commons.sh set +x diff --git a/tools/scripts/release/build-rpm.sh b/tools/scripts/release-old/build-rpm.sh similarity index 100% rename from tools/scripts/release/build-rpm.sh rename to tools/scripts/release-old/build-rpm.sh diff --git a/tools/scripts/release/commons.sh b/tools/scripts/release-old/commons.sh similarity index 100% rename from tools/scripts/release/commons.sh rename to tools/scripts/release-old/commons.sh diff --git a/tools/scripts/release-old/package-release.sh b/tools/scripts/release-old/package-release.sh new file mode 100644 index 0000000000..b4fc2c0d4d --- /dev/null +++ b/tools/scripts/release-old/package-release.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2025 Elide Technologies, Inc. +# +# Licensed under the MIT license (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://opensource.org/license/mit/ +# +# 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. +# + +set -euo pipefail +source tools/scripts/release/commons.sh + +set +x + +# if ELIDE_COSIGN is set to `false`, skip cosign +do_cosign=true +if [ "${ELIDE_COSIGN:-true}" = "false" ]; then + do_cosign=false +fi +COSIGN_ARGS="${COSIGN_ARGS:-}" + +# if ELIDE_GPGSIGN is set to `false`, skip GPG signing +do_gpgsign=true +if [ "${ELIDE_GPGSIGN:-true}" = "false" ]; then + do_gpgsign=false +fi + +echo "----------------------------------------------------" + +echo "Elide Release Builder" +echo "- Version: $version" +echo "- Platform: $platform" +echo "- Architecture: $arch" + +echo "----------------------------------------------------" + +# echo "platform: $platform" +# echo "variant: $variant" +# echo "version: $version" +# echo "arch: $arch" + +if [ "$platform" = "" ]; then exit 2; fi +if [ "$variant" = "" ]; then exit 3; fi +if [ "$version" = "" ]; then exit 4; fi +if [ "$arch" = "" ]; then exit 5; fi + +root=$(pwd) +echo "- Building release root (variant: $variant / platform: $platform)..." +pushd packages/cli/build/native/nativeOptimizedCompile \ + && mkdir -p "$archive_prefix-$version-$platform/" \ + && cp -fr elide ./*.{so,dylib,dll} $root/packages/cli/packaging/content/* resources "$archive_prefix-$version-$platform/" || echo "OK with copy warnings." + +echo "- Building tar package (variant: $variant / platform: $platform)..." +tar -cf "$archive_prefix-$version-$platform.tar" "$archive_prefix-$version-$platform/" + +echo "- Building zip package (variant: $variant / platform: $platform)..." +zip -v -9 -r "$archive_prefix-$version-$platform.zip" "$archive_prefix-$version-$platform/" + +echo "- Building tgz package (variant: $variant / platform: $platform)..." +gzip -v --best -k "$archive_prefix-$version-$platform.tar" +mv "$archive_prefix-$version-$platform.tar.gz" "$archive_prefix-$version-$platform.tgz" + +echo "- Building txz package (variant: $variant / platform: $platform)..." +xz -v --best -k "$archive_prefix-$version-$platform.tar" +mv "$archive_prefix-$version-$platform.tar.xz" "$archive_prefix-$version-$platform.txz" + +if [[ "$@" == *"--dry"* ]]; then + echo "Dry run mode enabled, skipping further steps." + exit 0 +fi + +echo "- Stamping releases (variant: $variant / platform: $platform)..." + +if [ "$(uname -o)" = "Darwin" ]; then + SHA256SUM="gsha256sum" + SHA512SUM="gsha512sum" +else + SHA256SUM="sha256sum" + SHA512SUM="sha512sum" +fi + +for archive in ./elide*.{tgz,txz,zip}; do + echo "- Archive \"$archive\"..." + echo "- SHA256..." + $SHA256SUM "$archive" > "$archive.sha256" + echo "- SHA512..." + $SHA512SUM "$archive" > "$archive.sha512" + if [ "$do_gpgsign" = true ]; then + echo "- GPG2..." + gpg --detach-sign --batch --yes --armor "$archive" + fi + if [ "$do_cosign" = true ]; then + echo "- Sigstore..." + cosignArgs="${COSIGN_ARGS} --output-signature=$archive.sig --output-certificate=$archive.pem --bundle=$archive.sigstore" + yes y | cosign sign-blob "$archive" $cosignArgs -y || echo "Cosign failed; inspect log." + fi + echo "" +done + +popd || exit 0 + diff --git a/tools/scripts/release/publish-dist.sh b/tools/scripts/release-old/publish-dist.sh similarity index 100% rename from tools/scripts/release/publish-dist.sh rename to tools/scripts/release-old/publish-dist.sh diff --git a/tools/scripts/release/sign-apk.sh b/tools/scripts/release-old/sign-apk.sh similarity index 100% rename from tools/scripts/release/sign-apk.sh rename to tools/scripts/release-old/sign-apk.sh diff --git a/tools/scripts/release/sign-deb.sh b/tools/scripts/release-old/sign-deb.sh similarity index 100% rename from tools/scripts/release/sign-deb.sh rename to tools/scripts/release-old/sign-deb.sh diff --git a/tools/scripts/release/sign-rpm.sh b/tools/scripts/release-old/sign-rpm.sh similarity index 100% rename from tools/scripts/release/sign-rpm.sh rename to tools/scripts/release-old/sign-rpm.sh diff --git a/tools/scripts/release/native-build.sh b/tools/scripts/release/native-build.sh new file mode 100644 index 0000000000..1f2d04bb08 --- /dev/null +++ b/tools/scripts/release/native-build.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2025 Elide Technologies, Inc. +# +# Licensed under the MIT license (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://opensource.org/license/mit/ +# +# 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. +# + +set -euo pipefail +set +x + +# This script is meant to be run from the root of the Elide repository as a part of release pipeline. +# It builds a native image. +# Several flags are supported: +# --dry: Skip unsafe commands, just print what would be done. Default mode. +# --release: Builds in local release mode. +# --publish: Publish the built artifacts to the remote repositories and package managers. +# --help: Show a help message. +dry=true +publish=false +release=false + +stamp=false +clean=false +pgo=false +help=false +nativeTask=nativeCompile +publishTask=publishAllPublicationsToStageRepository +GRADLE_PROPS="" +buildMode=dev + +if [[ "$@" == *"--dry"* ]]; then + dry=true +fi + +if [[ "$@" == *"--publish"* ]]; then + publish=true + release=true +fi + + if [[ "$@" == *"--release"* ]]; then + release=true + clean=true +fi + +if [[ "$release" == true ]]; then + stamp=true + publishTask=publishAllElidePublications + pgo=true + nativeTask=nativeOptimizedCompile + buildMode=release +fi + +# in release mode, tell gradle to build the docs and enable signing +if [[ "$release" == true ]]; then + GRADLE_PROPS="$GRADLE_PROPS -Pelide.buildDocs=true -PenableSigning=true" + if [[ "$dry" != true ]]; then + GRADLE_PROPS="$GRADLE_PROPS -PenableSigstore=true" + fi +else + GRADLE_PROPS="$GRADLE_PROPS -Pelide.buildDocs=false -PenableSigning=false -PenableSigstore=false" +fi + +GRADLE_PROPS="-Pelide.release=$release -Pelide.buildMode=$buildMode -Pelide.stamp=$stamp -Pelide.pgo=$pgo $GRADLE_PROPS" +GRADLE_ARGS="--no-configuration-cache" +PUBLISH_TARGETS=":packages:core:$publishTask :packages:base:$publishTask :packages:test:$publishTask :packages:tooling:$publishTask :packages:builder:$publishTask :packages:graalvm:$publishTask :packages:server:$publishTask :packages:http:$publishTask :packages:graalvm-java:$publishTask :packages:graalvm-js:$publishTask :packages:graalvm-jvm:$publishTask :packages:graalvm-kt:$publishTask :packages:graalvm-llvm:$publishTask :packages:graalvm-py:$publishTask :packages:graalvm-rb:$publishTask :packages:graalvm-ts:$publishTask :packages:graalvm-wasm:$publishTask :packages:engine:$publishTask" + +## Perform a clean if needed +if [[ "$clean" == true ]]; then + echo "Cleaning previous build artifacts..." + set -x; + ./gradlew \ + $GRADLE_ARGS \ + $GRADLE_PROPS \ + clean; + set +x; +fi + +## Assemble libraries +set -x; +./gradlew \ + $GRADLE_ARGS \ + $GRADLE_PROPS \ + assemble; +set +x; + +## Build native image +set -x; +./gradlew \ + :packages:cli:nativeOptimizedCompile -Pelide.buildMode=release -Pelide.pgo=true -Pelide.release=true -Pelide.opt=4 -Pelide.debug=false -Pelide.stamp=true -Pelide.static=false +set +x; + +## Build native image +set -x; + ./gradlew \ + $GRADLE_ARGS \ + $GRADLE_PROPS \ + :packages:cli:$nativeTask; +set +x; + +exit 0 diff --git a/tools/scripts/release/package-release.sh b/tools/scripts/release/package-release.sh new file mode 100644 index 0000000000..701873a469 --- /dev/null +++ b/tools/scripts/release/package-release.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2025 Elide Technologies, Inc. +# +# Licensed under the MIT license (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://opensource.org/license/mit/ +# +# 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. +# + +set -euo pipefail +source tools/scripts/release/version-set.sh +source tools/scripts/release/platform-set.sh + +set +x + +# if ELIDE_COSIGN is set to `false`, skip cosign +do_cosign=true +if [ "${ELIDE_COSIGN:-true}" = "false" ]; then + do_cosign=false +fi +COSIGN_ARGS="${COSIGN_ARGS:-}" + +# if ELIDE_GPGSIGN is set to `false`, skip GPG signing +do_gpgsign=true +if [ "${ELIDE_GPGSIGN:-true}" = "false" ]; then + do_gpgsign=false +fi + +echo "----------------------------------------------------" + +echo "Elide Release Builder" +echo "- Version: $version" +echo "- Platform: $platform" +echo "- Architecture: $arch" + +echo "----------------------------------------------------" + +# echo "platform: $platform" +# echo "variant: $variant" +# echo "version: $version" +# echo "arch: $arch" + +if [ "$platform" = "" ]; then exit 2; fi +if [ "$variant" = "" ]; then exit 3; fi +if [ "$version" = "" ]; then exit 4; fi +if [ "$arch" = "" ]; then exit 5; fi + +root=$(pwd) +echo "- Building release root (variant: $variant / platform: $platform-$arch)..." +pushd packages/cli/build/native/nativeOptimizedCompile \ + && mkdir -p "$archive_prefix-$version-$platform-$arch/" \ + && cp -fr elide ./*.{so,dylib,dll} $root/packages/cli/packaging/content/* resources "$archive_prefix-$version-$platform-$arch/" || echo "OK with copy warnings." + +echo "- Building tar package (variant: $variant / platform: $platform-$arch)..." +tar -cf "$archive_prefix-$version-$platform-$arch.tar" "$archive_prefix-$version-$platform-$arch/" + +echo "- Building zip package (variant: $variant / platform: $platform-$arch)..." +zip -v -9 -r "$archive_prefix-$version-$platform-$arch.zip" "$archive_prefix-$version-$platform-$arch/" + +echo "- Building tgz package (variant: $variant / platform: $platform-$arch)..." +gzip -v --best -k "$archive_prefix-$version-$platform-$arch.tar" +mv "$archive_prefix-$version-$platform-$arch.tar.gz" "$archive_prefix-$version-$platform-$arch.tgz" + +echo "- Building txz package (variant: $variant / platform: $platform-$arch)..." +xz -v --best -k "$archive_prefix-$version-$platform-$arch.tar" +mv "$archive_prefix-$version-$platform-$arch.tar.xz" "$archive_prefix-$version-$platform-$arch.txz" + +if [[ "$@" == *"--dry"* ]]; then + echo "Dry run mode enabled, skipping further steps." + exit 0 +fi + +echo "- Stamping releases (variant: $variant / platform: $platform-$arch)..." + +if [ "$hostPlatform" = "darwin" ]; then + SHA256SUM="gsha256sum" + SHA512SUM="gsha512sum" +else + SHA256SUM="sha256sum" + SHA512SUM="sha512sum" +fi + +for archive in ./elide*.{tgz,txz,zip}; do + echo "- Archive \"$archive\"..." + echo "- SHA256..." + $SHA256SUM "$archive" > "$archive.sha256" + echo "- SHA512..." + $SHA512SUM "$archive" > "$archive.sha512" + if [ "$do_gpgsign" = true ]; then + echo "- GPG2..." + gpg --detach-sign --batch --yes --armor "$archive" + fi + if [ "$do_cosign" = true ]; then + echo "- Sigstore..." + cosignArgs="${COSIGN_ARGS} --output-signature=$archive.sig --output-certificate=$archive.pem --bundle=$archive.sigstore" + yes y | cosign sign-blob "$archive" $cosignArgs -y || echo "Cosign failed; inspect log." + fi + echo "" +done + +popd || exit 0 + diff --git a/tools/scripts/release/platform-set.sh b/tools/scripts/release/platform-set.sh new file mode 100644 index 0000000000..099f0eb3f7 --- /dev/null +++ b/tools/scripts/release/platform-set.sh @@ -0,0 +1,30 @@ +# +# Copyright (c) 2024 Elide Technologies, Inc. +# +# Licensed under the MIT license (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://opensource.org/license/mit/ +# +# 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. +# + +# This script is not meant to be run directly, but rather sourced by other release scripts. +# It sets the pipeline's platform. +hostPlatform=$(uname -s | tr '[:upper:]' '[:lower:]') +platform="${ELIDE_PLATFORM-$hostPlatform}" +hostArch=$(uname -m) +arch="${ELIDE_ARCH-$hostArch}" +variant="opt" +archive_prefix="elide" +install_prefix="/opt/elide" +revision="0" + +if [ "$arch" = "arm64" ]; then + arch="aarch64" +fi +if [ "$arch" = "x86_64" ]; then + arch="amd64" +fi diff --git a/tools/scripts/release/push-to-cloud.sh b/tools/scripts/release/push-to-cloud.sh new file mode 100644 index 0000000000..e792e0a6b6 --- /dev/null +++ b/tools/scripts/release/push-to-cloud.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2025 Elide Technologies, Inc. +# +# Licensed under the MIT license (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://opensource.org/license/mit/ +# +# 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. +# + +set -euo pipefail +source tools/scripts/release/version-set.sh +source tools/scripts/release/platform-set.sh +set +x + +rclone --progress copy ./staging/release r2:elide-tools/cli/v1/snapshot/$platform-$arch/$version/ + + +set -x +exit 0 diff --git a/tools/scripts/release/release.sh b/tools/scripts/release/release.sh new file mode 100644 index 0000000000..2ea29187a2 --- /dev/null +++ b/tools/scripts/release/release.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2025 Elide Technologies, Inc. +# +# Licensed under the MIT license (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://opensource.org/license/mit/ +# +# 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. +# +set -euo pipefail +set +x + +# This script is meant to be run from the root of the Elide and acts as an entry point for the release pipeline. +# It unifies the entier pipeline into a single script. +# Several flags are supported: +# --dry: Skip unsafe commands, just print what would be done. Default mode. +# --release: Builds in local release mode. +# --publish: Publish the built artifacts to the remote repositories and package managers. +# --help: Show a help message. +source tools/scripts/release/platform-set.sh + +dry=true +publish=false +release=false +help=false +version="" +RELEASE_PARAMS="" + +if [[ "$@" == *"--help"* ]]; then + help=true +fi + +# render help message and exit if requested. +if [[ "$help" == true ]]; then + echo "Usage: $0 [--dry] [--publish] [--release] [--version ] [--help]" + echo "" + echo "Performs a full release build of Elide, including native binaries, packaging,." + echo "" + echo "Options:" + echo " --dry Dry run, skips unsafe commands (still builds, etc). Default mode." + echo " --release Build in local release mode." + echo " --publish Publish the built artifacts to the remote repository." + echo " --version Specify a version to release (default: read from .release)." + echo " --help Show this help message." + exit 0 +fi + +#TODO: add logic to make sure --publish and --release are exclusive. +if [["$@" == *"--dry"*]]; then + RELEASE_PARAMS="$RELEASE_PARAMS --dry" +fi + +if [[ "$@" == *"--publish"* ]]; then + RELEASE_PARAMS="$RELEASE_PARAMS --publish" +fi + +if [[ "$@" == *"--release"* ]]; then + RELEASE_PARAMS="$RELEASE_PARAMS --release" +fi + +echo "┌─────────────────────────────────────────────────┐" +echo "╵ Elide Release ╵" +echo "└─────────────────────────────────────────────────┘" +echo " Creating a release for $platform-$arch." +echo "┌─────────────────────────────────────────────────┐" +echo "╵ Cooking a native build ╵" +echo "└─────────────────────────────────────────────────┘" +bash ./tools/scripts/release/native-build.sh $RELEASE_PARAMS +echo "┌─────────────────────────────────────────────────┐" +echo "╵ Packaging and signing the release. ╵" +echo "└─────────────────────────────────────────────────┘" +bash ./tools/scripts/release/package-release.sh $RELEASE_PARAMS +echo "┌─────────────────────────────────────────────────┐" +echo "╵ Staging the release. ╵" +echo "└─────────────────────────────────────────────────┘" +bash ./tools/scripts/release/package-release.sh $RELEASE_PARAMS + +source tools/scripts/release/version-set.sh +echo "┌─────────────────────────────────────────────────┐" +echo "╵ Elide release receipt ╵" +echo "└─────────────────────────────────────────────────┘" +echo "- Version: $version" +echo "- Platform: $platform" +echo "- Architecture: $arch" +echo "- Tag: ${platform}-${arch}" diff --git a/tools/scripts/release/signing-key.sh b/tools/scripts/release/signing-key.sh new file mode 100644 index 0000000000..db456f6d93 --- /dev/null +++ b/tools/scripts/release/signing-key.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2025 Elide Technologies, Inc. +# +# Licensed under the MIT license (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://opensource.org/license/mit/ +# +# 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. +# +set -euo pipefail +set +x + +cat <(echo -e "${secrets.SIGNING_KEY }") | base64 -d | gpg --batch --import +gpg --list-secret-keys --keyid-format LONG +gpg --export-secret-keys > /home/runner/.gnupg/secring.gpg + +set -x +exit 0 diff --git a/tools/scripts/release/stage-release.sh b/tools/scripts/release/stage-release.sh new file mode 100644 index 0000000000..97565420af --- /dev/null +++ b/tools/scripts/release/stage-release.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2025 Elide Technologies, Inc. +# +# Licensed under the MIT license (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://opensource.org/license/mit/ +# +# 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. +# +set -euo pipefail +set +x + +source tools/scripts/release/version-set.sh +source tools/scripts/release/platform-set.sh + +cd ./packages/cli/build/native/nativeOptimizedCompile/; +mkdir -p "release/$platform-$arch/$version" +cp -fv elide-*.{tgz,txz,zip}* "release/$platform-$arch/$version/" +cp -fv elide.sbom.json "release/$platform-$arch/$version/elide-$version-$platform-$arch.sbom.json" +cp -fv elide-build-report.html "release/$platform-$arch/$version/elide-$version-$platform-$arch.build-report.html" +cd -; +mkdir -p staging/release +mv "packages/cli/build/native/nativeOptimizedCompile/release" "staging/" +echo "version=$version" +tree -L 3 staging/ +echo "Release built." +set -x +exit 0 diff --git a/tools/scripts/release/version-set.sh b/tools/scripts/release/version-set.sh new file mode 100644 index 0000000000..ab7561715f --- /dev/null +++ b/tools/scripts/release/version-set.sh @@ -0,0 +1,27 @@ +# +# Copyright (c) 2024 Elide Technologies, Inc. +# +# Licensed under the MIT license (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://opensource.org/license/mit/ +# +# 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. +# + +# This script is not meant to be run directly, but rather sourced by other release scripts. +# It must run after native build and sets the version of the binary +nativeBinTarget="${ELIDE_TARGET:-nativeOptimizedCompile}" +nativePrefix="packages/cli/build/native/$nativeBinTarget" +elideBin="$nativePrefix/elide" +# ensure the binary exists and is executable +if [ ! -x "$elideBin" ]; then + echo "Error: The binary '$elideBin' does not exist or is not executable." >&2 + exit 1 +fi + +# load from `ELIDE_VERSION` or default to `./.release` +version=$($elideBin --version) +ELIDE_VERSION="$version"