Skip to content

Commit

Permalink
chore(ci): refactor release pipeline
Browse files Browse the repository at this point in the history
This is a refactor of the release pipeline scripts and includes a number
of changes:

- Scripts have been reorganised into independent functions for each
  target being built. This should, hopefully, help maintain these
  scripts going forward.

- The scripts allow for arguments to be passed directly to `cargo`,
  thereby allowing for non-release builds as well.

- The release pipeline now also runs on PRs. If being run on PRs, a
  non-release build done as it is faster.

- The publishing steps of the pipeline have been separated into a
  distinct job (which only runs on releases)

- A concurrency group is set up, which will cancel existing builds if a
  new build is triggered on the same PR or on master.

- Some actions in the pipeline have been updated.

- The macOS SDK target has been upgraded to version 12 as version 11
  is no longer maintained.

- Cache dependencies to try and reduce the runtime

Signed-off-by: JP-Ellis <josh@jpellis.me>
  • Loading branch information
JP-Ellis committed Feb 27, 2024
1 parent a3571b2 commit 7732a63
Show file tree
Hide file tree
Showing 11 changed files with 614 additions and 256 deletions.
156 changes: 105 additions & 51 deletions .github/workflows/release.yml
Expand Up @@ -2,88 +2,142 @@ name: Release workflow

on:
release:
types: [published]
types:
- published

pull_request:
branches:
- master

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: true

jobs:
build-release:
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-20.04, windows-latest, macos-11]
include:
- operating-system: ubuntu-20.04
targets: x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl,aarch64-unknown-linux-gnu,aarch64-unknown-linux-musl
- operating-system: windows-2019
targets: aarch64-pc-windows-msvc,x86_64-pc-windows-msvc
- operating-system: macos-12
targets: aarch64-apple-darwin,x86_64-apple-darwin
fail-fast: false

env:
pact_do_not_track: true

steps:
- uses: actions/checkout@v3
- name: Install stable Rust toolchain
if: runner.os == 'Linux'
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: aarch64-unknown-linux-gnu,x86_64-unknown-linux-musl
- name: Install stable Rust toolchain
if: runner.os == 'Windows'
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: aarch64-pc-windows-msvc,x86_64-pc-windows-msvc
- uses: actions/checkout@v4

- name: Install stable Rust toolchain
if: runner.os == 'MacOS'
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: aarch64-apple-darwin,x86_64-apple-darwin
- uses: maxim-lobanov/setup-xcode@v1
targets: ${{ matrix.targets }}

- name: Rust caching
uses: Swatinem/rust-cache@v2
with:
xcode-version: 12.4
if: runner.os == 'MacOS'
workspaces: rust

- name: Set up QEMU
if: runner.os == 'Linux'
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
if: runner.os == 'Linux'
uses: docker/setup-buildx-action@v3
- if: startsWith(github.ref, 'refs/tags/pact_mock_server_cli') && runner.os == 'Linux'
run: ./release-linux.sh
working-directory: rust/pact_mock_server_cli
- if: startsWith(github.ref, 'refs/tags/pact_mock_server_cli') && runner.os == 'Windows'
run: ./release-win.sh

- name: Platform abbreviation
id: platform-abbreviation
shell: bash
working-directory: rust/pact_mock_server_cli
- if: startsWith(github.ref, 'refs/tags/pact_mock_server_cli') && runner.os == 'macOS'
run: ./release-osx.sh
run: |
if [[ "${{ runner.os }}" = "Linux" ]]; then
echo "platform=linux" >> "$GITHUB_OUTPUT"
elif [[ "${{ runner.os }}" = "Windows" ]]; then
echo "platform=win" >> "$GITHUB_OUTPUT"
elif [[ "${{ runner.os }}" = "macOS" ]]; then
echo "platform=osx" >> "$GITHUB_OUTPUT"
else
echo "Unknown platform"
exit 1
fi
- name: Cargo flags
id: cargo-flags
shell: bash
working-directory: rust/pact_mock_server_cli
- if: startsWith(github.ref, 'refs/tags/pact_verifier_cli') && runner.os == 'Linux'
run: ./release-linux.sh
working-directory: rust/pact_verifier_cli
- if: startsWith(github.ref, 'refs/tags/pact_verifier_cli') && runner.os == 'Windows'
run: ./release-win.sh
run: |
if [[ "${{ github.event_name }}" = "release" ]]; then
echo "flags=--release" >> "$GITHUB_OUTPUT"
else
echo "flags=" >> "$GITHUB_OUTPUT"
fi
- name: Build mock server CLI
if: |
github.event_name == 'push' ||
github.event_name == 'pull_request' ||
startsWith(github.ref, 'refs/tags/pact_mock_server_cli')
shell: bash
working-directory: rust/pact_verifier_cli
- if: startsWith(github.ref, 'refs/tags/pact_verifier_cli') && runner.os == 'macOS'
run: ./release-osx.sh
run: |
./release-${{ steps.platform-abbreviation.outputs.platform }}.sh \
${{ steps.cargo-flags.outputs.flags }}
working-directory: rust/pact_mock_server_cli

- name: Build verifier CLI
if: |
github.event_name == 'push' ||
github.event_name == 'pull_request' ||
startsWith(github.ref, 'refs/tags/pact_verifier_cli')
shell: bash
run: |
./release-${{ steps.platform-abbreviation.outputs.platform }}.sh \
${{ steps.cargo-flags.outputs.flags }}
working-directory: rust/pact_verifier_cli
- if: startsWith(github.ref, 'refs/tags/libpact_ffi') && runner.os == 'Linux'
run: ./release-linux.sh
working-directory: rust/pact_ffi
- if: startsWith(github.ref, 'refs/tags/libpact_ffi') && runner.os == 'Windows'
run: ./release-win.sh
shell: bash
working-directory: rust/pact_ffi
- if: startsWith(github.ref, 'refs/tags/libpact_ffi') && runner.os == 'macOS'
run: ./release-osx.sh

- name: Build FFI library
if: |
github.event_name == 'push' ||
github.event_name == 'pull_request' ||
startsWith(github.ref, 'refs/tags/libpact_ffi')
shell: bash
run: |
./release-${{ steps.platform-abbreviation.outputs.platform }}.sh \
${{ steps.cargo-flags.outputs.flags }}
working-directory: rust/pact_ffi

- name: Upload the artifacts
if: startsWith(github.ref, 'refs/tags/libpact_ffi') || startsWith(github.ref, 'refs/tags/pact_verifier_cli') || startsWith(github.ref, 'refs/tags/pact_mock_server_cli')
uses: actions/upload-artifact@v3.1.2
if: |
startsWith(github.ref, 'refs/tags/libpact_ffi') ||
startsWith(github.ref, 'refs/tags/pact_verifier_cli') ||
startsWith(github.ref, 'refs/tags/pact_mock_server_cli')
uses: actions/upload-artifact@v4
with:
name: release-artifacts
name: release-artifacts-${{ matrix.operating-system }}
path: rust/release_artifacts
if-no-files-found: error

publish:
runs-on: ubuntu-latest
if: |
startsWith(github.ref, 'refs/tags/libpact_ffi') ||
startsWith(github.ref, 'refs/tags/pact_verifier_cli') ||
startsWith(github.ref, 'refs/tags/pact_mock_server_cli')
needs: build-release

steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
pattern: release-artifacts-*
path: rust/release_artifacts

- name: Upload Release Assets
if: startsWith(github.ref, 'refs/tags/libpact_ffi') || startsWith(github.ref, 'refs/tags/pact_verifier_cli') || startsWith(github.ref, 'refs/tags/pact_mock_server_cli')
uses: svenstaro/upload-release-action@2.5.0
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: rust/release_artifacts/*
Expand Down
181 changes: 115 additions & 66 deletions rust/pact_ffi/release-linux.sh
@@ -1,75 +1,124 @@
#!/bin/bash -x
#!/bin/bash

set -e
set -x

echo -- Setup directories --
cargo clean
mkdir -p ../release_artifacts

echo -- Build the Docker build image --
docker build -f Dockerfile.linux-build -t pact-ffi-build .

echo -- Build the release artifacts --
docker run -t --rm --user "$(id -u)":"$(id -g)" -v $(pwd)/..:/workspace -w /workspace/pact_ffi pact-ffi-build -c 'cargo build --release'
gzip -c ../target/release/libpact_ffi.so > ../release_artifacts/libpact_ffi-linux-x86_64.so.gz
openssl dgst -sha256 -r ../release_artifacts/libpact_ffi-linux-x86_64.so.gz > ../release_artifacts/libpact_ffi-linux-x86_64.so.gz.sha256
gzip -c ../target/release/libpact_ffi.a > ../release_artifacts/libpact_ffi-linux-x86_64.a.gz
openssl dgst -sha256 -r ../release_artifacts/libpact_ffi-linux-x86_64.a.gz > ../release_artifacts/libpact_ffi-linux-x86_64.a.gz.sha256

echo -- Generate the header files --
rustup toolchain install nightly
rustup component add rustfmt --toolchain nightly
rustup run nightly cbindgen \
--config cbindgen.toml \
--crate pact_ffi \
--output include/pact.h
rustup run nightly cbindgen \
--config cbindgen-c++.toml \
--crate pact_ffi \
--output include/pact-cpp.h
cp include/*.h ../release_artifacts

echo -- Build the musl release artifacts --
cargo install cross@0.2.5
cross build --release --target=x86_64-unknown-linux-musl
gzip -c ../target/x86_64-unknown-linux-musl/release/libpact_ffi.a > ../release_artifacts/libpact_ffi-linux-x86_64-musl.a.gz
openssl dgst -sha256 -r ../release_artifacts/libpact_ffi-linux-x86_64-musl.a.gz > ../release_artifacts/libpact_ffi-linux-x86_64-musl.a.gz.sha256

mkdir tmp
cp ../target/x86_64-unknown-linux-musl/release/libpact_ffi.a tmp/
docker run --platform=linux/amd64 --rm -v $PWD/tmp:/scratch alpine /bin/sh -c 'apk add --no-cache musl-dev gcc && \
RUST_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")/.." && pwd )"

source "$RUST_DIR/scripts/gzip-and-sum.sh"
ARTIFACTS_DIR=${ARTIFACTS_DIR:-"$RUST_DIR/release_artifacts"}
mkdir -p "$ARTIFACTS_DIR"
export CARGO_TARGET_DIR=${CARO_TARGET_DIR:-"$RUST_DIR/target"}

# All flags passed to this script are passed to cargo.
cargo_flags=( "$@" )

# Build the x86_64 GNU linux release
build_x86_64_gnu() {
cargo build --target x86_64-unknown-linux-gnu "${cargo_flags[@]}"

if [[ "${cargo_flags[*]}" =~ "--release" ]]; then
gzip_and_sum \
"$CARGO_TARGET_DIR/x86_64-unknown-linux-gnu/release/libpact_ffi.a" \
"$ARTIFACTS_DIR/libpact_ffi-linux-x86_64.a.gz"
gzip_and_sum \
"$CARGO_TARGET_DIR/x86_64-unknown-linux-gnu/release/libpact_ffi.so" \
"$ARTIFACTS_DIR/libpact_ffi-linux-x86_64.so.gz"
fi
}

build_x86_64_musl() {
sudo apt-get install -y musl-tools
cargo build --target x86_64-unknown-linux-musl "${cargo_flags[@]}"

if [[ "${cargo_flags[*]}" =~ "--release" ]]; then
BUILD_SCRIPT=$(cat <<EOM
apk add --no-cache musl-dev gcc && \
cd /scratch && \
ar -x libpact_ffi.a && \
gcc -shared *.o -o libpact_ffi.so && \
rm -f *.o'
ar -x libpact_ffi.a && \
gcc -shared *.o -o libpact_ffi.so && \
rm -f *.o
EOM
)

docker run \
--platform=linux/amd64 \
--rm \
-v "$CARGO_TARGET_DIR/x86_64-unknown-linux-musl/release:/scratch" \
alpine \
/bin/sh -c "$BUILD_SCRIPT"

gzip -c tmp/libpact_ffi.so > ../release_artifacts/libpact_ffi-linux-x86_64-musl.so.gz
openssl dgst -sha256 -r ../release_artifacts/libpact_ffi-linux-x86_64-musl.so.gz > ../release_artifacts/libpact_ffi-linux-x86_64-musl.so.gz.sha256
rm -rf tmp
gzip_and_sum \
"$CARGO_TARGET_DIR/x86_64-unknown-linux-musl/release/libpact_ffi.a" \
"$ARTIFACTS_DIR/libpact_ffi-linux-x86_64-musl.a.gz"
gzip_and_sum \
"$CARGO_TARGET_DIR/x86_64-unknown-linux-musl/release/libpact_ffi.so" \
"$ARTIFACTS_DIR/libpact_ffi-linux-x86_64-musl.so.gz"
fi
}

install_cross() {
cargo install cross@0.2.5
}

echo -- Build the musl aarch64 release artifacts --
cargo clean
cross build --release --target=aarch64-unknown-linux-musl
gzip -c ../target/aarch64-unknown-linux-musl/release/libpact_ffi.a > ../release_artifacts/libpact_ffi-linux-aarch64-musl.a.gz
openssl dgst -sha256 -r ../release_artifacts/libpact_ffi-linux-aarch64-musl.a.gz > ../release_artifacts/libpact_ffi-linux-aarch64-musl.a.gz.sha256
build_aarch64_gnu() {
install_cross
cross build --target aarch64-unknown-linux-gnu "${cargo_flags[@]}"

mkdir tmp
cp ../target/aarch64-unknown-linux-musl/release/libpact_ffi.a tmp/
docker run --platform=linux/arm64 --rm -v $PWD/tmp:/scratch alpine /bin/sh -c 'apk add --no-cache musl-dev gcc && \
if [[ "${cargo_flags[*]}" =~ "--release" ]]; then
gzip_and_sum \
"$CARGO_TARGET_DIR/aarch64-unknown-linux-gnu/release/libpact_ffi.a" \
"$ARTIFACTS_DIR/libpact_ffi-linux-aarch64.a.gz"
gzip_and_sum \
"$CARGO_TARGET_DIR/aarch64-unknown-linux-gnu/release/libpact_ffi.so" \
"$ARTIFACTS_DIR/libpact_ffi-linux-aarch64.so.gz"
fi
}

build_aarch64_musl() {
install_cross
cross build --target aarch64-unknown-linux-musl "${cargo_flags[@]}"

if [[ "${cargo_flags[*]}" =~ "--release" ]]; then
BUILD_SCRIPT=$(cat <<EOM
apk add --no-cache musl-dev gcc && \
cd /scratch && \
ar -x libpact_ffi.a && \
gcc -shared *.o -o libpact_ffi.so && \
rm -f *.o'

gzip -c tmp/libpact_ffi.so > ../release_artifacts/libpact_ffi-linux-aarch64-musl.so.gz
openssl dgst -sha256 -r ../release_artifacts/libpact_ffi-linux-aarch64-musl.so.gz > ../release_artifacts/libpact_ffi-linux-aarch64-musl.so.gz.sha256
rm -rf tmp

echo -- Build the aarch64 release artifacts --
cargo clean
cross build --target aarch64-unknown-linux-gnu --release
gzip -c ../target/aarch64-unknown-linux-gnu/release/libpact_ffi.so > ../release_artifacts/libpact_ffi-linux-aarch64.so.gz
openssl dgst -sha256 -r ../release_artifacts/libpact_ffi-linux-aarch64.so.gz > ../release_artifacts/libpact_ffi-linux-aarch64.so.gz.sha256
gzip -c ../target/aarch64-unknown-linux-gnu/release/libpact_ffi.a > ../release_artifacts/libpact_ffi-linux-aarch64.a.gz
openssl dgst -sha256 -r ../release_artifacts/libpact_ffi-linux-aarch64.a.gz > ../release_artifacts/libpact_ffi-linux-aarch64.a.gz.sha256
ar -x libpact_ffi.a && \
gcc -shared *.o -o libpact_ffi.so && \
rm -f *.o
EOM
)

docker run \
--platform=linux/arm64 \
--rm \
-v "$CARGO_TARGET_DIR/aarch64-unknown-linux-musl/release:/scratch" \
alpine \
/bin/sh -c "$BUILD_SCRIPT"

gzip_and_sum \
"$CARGO_TARGET_DIR/aarch64-unknown-linux-musl/release/libpact_ffi.a" \
"$ARTIFACTS_DIR/libpact_ffi-linux-aarch64-musl.a.gz"
gzip_and_sum \
"$CARGO_TARGET_DIR/aarch64-unknown-linux-musl/release/libpact_ffi.so" \
"$ARTIFACTS_DIR/libpact_ffi-linux-aarch64-musl.so.gz"
fi
}

build_header() {
rustup toolchain install nightly
rustup run nightly cbindgen \
--config cbindgen.toml \
--crate pact_ffi \
--output "$ARTIFACTS_DIR/pact.h"
rustup run nightly cbindgen \
--config cbindgen-c++.toml \
--crate pact_ffi \
--output "$ARTIFACTS_DIR/pact-cpp.h"
}

build_x86_64_gnu
build_x86_64_musl
build_aarch64_gnu
build_aarch64_musl
build_header

0 comments on commit 7732a63

Please sign in to comment.