Skip to content

feat: add isolated build tools #5893

feat: add isolated build tools

feat: add isolated build tools #5893

Workflow file for this run

on:
push:
tags:
- "v*.*.*"
branches:
- main
paths-ignore:
- "docs/**"
- "mkdocs.yml"
- "*.md"
workflow_dispatch:
pull_request:
paths-ignore:
- "docs/**"
- "mkdocs.yml"
- "*.md"
name: Rust
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
RUST_LOG: info
RUST_BACKTRACE: 1
RUSTFLAGS: "-D warnings"
CARGO_TERM_COLOR: always
CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
XDG_CACHE_HOME: ${{ github.workspace }}/.cache
jobs:
check-rustdoc-links:
name: Check intra-doc links
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: Swatinem/rust-cache@v2
with:
save-if: false
# - name: Run sccache-cache
# uses: mozilla-actions/[email protected]
- uses: actions-rust-lang/setup-rust-toolchain@v1
- run: |
for package in $(cargo metadata --no-deps --format-version=1 | jq -r '.packages[] | .name'); do
cargo rustdoc -p "$package" --all-features -- -D warnings -W unreachable-pub
done
format:
name: Cargo Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: rustfmt
- name: Run rustfmt
uses: actions-rust-lang/rustfmt@v1
lint:
name: Cargo Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: clippy
- uses: Swatinem/rust-cache@v2
with:
save-if: false
- name: Run clippy
run: cargo clippy --all-targets --workspace
crate_metadata:
name: Extract crate metadata
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Extract crate information
id: crate_metadata
run: |
cargo metadata --no-deps --format-version 1 | jq -r '"name=" + (.packages[] | select(.name == "pixi") | .name)' | tee -a $GITHUB_OUTPUT
cargo metadata --no-deps --format-version 1 | jq -r '"version=" + (.packages[] | select(.name == "pixi") | .version)' | tee -a $GITHUB_OUTPUT
cargo metadata --no-deps --format-version 1 | jq -r '"maintainer=" + (.packages[] | select(.name == "pixi") | .authors[0])' | tee -a $GITHUB_OUTPUT
cargo metadata --no-deps --format-version 1 | jq -r '"homepage=" + (.packages[] | select(.name == "pixi") | .homepage)' | tee -a $GITHUB_OUTPUT
outputs:
name: ${{ steps.crate_metadata.outputs.name }}
version: ${{ steps.crate_metadata.outputs.version }}
maintainer: ${{ steps.crate_metadata.outputs.maintainer }}
homepage: ${{ steps.crate_metadata.outputs.homepage }}
# Checks for dependencies that are not used in the codebase
cargo-machete:
name: Cargo Machete
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Machete
uses: bnjbvr/cargo-machete@main
cargo-test:
name: Cargo Test | ${{ matrix.name }}
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- {
name: "Linux",
target: x86_64-unknown-linux-musl,
os: "${{ contains(github.event.pull_request.labels.*.name, 'ci:free') && 'ubuntu-latest' || '8core_ubuntu_latest_runner' }}",
}
- { name: "macOS", target: x86_64-apple-darwin, os: macos-13 }
- { name: "macOS-arm", target: aarch64-apple-darwin, os: macos-14 }
- {
name: "Windows",
target: x86_64-pc-windows-msvc,
os: "${{ contains(github.event.pull_request.labels.*.name, 'ci:free') && 'windows-latest' || '16core_windows_latest_runner' }}",
}
steps:
- uses: actions/checkout@v4
- uses: prefix-dev/[email protected]
with:
cache: true
- uses: Swatinem/rust-cache@v2
with:
workspaces: ". -> target-pixi"
key: ${{ hashFiles('pixi.lock') }}
- name: Test pixi
run: pixi run test-slow
build:
name: Build Binary | ${{ matrix.name }}
runs-on: ${{ matrix.os }}
needs: [crate_metadata]
strategy:
fail-fast: false
matrix:
include:
- name: "Linux-x86_64"
target: x86_64-unknown-linux-musl
os: "${{ contains(github.event.pull_request.labels.*.name, 'ci:free') && 'ubuntu-latest' || '8core_ubuntu_latest_runner' }}"
- name: "Linux-aarch64"
target: aarch64-unknown-linux-musl
os: ubuntu-latest
- name: "macOS-x86"
target: x86_64-apple-darwin
os: macos-13
- name: "macOS-arm"
target: aarch64-apple-darwin
os: macos-14
- name: "Windows"
target: x86_64-pc-windows-msvc
os: "${{ contains(github.event.pull_request.labels.*.name, 'ci:free') && 'windows-latest' || '16core_windows_latest_runner' }}"
- name: "Windows-arm"
target: aarch64-pc-windows-msvc
os: windows-latest
env:
#
# These are some environment variables that configure the build so that the binary size is reduced.
# Inspiration was taken from this blog: https://arusahni.net/blog/2020/03/optimizing-rust-binary-size.html
# They're only enable it on main and releases.
#
# Pick the profile to build, as defined in Cargo.toml
CARGO_PROFILE: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) && 'dist' || 'ci' }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
target: ${{ matrix.target }}
cache: false
- uses: taiki-e/setup-cross-toolchain-action@v1
with:
target: ${{ matrix.target }}
- name: Use static CRT on Windows
shell: bash
run: echo "RUSTFLAGS=${RUSTFLAGS} -C target-feature=+crt-static" >> "${GITHUB_ENV}"
if: endsWith(matrix.target, 'windows-msvc')
- uses: Swatinem/rust-cache@v2
- name: Setup | Install cargo-wix [Windows]
# aarch64 is only supported in wix 4.0 development builds
if: startsWith(matrix.name, 'Windows') && matrix.target != 'aarch64-pc-windows-msvc'
run: cargo install --version 0.3.8 cargo-wix
env:
# cargo-wix does not require static crt
RUSTFLAGS: ""
- name: Show version information (Rust, cargo, GCC)
shell: bash
run: |
gcc --version || true
rustup -V
rustup toolchain list
cargo -V
rustc -V
- name: Check for release
id: is-release
shell: bash
run: |
unset IS_RELEASE ; if [[ $GITHUB_REF =~ ^refs/tags/v[0-9].* ]]; then IS_RELEASE='true' ; fi
echo "IS_RELEASE=${IS_RELEASE}" >> $GITHUB_OUTPUT
- name: Use rustls on musl targets.
id: build-options
if: contains(matrix.target, '-musl')
run: |
echo "CARGO_BUILD_OPTIONS=${CARGO_BUILD_OPTIONS}" >> $GITHUB_OUTPUT
- name: Build on Linux / Mac
if: runner.os != 'Windows'
run: >
cargo build
--locked
--profile $CARGO_PROFILE
--features self_update
${{ steps.build-options.outputs.CARGO_BUILD_OPTIONS}}
- name: Build on Windows
if: runner.os == 'Windows'
run: >
cargo build
--locked
--profile $env:CARGO_PROFILE
--features self_update
${{ steps.build-options.outputs.CARGO_BUILD_OPTIONS}}
- name: Set binary name & path
id: bin
shell: bash
run: |
# Figure out suffix of binary
EXE_SUFFIX=""
case ${{ matrix.target }} in
*-pc-windows-*) EXE_SUFFIX=".exe" ;;
esac;
# Setup paths
BIN_NAME="${{ needs.crate_metadata.outputs.name }}${EXE_SUFFIX}"
BIN_PATH="target/${{ matrix.target }}/${CARGO_PROFILE}/${BIN_NAME}"
# Let subsequent steps know where to find the binary
{
echo "BIN_PATH=${BIN_PATH}"
echo "BIN_NAME=${BIN_NAME}"
echo "EXE_SUFFIX=${EXE_SUFFIX}"
} >> $GITHUB_OUTPUT
- name: Build msi Installer
if: startsWith(matrix.name, 'Windows') && matrix.target != 'aarch64-pc-windows-msvc'
run: >
cargo wix -v --no-build --nocapture -I install/windows/main.wxs
--profile $env:CARGO_PROFILE
--package pixi
--target ${{ matrix.target }}
--output target/wix/pixi-${{ matrix.target }}.msi
# Here we notarize the binary with a certificate from Apple
# To get a certificate, go to XCode and request a Developer ID certificate for the right team.
# Then export the certificate from XCode and copy it as base64 into the secrets.
# Using e.g. `openssl base64 -in ~/Desktop/DeveloperID.p12 | tr -d '\n' | pbcopy` (to copy to clipboard).
# The password is the password you used to export the certificate.
# The ident is the ident of the certificate, which you can find in the keychain.
# The apple id password is a app specific password that you can get on the apple website (https://support.apple.com/en-us/HT204397) (usually a UUID looking string)
# The team id is the team id of the Apple Developer Team.
- name: Notarize binary
# only execute this step when releasing, or on main branch and on macOS
if: startsWith(matrix.os, 'macOS-') && (github.ref == 'refs/heads/main' || steps.is-release.outputs.IS_RELEASE)
env:
APPLEID_TEAMID: ${{ secrets.APPLEID_TEAMID }}
APPLEID_USERNAME: ${{ secrets.APPLEID_USERNAME }}
APPLEID_PASSWORD: ${{ secrets.APPLEID_PASSWORD }}
DEVELOPER_ID_CERTIFICATE: ${{ secrets.DEVELOPER_ID_CERTIFICATE }}
DEVELOPER_ID_PASSWORD: ${{ secrets.DEVELOPER_ID_PASSWORD }}
DEVELOPER_ID_IDENT: ${{ secrets.DEVELOPER_ID_IDENT }}
KEYCHAIN_FILENAME: app-signing.keychain-db
BIN_PATH: ${{ steps.bin.outputs.BIN_PATH }}
run: |
export KEYCHAIN_ENTRY="AC_PASSWORD"
INSTALL_CERTIFICATE_PATH="$RUNNER_TEMP/install_certificate.p12"
KEYCHAIN_PATH="$RUNNER_TEMP/$KEYCHAIN_FILENAME"
# create temporary keychain
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
export KEYCHAIN_PASSWORD
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
echo -n "$DEVELOPER_ID_CERTIFICATE" | base64 --decode -o $INSTALL_CERTIFICATE_PATH
security import $INSTALL_CERTIFICATE_PATH -P "$DEVELOPER_ID_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
echo "Successfully imported Developer ID certificate into keychain"
# Add Apple Developer ID credentials to keychain
xcrun notarytool store-credentials "$KEYCHAIN_ENTRY" \
--team-id "$APPLEID_TEAMID" \
--apple-id "$APPLEID_USERNAME" \
--password "$APPLEID_PASSWORD" \
--keychain "$KEYCHAIN_PATH"
echo "Successfully added Apple Developer ID credentials to keychain"
echo "Now signing binary..."
# codesign binary
xcrun codesign --force --options=runtime --keychain "$KEYCHAIN_PATH" \
--timestamp --sign "$DEVELOPER_ID_IDENT" --verbose "$BIN_PATH" \
--identifier "dev.prefix.pixi"
zip pixi.zip ${BIN_PATH}
# notarize binary
xcrun notarytool submit pixi.zip --keychain-profile "$KEYCHAIN_ENTRY" --wait
- name: Create tarball
id: package
shell: bash
run: |
PKG_suffix=".tar.gz" ; case ${{ matrix.target }} in *-pc-windows-*) PKG_suffix=".zip" ;; esac;
PKG_BASENAME=${{ needs.crate_metadata.outputs.name }}-${{ matrix.target }}
PKG_NAME=${PKG_BASENAME}${PKG_suffix}
echo "PKG_NAME=${PKG_NAME}" >> $GITHUB_OUTPUT
PKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/package"
mkdir -p "${PKG_STAGING}"
# Binary
cp "${{ steps.bin.outputs.BIN_PATH }}" "$PKG_STAGING"
# README, LICENSE and CHANGELOG files
# cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "CHANGELOG.md" "$PKG_STAGING"
# base compressed package
pushd "${PKG_STAGING}/" >/dev/null
case ${{ matrix.target }} in
*-pc-windows-*) 7z -y a "${PKG_NAME}" ./* | tail -2 ;;
*) tar czf "${PKG_NAME}" ./* ;;
esac;
popd >/dev/null
cp "${{ steps.bin.outputs.BIN_PATH }}" "$PKG_STAGING/pixi-${{ matrix.target }}${{ steps.bin.outputs.EXE_SUFFIX }}"
# Let subsequent steps know where to find the compressed package
echo "PKG_PATH=${PKG_STAGING}/${PKG_NAME}" >> $GITHUB_OUTPUT
echo "BIN_PATH=$PKG_STAGING/pixi-${{ matrix.target }}${{ steps.bin.outputs.EXE_SUFFIX }}" >> $GITHUB_OUTPUT
- name: "Artifact upload: tarball"
uses: actions/upload-artifact@master
with:
name: ${{ steps.package.outputs.PKG_NAME }}
path: ${{ steps.package.outputs.PKG_PATH }}
- name: "Artifact upload: binary"
uses: actions/upload-artifact@master
with:
name: pixi-${{ matrix.target }}${{ steps.bin.outputs.EXE_SUFFIX }}
path: ${{ steps.package.outputs.BIN_PATH }}
- name: "Artifact upload: windows installer"
if: startsWith(matrix.name, 'Windows') && matrix.target != 'aarch64-pc-windows-msvc'
uses: actions/upload-artifact@v4
with:
name: pixi-${{ matrix.target }}.msi
path: target/wix/pixi-${{ matrix.target }}.msi
- name: Publish packages
uses: softprops/action-gh-release@v2
if: steps.is-release.outputs.IS_RELEASE
with:
draft: true
files: |
${{ steps.package.outputs.PKG_PATH }}
${{ steps.package.outputs.BIN_PATH }}
target/wix/pixi-${{ matrix.target }}.msi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
downstream_tests:
name: "Test examples, downstream projects and integration"
needs:
- build
uses: ./.github/workflows/test_downstream.yml
export-filter:
name: Only run example tests if relevant code or manifests have changed
runs-on: ubuntu-20.04
needs:
- build
outputs:
exports: ${{ steps.filter.outputs.exports }}
steps:
- name: checkout repo
uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
exports:
- src/cli/project/export/conda_environment.rs
- src/cli/project/export/test-data/testenv/*
- examples/pypi-source-deps/*
- examples/pypi-custom-registry/*
- examples/pypi-find-links/*
- examples/docker/*
export_tests:
name: "Export tests"
needs: export-filter
if: ${{ needs.export-filter.outputs.exports == 'true' }}
uses: ./.github/workflows/test_exports.yml
test_common_wheels:
name: "Test installation of common wheels"
needs:
- build
uses: ./.github/workflows/test_common_wheels.yml