Continuous Deployment #233
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Continuous Deployment | |
| on: | |
| workflow_dispatch: | |
| push: | |
| tags: | |
| - "*" | |
| env: | |
| CICD_INTERMEDIATES_DIR: "_cd-intermediates" | |
| jobs: | |
| crate_metadata: | |
| name: extract crate metadata | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: extract crate information | |
| id: crate_metadata | |
| run: | | |
| rustup update stable | |
| cargo metadata --no-deps --format-version 1 | jq -r ' | |
| .packages[0] | | |
| [ | |
| "version=" + .version, | |
| "maintainer=" + (.authors[0] // ""), | |
| "homepage=" + (.homepage // ""), | |
| "msrv=" + (.rust_version // "") | |
| ] | | |
| join("\n") | |
| ' | tee -a $GITHUB_OUTPUT | |
| outputs: | |
| name: "mago" | |
| bin-name: "mago" | |
| version: ${{ steps.crate_metadata.outputs.version }} | |
| maintainer: ${{ steps.crate_metadata.outputs.maintainer }} | |
| homepage: ${{ steps.crate_metadata.outputs.homepage }} | |
| msrv: ${{ steps.crate_metadata.outputs.msrv }} | |
| min_version: | |
| name: Minimum supported rust version | |
| runs-on: ubuntu-latest | |
| needs: crate_metadata | |
| steps: | |
| - name: Checkout source code | |
| uses: actions/checkout@v4 | |
| - name: Install rust toolchain (v${{ needs.crate_metadata.outputs.msrv }}) | |
| uses: dtolnay/rust-toolchain@master | |
| with: | |
| toolchain: ${{ needs.crate_metadata.outputs.msrv }} | |
| - name: Run tests | |
| run: cargo test --workspace --locked --all-targets | |
| build: | |
| name: ${{ matrix.job.target }} (${{ matrix.job.os }}) | |
| runs-on: ${{ matrix.job.os }} | |
| needs: crate_metadata | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| job: | |
| # Each job in this matrix defines a build target. The following custom keys control the pipeline steps: | |
| # - `test: true`: Enables the test suite to be run for this build. | |
| # - `wasm: true`: Triggers an additional WebAssembly build and packaging for this release. | |
| # - `debian-package: true`: Generates a Debian package for the release. | |
| # Tier 1 targets: | |
| ## Windows MSVC: x86_64 | |
| - { target: x86_64-pc-windows-msvc, os: windows-latest, test: true, pgo: true } | |
| ## macOS: aarch64, x86_64 | |
| - { target: aarch64-apple-darwin, os: macos-latest, test: true, pgo: true } | |
| - { target: x86_64-apple-darwin, os: macos-latest, test: true, pgo: true } | |
| ## Linux: aarch64, x86_64 | |
| - { target: aarch64-unknown-linux-gnu, os: ubuntu-latest, test: true, debian-package: true } | |
| - { target: aarch64-unknown-linux-musl, os: ubuntu-latest, test: true } | |
| - { target: x86_64-unknown-linux-gnu, os: ubuntu-latest, test: true, wasm: true, debian-package: true } | |
| - { target: x86_64-unknown-linux-musl, os: ubuntu-latest, test: true } | |
| # Tier 2 targets: | |
| # Windows MinGW: x86_64 | |
| - { target: x86_64-pc-windows-gnu, os: windows-latest } | |
| # FreeBSD: x86_64 | |
| - { target: x86_64-unknown-freebsd, os: ubuntu-latest } | |
| # Linux: arm, armv7, powerpc, powerpc64, powerpc64le, s390x | |
| - { target: arm-unknown-linux-gnueabi, os: ubuntu-latest } | |
| - { target: arm-unknown-linux-gnueabihf, os: ubuntu-latest } | |
| - { target: arm-unknown-linux-musleabi, os: ubuntu-latest } | |
| - { target: arm-unknown-linux-musleabihf, os: ubuntu-latest } | |
| - { target: armv7-unknown-linux-gnueabihf, os: ubuntu-latest } | |
| - { target: armv7-unknown-linux-musleabihf, os: ubuntu-latest } | |
| - { target: powerpc-unknown-linux-gnu, os: ubuntu-latest } | |
| - { target: powerpc64-unknown-linux-gnu, os: ubuntu-latest } | |
| - { target: powerpc64le-unknown-linux-gnu, os: ubuntu-latest } | |
| - { target: s390x-unknown-linux-gnu, os: ubuntu-latest } | |
| env: | |
| BUILD_CMD: cargo | |
| steps: | |
| - name: checkout source code | |
| uses: actions/checkout@v4 | |
| - name: set version env variable | |
| id: version | |
| shell: bash | |
| run: echo "VERSION=${{ needs.crate_metadata.outputs.version }}" >> $GITHUB_OUTPUT | |
| - name: Install Prerequisites | |
| if: contains(matrix.job.os, 'ubuntu') | |
| shell: bash | |
| run: | | |
| sudo apt-get -y update | |
| sudo apt-get remove -y libssl-dev | |
| case ${{ matrix.job.target }} in | |
| arm-unknown-linux-*) sudo apt-get -y install gcc-arm-linux-gnueabihf ;; | |
| aarch64-unknown-linux-gnu) sudo apt-get -y install gcc-aarch64-linux-gnu ;; | |
| arm-unknown-linux-gnueabihf) sudo apt-get -y install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf qemu-user ;; | |
| esac | |
| - name: install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: ${{ needs.crate_metadata.outputs.msrv }} | |
| targets: ${{ matrix.job.target }} | |
| - name: install PGO tools | |
| if: matrix.job.pgo | |
| shell: bash | |
| run: | | |
| rustup component add llvm-tools-preview | |
| cargo install cargo-pgo | |
| - name: install cross | |
| if: startsWith(matrix.job.os, 'ubuntu') | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cross | |
| - name: overwrite build command env variable (for cross) | |
| if: startsWith(matrix.job.os, 'ubuntu') | |
| shell: bash | |
| run: echo "BUILD_CMD=cross" >> $GITHUB_ENV | |
| - name: Configure cross-rs container image for glibc 2.17 | |
| if: contains(matrix.job.target, 'linux-gnu') | |
| shell: bash | |
| run: | | |
| IMAGE="" | |
| case ${{ matrix.job.target }} in | |
| x86_64-unknown-linux-gnu) IMAGE="quay.io/pypa/manylinux2014_x86_64" ;; | |
| aarch64-unknown-linux-gnu) IMAGE="quay.io/pypa/manylinux2014_aarch64" ;; | |
| powerpc64le-unknown-linux-gnu) IMAGE="quay.io/pypa/manylinux2014_ppc64le" ;; | |
| s390x-unknown-linux-gnu) IMAGE="quay.io/pypa/manylinux2014_s390x" ;; | |
| esac | |
| if [[ -n "$IMAGE" ]]; then | |
| echo "Using custom image for glibc 2.17: $IMAGE" | |
| echo "CROSS_IMAGE=$IMAGE" >> $GITHUB_ENV | |
| else | |
| echo "::warning:: No manylinux2014 image found for target ${{ matrix.job.target }}. Build will use default cross image, which may have a newer glibc." | |
| fi | |
| - name: show version information (Rust, cargo, GCC) | |
| shell: bash | |
| run: | | |
| set -x | |
| gcc --version || true | |
| ldd --version || true | |
| rustup -V | |
| rustup toolchain list | |
| rustup default | |
| cargo -V | |
| rustc -V | |
| - name: setup PHP for PGO profiling | |
| if: matrix.job.pgo | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.3' | |
| tools: composer | |
| - name: setup PHP corpus for PGO profiling | |
| if: matrix.job.pgo | |
| shell: bash | |
| run: | | |
| cd corpus | |
| composer install --ignore-platform-reqs | |
| cd .. | |
| - name: build | |
| shell: bash | |
| run: | | |
| if [[ "${{ matrix.job.pgo }}" == "true" ]]; then | |
| cargo pgo build -- --target=${{ matrix.job.target }} | |
| cargo pgo run -- -- --workspace corpus/ analyze --reporting-format count || true | |
| cargo pgo run --keep-profiles -- -- --workspace corpus/ lint --reporting-format count || true | |
| cargo pgo run --keep-profiles -- -- --workspace corpus/ fmt --check || true | |
| cargo pgo optimize -- build --target=${{ matrix.job.target }} | |
| else | |
| $BUILD_CMD build --locked --release --target=${{ matrix.job.target }} | |
| fi | |
| - name: set binary name | |
| id: bin | |
| shell: bash | |
| run: | | |
| EXE_suffix="" | |
| case ${{ matrix.job.target }} in | |
| *-pc-windows-*) EXE_suffix=".exe" ;; | |
| esac; | |
| BIN_NAME="${{ needs.crate_metadata.outputs.bin-name }}${EXE_suffix}" | |
| BIN_PATH="target/${{ matrix.job.target }}/release/${BIN_NAME}" | |
| echo "BIN_PATH=${BIN_PATH}" >> $GITHUB_OUTPUT | |
| echo "BIN_NAME=${BIN_NAME}" >> $GITHUB_OUTPUT | |
| - name: check GLIBC version requirements | |
| if: contains(matrix.job.target, 'linux-gnu') | |
| shell: bash | |
| run: | | |
| echo "binary for target '${{ matrix.job.target }}' requires the following GLIBC versions:" | |
| strings "${{ steps.bin.outputs.BIN_PATH }}" | grep GLIBC_ || echo "No GLIBC version strings found." | |
| - name: run tests | |
| if: matrix.job.test && !startsWith(github.ref, 'refs/pull/') | |
| shell: bash | |
| run: $BUILD_CMD test --workspace --locked --target=${{ matrix.job.target }} | |
| - name: Install wasm-pack and build WASM | |
| if: matrix.job.wasm && !startsWith(github.ref, 'refs/pull/') | |
| run: | | |
| cargo install wasm-pack --version 0.13.1 --locked | |
| cd crates/wasm | |
| wasm-pack build -d pkg --release | |
| cd ../.. | |
| WASM_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/wasm" | |
| mkdir -p "${WASM_STAGING}" | |
| cp -r crates/wasm/pkg/* "${WASM_STAGING}/" | |
| - name: create tarball (main binary) | |
| id: package | |
| shell: bash | |
| run: | | |
| VERSION="${{ steps.version.outputs.VERSION }}" | |
| TARGET="${{ matrix.job.target }}" | |
| PKG_SUFFIX=".tar.gz" | |
| case "$TARGET" in | |
| *-pc-windows-msvc) PKG_SUFFIX=".zip" ;; | |
| esac | |
| PKG_NAME="mago-${VERSION}-${TARGET}${PKG_SUFFIX}" | |
| echo "PKG_NAME=${PKG_NAME}" >> $GITHUB_OUTPUT | |
| PKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/package" | |
| ARCHIVE_DIR="${PKG_STAGING}/mago-${VERSION}-${TARGET}/" | |
| mkdir -p "${ARCHIVE_DIR}" | |
| # Binary | |
| cp "${{ steps.bin.outputs.BIN_PATH }}" "$ARCHIVE_DIR" | |
| # Docs and licenses | |
| cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "$ARCHIVE_DIR" || true | |
| pushd "${PKG_STAGING}/" >/dev/null | |
| case "$PKG_SUFFIX" in | |
| .zip) | |
| 7z -y a "${PKG_NAME}" "mago-${VERSION}-${TARGET}/*" | |
| ;; | |
| .tar.gz) | |
| tar czf "${PKG_NAME}" "mago-${VERSION}-${TARGET}"/* | |
| ;; | |
| esac | |
| popd >/dev/null | |
| echo "PKG_PATH=${PKG_STAGING}/${PKG_NAME}" >> $GITHUB_OUTPUT | |
| - name: create WASM tarball | |
| id: wasm_package | |
| if: matrix.job.wasm && !startsWith(github.ref, 'refs/pull/') | |
| shell: bash | |
| run: | | |
| VERSION="${{ steps.version.outputs.VERSION }}" | |
| # Since WASM is universal, just name it 'mago-{VERSION}-wasm.tar.gz' | |
| WASM_PKG_NAME="mago-${VERSION}-wasm.tar.gz" | |
| echo "WASM_PKG_NAME=${WASM_PKG_NAME}" >> $GITHUB_OUTPUT | |
| WASM_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/wasm" | |
| pushd "${WASM_STAGING}" >/dev/null | |
| tar czf "${WASM_PKG_NAME}" mago_wasm.d.ts mago_wasm.js mago_wasm_bg.js mago_wasm_bg.wasm package.json | |
| popd >/dev/null | |
| echo "WASM_PKG_PATH=${WASM_STAGING}/${WASM_PKG_NAME}" >> $GITHUB_OUTPUT | |
| - name: create Debian package | |
| id: debian-package | |
| shell: bash | |
| if: matrix.job.debian-package && !startsWith(github.ref, 'refs/pull/') | |
| run: | | |
| VERSION="${{ steps.version.outputs.VERSION }}" | |
| TARGET="${{ matrix.job.target }}" | |
| # Derive arch from target: | |
| case "$TARGET" in | |
| *x86_64*) DPKG_ARCH="amd64" ;; | |
| *aarch64*|*arm64*) DPKG_ARCH="arm64" ;; | |
| *arm*hf*) DPKG_ARCH="armhf" ;; | |
| *arm*) DPKG_ARCH="armel" ;; | |
| *powerpc64*) DPKG_ARCH="ppc64el" ;; | |
| *powerpc*) DPKG_ARCH="powerpc" ;; | |
| *s390x*) DPKG_ARCH="s390x" ;; | |
| esac | |
| DPKG_NAME="mago-${VERSION}-${TARGET}.deb" | |
| echo "DPKG_NAME=${DPKG_NAME}" >> $GITHUB_OUTPUT | |
| DPKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/debian-package" | |
| DPKG_DIR="${DPKG_STAGING}/dpkg" | |
| mkdir -p "${DPKG_DIR}" | |
| install -Dm755 "${{ steps.bin.outputs.BIN_PATH }}" "${DPKG_DIR}/usr/bin/${{ steps.bin.outputs.BIN_NAME }}" | |
| install -Dm644 "README.md" "${DPKG_DIR}/usr/share/doc/mago/README.md" || true | |
| install -Dm644 "LICENSE-MIT" "${DPKG_DIR}/usr/share/doc/mago/LICENSE-MIT" || true | |
| install -Dm644 "LICENSE-APACHE" "${DPKG_DIR}/usr/share/doc/mago/LICENSE-APACHE" || true | |
| mkdir -p "${DPKG_DIR}/DEBIAN" | |
| cat > "${DPKG_DIR}/DEBIAN/control" <<EOF | |
| Package: mago | |
| Version: ${VERSION} | |
| Section: devel | |
| Priority: optional | |
| Maintainer: ${{ needs.crate_metadata.outputs.maintainer }} | |
| Homepage: ${{ needs.crate_metadata.outputs.homepage }} | |
| Architecture: ${DPKG_ARCH} | |
| Description: Mago is a toolchain for PHP that aims to provide a set of tools to help developers write better code. | |
| EOF | |
| DPKG_PATH="${DPKG_STAGING}/${DPKG_NAME}" | |
| echo "DPKG_PATH=${DPKG_PATH}" >> $GITHUB_OUTPUT | |
| fakeroot dpkg-deb --build "${DPKG_DIR}" "${DPKG_PATH}" | |
| - name: "Artifact upload: tarball" | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ steps.package.outputs.PKG_NAME }} | |
| path: ${{ steps.package.outputs.PKG_PATH }} | |
| - name: "Artifact upload: WASM" | |
| if: matrix.job.wasm && !startsWith(github.ref, 'refs/pull/') | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ steps.wasm_package.outputs.WASM_PKG_NAME }} | |
| path: ${{ steps.wasm_package.outputs.WASM_PKG_PATH }} | |
| - name: "Artifact upload: Debian package" | |
| uses: actions/upload-artifact@v4 | |
| if: steps.debian-package.outputs.DPKG_NAME | |
| with: | |
| name: ${{ steps.debian-package.outputs.DPKG_NAME }} | |
| path: ${{ steps.debian-package.outputs.DPKG_PATH }} | |
| - name: check for release | |
| id: is-release | |
| shell: bash | |
| run: | | |
| unset IS_RELEASE ; if [[ $GITHUB_REF =~ ^refs/tags/[0-9].* ]]; then IS_RELEASE='true' ; fi | |
| echo "IS_RELEASE=${IS_RELEASE}" >> $GITHUB_OUTPUT | |
| - name: publish archives and packages | |
| uses: softprops/action-gh-release@v2 | |
| if: steps.is-release.outputs.IS_RELEASE | |
| with: | |
| files: | | |
| ${{ steps.package.outputs.PKG_PATH }} | |
| ${{ steps.debian-package.outputs.DPKG_PATH }} | |
| ${{ steps.wasm_package.outputs.WASM_PKG_PATH }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |