diff --git a/.github/scripts/gen_dockerfile.sh b/.github/scripts/gen_dockerfile.sh deleted file mode 100755 index 512e9700e..000000000 --- a/.github/scripts/gen_dockerfile.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -export filename="Dockerfile" -rm -f $filename -touch $filename - -if [ $(echo $full_tgtname | cut -d ':' -f 1) = "rhel" ]; then - export maj_version=$(echo $full_tgtname | cut -d ':' -f 2) - export full_tgtname=redhat/ubi$(echo $maj_version | cut -d '.' -f 1):$(echo $full_tgtname | cut -d ':' -f 2) - if [ $(echo $full_tgtname | cut -d ':' -f 2 | cut -d '.' -f 1) = '9' ]; then - if [ $(echo $full_tgtname | cut -d ':' -f 2 | cut -d '.' -f 2) = '0' ]; then - export full_tgtname=$full_tgtname.0 - fi - if [ $(echo $full_tgtname | cut -d ':' -f 2 | cut -d '.' -f 2) = '1' ]; then - export full_tgtname=$full_tgtname.0 - fi - fi -fi - -echo "FROM $full_tgtname" >> $filename -echo >> $filename -if [ $(echo $full_tgtname | cut -d ':' -f 1) = "centos" ]; then - echo "RUN sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo" >> $filename - echo "RUN sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo" >> $filename - echo "RUN sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo" >> $filename - - echo "RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*" >> $filename - echo "RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*" >> $filename - echo 'RUN yum group install "Development Tools" -y && yum clean all' >> $filename -fi -if [ $(echo $full_tgtname | cut -d ':' -f 1) = "ubuntu" ]; then - echo 'RUN apt update && apt -y install build-essential curl' >> $filename -fi -if [ $(echo $full_tgtname | cut -d ':' -f 1) = "fedora" ]; then - echo 'RUN dnf -y update && dnf -y install @development-tools' >> $filename -fi -if [ $(echo $full_tgtname | cut -d ':' -f 1) = "debian" ]; then - echo 'RUN apt update && apt -y install build-essential curl gcc make' >> $filename -fi -if [ $(echo $full_tgtname | cut -d ':' -f 1) = "almalinux" ]; then - if [ $(echo $full_tgtname | cut -d ':' -f 2 | cut -d '.' -f 1) = '8' ]; then - echo 'RUN rpm --import https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux' >> $filename - fi - echo 'RUN dnf -y update && dnf -y group install "Development Tools"' >> $filename -fi -if [[ $(echo $full_tgtname | cut -d ':' -f 1) == "redhat"* ]]; then - echo 'RUN dnf -y install gcc' >> $filename -fi -echo >> $filename -echo 'ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo' >> $filename -echo 'ENV PATH=$CARGO_HOME/bin:$PATH' >> $filename -echo >> $filename -echo 'RUN mkdir -p "$CARGO_HOME" && mkdir -p "$RUSTUP_HOME" && \' >> $filename -echo ' curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable && \' >> $filename -echo ' chmod -R a=rwX $CARGO_HOME' >> $filename -echo >> $filename -echo 'WORKDIR /source' >> $filename - diff --git a/.github/scripts/package.sh b/.github/scripts/package.sh deleted file mode 100755 index ed3ab3b9d..000000000 --- a/.github/scripts/package.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash - -# This script expects two optional arguments: -# 1. The target architecture (e.g., x86_64, aarch64) -# 2. The target OS (e.g., linux, windows, macos) - -if [[ "$GITHUB_REF" =~ ^refs/tags/v.*$ ]]; then - pkgver="$(echo $GITHUB_REF | sed -n 's/^refs\/tags\/v//p')" -else - pkgver="$(echo $GITHUB_REF | sed -n 's/^refs\/tags\///p')" -fi - -if [ -z "$pkgver" ]; then - pkgver="latest" -fi - -if [ -z "$2" ] && [ -z "$1" ]; then # no arguments - release_dir="target/release" - tar_suffix="" - tar_prefix="-x86_64" -elif [ -n "$1" ] && [ -z "$2" ]; then # only first argument - release_dir="target/$1/release" - tar_suffix="" - tar_prefix="-$1" -elif [ -n "$2" ] && [ -n "$1" ]; then # both arguments - release_dir="target/$1/$2/release" - tar_suffix="-$2" - tar_prefix="-$1" -fi - -# WIESEP: Change amd64 to x86_64 to keep release names compatible with previous releases -if [ "$tar_prefix" == "-amd64" ]; then - tar_prefix="-x86_64" -fi - -tar -czf "bender-$pkgver$tar_prefix-linux-gnu$tar_suffix.tar.gz" \ - -C "./$release_dir" \ - --owner=0 --group=0 \ - bender diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f438eb44a..257e41322 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,62 +6,37 @@ on: pull_request: workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + jobs: test: - runs-on: ubuntu-latest + name: Test (${{ matrix.os }}, Rust ${{ matrix.rust }}) + runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.rust == 'nightly' }} strategy: fail-fast: false matrix: - rust: - - stable - - beta - - nightly - - 1.87.0 # minimum supported version - continue-on-error: ${{ matrix.rust == 'nightly' }} + # Linux runs the full Rust version matrix; Windows and macOS test stable only. + os: [ubuntu-latest] + rust: [stable, beta, nightly, "1.87.0"] + include: + - os: windows-latest + rust: stable + - os: macos-latest + rust: stable steps: - uses: actions/checkout@v6 with: submodules: recursive - uses: dtolnay/rust-toolchain@stable with: - toolchain: ${{ matrix.rust}} - components: rustfmt - - name: Build - run: cargo build --all-features - - name: Cargo Test - run: cargo test --workspace --all-features - - name: Format (fix with `cargo fmt`) - run: cargo fmt -- --check - - name: Run unit-tests - run: tests/run_all.sh - shell: bash - - test-windows: - runs-on: windows-latest - steps: - - uses: actions/checkout@v6 - with: - submodules: recursive - - uses: dtolnay/rust-toolchain@stable + toolchain: ${{ matrix.rust }} + - uses: Swatinem/rust-cache@v2 with: - toolchain: stable - - name: Build - run: cargo build --all-features - - name: Cargo Test - run: cargo test --workspace --all-features - - name: Run unit-tests - run: tests/run_all.sh - shell: bash - - test-macos: - runs-on: macos-latest - steps: - - uses: actions/checkout@v6 - with: - submodules: recursive - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable + shared-key: ci-test-${{ matrix.os }}-${{ matrix.rust }} + cache-workspace-crates: "true" - name: Build run: cargo build --all-features - name: Cargo Test @@ -81,6 +56,10 @@ jobs: with: toolchain: stable components: clippy + - uses: Swatinem/rust-cache@v2 + with: + shared-key: ci-clippy-${{ runner.os }}-stable + cache-workspace-crates: "true" - run: cargo clippy --all-features unused-deps: @@ -91,6 +70,10 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: toolchain: stable + - uses: Swatinem/rust-cache@v2 + with: + shared-key: ci-unused-deps-${{ runner.os }}-stable + cache-workspace-crates: "true" - name: Install machete run: cargo install cargo-machete - name: Check for unused dependencies diff --git a/.github/workflows/cli_regression.yml b/.github/workflows/cli_regression.yml index bfdcf9bd7..71b5780a8 100644 --- a/.github/workflows/cli_regression.yml +++ b/.github/workflows/cli_regression.yml @@ -4,6 +4,10 @@ on: pull_request: workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + jobs: test: runs-on: ubuntu-latest diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml new file mode 100644 index 000000000..f81cf6392 --- /dev/null +++ b/.github/workflows/formatting.yml @@ -0,0 +1,35 @@ +name: formatting + +on: + push: + branches: [master] + pull_request: + branches: [master] + workflow_dispatch: + +jobs: + rustfmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + submodules: recursive + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + components: rustfmt + - name: Check Rust formatting + run: cargo fmt -- --check + + clang-format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + submodules: recursive + - name: Check C/C++ formatting + uses: DoozyX/clang-format-lint-action@v0.18 + with: + source: "." + extensions: "h,hpp,c,cc,cpp,cxx" + exclude: "./crates/bender-slang/vendor" diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml new file mode 100644 index 000000000..b3c93240c --- /dev/null +++ b/.github/workflows/release-build.yml @@ -0,0 +1,59 @@ +name: release-build + +# Verify that a release build succeeds on all platforms that cargo-dist will +# target. Runs on every push to master (and can be triggered manually) so +# that compatibility issues or platform-specific build failures are +# caught before tagging a release. +on: + push: + branches: [master] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + release-build: + name: Release Build (${{ matrix.target }}) + runs-on: ${{ matrix.runner }} + container: ${{ matrix.container || '' }} + strategy: + fail-fast: false + # Mirror the release matrix from dist-workspace.toml exactly, including + # the manylinux containers, so CI catches compatibility issues early. + matrix: + include: + - target: x86_64-unknown-linux-gnu + runner: ubuntu-22.04 + container: quay.io/pypa/manylinux_2_28_x86_64 + - target: aarch64-unknown-linux-gnu + runner: ubuntu-22.04-arm + container: quay.io/pypa/manylinux_2_28_aarch64 + - target: x86_64-apple-darwin + runner: macos-latest + - target: aarch64-apple-darwin + runner: macos-15 + - target: x86_64-pc-windows-msvc + runner: windows-latest + steps: + - uses: actions/checkout@v6 + with: + submodules: recursive + - name: Install Rust non-interactively if not already installed + if: ${{ matrix.container }} + run: | + if ! command -v cargo > /dev/null 2>&1; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + fi + - uses: dtolnay/rust-toolchain@stable + if: ${{ !matrix.container }} + with: + toolchain: stable + - uses: Swatinem/rust-cache@v2 + with: + shared-key: release-build-${{ matrix.target }} + cache-workspace-crates: "true" + - name: Build (release) + run: cargo build --release --all-features diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml deleted file mode 100644 index 2df026bd0..000000000 --- a/.github/workflows/release.yaml +++ /dev/null @@ -1,297 +0,0 @@ -name: release - -on: - release: - types: [created] - workflow_dispatch: - -jobs: - release_amd64: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - rust: - - stable - os: - - centos:7.4.1708 - - centos:7.6.1810 - - centos:7.7.1908 - - centos:7.8.2003 - - centos:7.9.2009 - - ubuntu:18.04 - - ubuntu:20.04 - - ubuntu:22.04 - - ubuntu:24.04 - - fedora:42 - - fedora:43 - - debian:11 - - debian:12 - - debian:13 - - rhel:8.6 - - rhel:8.7 - - rhel:8.8 - - rhel:8.9 - - rhel:8.10 - - rhel:9.0 - - rhel:9.1 - - rhel:9.2 - - rhel:9.3 - - rhel:9.4 - - rhel:9.5 - - rhel:9.6 - - rhel:9.7 - - rhel:10.0 - - rhel:10.1 - - almalinux:8.6 - - almalinux:8.7 - - almalinux:8.8 - - almalinux:8.9 - - almalinux:8.10 - - almalinux:9.0 - - almalinux:9.1 - - almalinux:9.2 - - almalinux:9.3 - - almalinux:9.4 - - almalinux:9.5 - - almalinux:9.6 - - almalinux:9.7 - - almalinux:10.0 - - almalinux:10.1 - platform: - - linux/amd64 - steps: - - uses: actions/checkout@v4 - - name: OS Build - run: | - export full_tgtname=${{ matrix.os }} - export tgtname=$(echo ${{ matrix.os }} | tr -d ':') - export full_platform=${{ matrix.platform }} - export platform=$(echo ${{ matrix.platform }} | awk -F'/' '{print $NF}') - .github/scripts/gen_dockerfile.sh - docker build ./ -t $tgtname-$platform --platform $full_platform - docker run \ - -t --rm \ - -v "$GITHUB_WORKSPACE:/source" \ - -v "$GITHUB_WORKSPACE/target/$platform/$tgtname:/source/target" \ - --platform $full_platform \ - $tgtname-$platform \ - cargo build --release --all-features; - shell: bash - - name: OS Create Package - run: | - export tgtname=$(echo ${{ matrix.os }} | tr -d ':') - export platform=$(echo ${{ matrix.platform }} | awk -F'/' '{print $NF}') - .github/scripts/package.sh $platform $tgtname; - shell: bash - - name: Upload Release Asset - uses: softprops/action-gh-release@v1 - with: - tag_name: ${{ github.event.release.tag_name }} - files: bender-*.tar.gz - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - release_arm64: - runs-on: ubuntu-24.04-arm - strategy: - fail-fast: false - matrix: - rust: - - stable - os: - - ubuntu:18.04 - - ubuntu:20.04 - - ubuntu:22.04 - - ubuntu:24.04 - platform: - - linux/arm64 - steps: - - uses: actions/checkout@v4 - - name: OS Build - run: | - export full_tgtname=${{ matrix.os }} - export tgtname=$(echo ${{ matrix.os }} | tr -d ':') - export full_platform=${{ matrix.platform }} - export platform=$(echo ${{ matrix.platform }} | awk -F'/' '{print $NF}') - .github/scripts/gen_dockerfile.sh - docker build ./ -t $tgtname-$platform --platform $full_platform - docker run \ - -t --rm \ - -v "$GITHUB_WORKSPACE:/source" \ - -v "$GITHUB_WORKSPACE/target/$platform/$tgtname:/source/target" \ - --platform $full_platform \ - $tgtname-$platform \ - cargo build --release --all-features; - shell: bash - - name: OS Create Package - run: | - export tgtname=$(echo ${{ matrix.os }} | tr -d ':') - export platform=$(echo ${{ matrix.platform }} | awk -F'/' '{print $NF}') - .github/scripts/package.sh $platform $tgtname; - shell: bash - - name: Upload Release Asset - uses: softprops/action-gh-release@v1 - with: - tag_name: ${{ github.event.release.tag_name }} - files: bender-*.tar.gz - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - release-gnu_amd64: - runs-on: ubuntu-latest - # Use container that supports old GLIBC versions and (hopefully) many linux OSs - # container: quay.io/pypa/manylinux2014_x86_64 - steps: - - uses: actions/checkout@v4 - - name: Setup Dockerfile - run: | - touch Dockerfile - echo "FROM quay.io/pypa/manylinux2014_x86_64" >> Dockerfile - echo "RUN sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo" >> Dockerfile - echo "RUN sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo" >> Dockerfile - echo "RUN sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo" >> Dockerfile - - echo "RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*" >> Dockerfile - echo "RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*" >> Dockerfile - echo "RUN yum group install "Development Tools" -y && yum clean all" >> Dockerfile - echo 'ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo' >> Dockerfile - echo 'ENV PATH=$CARGO_HOME/bin:$PATH' >> Dockerfile - echo >> Dockerfile - echo 'RUN mkdir -p "$CARGO_HOME" && mkdir -p "$RUSTUP_HOME" && \' >> Dockerfile - echo ' curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable && \' >> Dockerfile - echo ' chmod -R a=rwX $CARGO_HOME' >> Dockerfile - echo >> Dockerfile - echo 'WORKDIR /source' >> Dockerfile - - name: OS build - run: | - docker build ./ -t manylinux-amd64 --platform linux/amd64 - docker run \ - -t --rm \ - -v "$GITHUB_WORKSPACE:/source" \ - -v "$GITHUB_WORKSPACE/target/amd64:/source/target" \ - --platform linux/amd64 \ - manylinux-amd64 \ - cargo build --release --all-features; - - name: GNU Create Package - run: .github/scripts/package.sh amd64 - shell: bash - - name: Upload Release Asset - uses: softprops/action-gh-release@v1 - with: - tag_name: ${{ github.event.release.tag_name }} - files: bender-*.tar.gz - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - release-gnu_arm64: - runs-on: ubuntu-24.04-arm - # Use container that supports old GLIBC versions and (hopefully) many linux OSs - # container: quay.io/pypa/manylinux2014_aarch64 - steps: - - uses: actions/checkout@v4 - - name: Setup Dockerfile - run: | - touch Dockerfile - echo "FROM quay.io/pypa/manylinux2014_aarch64" >> Dockerfile - echo "RUN sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo" >> Dockerfile - echo "RUN sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo" >> Dockerfile - echo "RUN sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo" >> Dockerfile - - echo "RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*" >> Dockerfile - echo "RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*" >> Dockerfile - echo "RUN yum group install "Development Tools" -y && yum clean all" >> Dockerfile - echo 'ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo' >> Dockerfile - echo 'ENV PATH=$CARGO_HOME/bin:$PATH' >> Dockerfile - echo >> Dockerfile - echo 'RUN mkdir -p "$CARGO_HOME" && mkdir -p "$RUSTUP_HOME" && \' >> Dockerfile - echo ' curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable && \' >> Dockerfile - echo ' chmod -R a=rwX $CARGO_HOME' >> Dockerfile - echo >> Dockerfile - echo 'WORKDIR /source' >> Dockerfile - - name: OS build - run: | - docker build ./ -t manylinux-arm64 --platform linux/arm64 - docker run \ - -t --rm \ - -v "$GITHUB_WORKSPACE:/source" \ - -v "$GITHUB_WORKSPACE/target/arm64:/source/target" \ - --platform linux/arm64 \ - manylinux-arm64 \ - cargo build --release --all-features; - - name: GNU Create Package - run: .github/scripts/package.sh arm64 - shell: bash - - name: Upload Release Asset - uses: softprops/action-gh-release@v1 - with: - tag_name: ${{ github.event.release.tag_name }} - files: bender-*.tar.gz - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - release-macos: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: Install Rust - run: | - curl --proto '=https' --tlsv1.2 -sSf https://https://sh.rustup.rs | sh -s -- -y --default-toolchain stable - echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH - - name: universal2 install - run: | - rustup target add x86_64-apple-darwin - rustup target add aarch64-apple-darwin - cargo install universal2 - - name: MacOS Build - run: cargo-universal2 --release --all-features - - name: Get Artifact Name - run: | - if [[ "$GITHUB_REF" =~ ^refs/tags/v.*$ ]]; then \ - PKG_VERSION=$(echo $GITHUB_REF | sed -n 's/^refs\/tags\/v//p'); \ - else \ - PKG_VERSION=$(echo $GITHUB_REF | sed -n 's/^refs\/tags\///p'); \ - fi - ARTIFACT_PATHNAME="bender-$PKG_VERSION-universal-apple-darwin.tar.gz" - ARTIFACT_NAME=$(basename $ARTIFACT_PATHNAME) - echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV - echo "ARTIFACT_PATHNAME=${ARTIFACT_PATHNAME}" >> $GITHUB_ENV - - name: Create Package - run: | - gtar -czf $ARTIFACT_PATHNAME -C "./target/universal2-apple-darwin/release" --owner=0 --group=0 bender - - name: Upload Release Asset - uses: softprops/action-gh-release@v1 - with: - tag_name: ${{ github.event.release.tag_name }} - files: bender-*.tar.gz - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - release-windows: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - - name: Build - run: cargo build --release - - name: Get Artifact Name - shell: bash - run: | - if [[ "$GITHUB_REF" =~ ^refs/tags/v.*$ ]]; then \ - PKG_VERSION=$(echo $GITHUB_REF | sed -n 's/^refs\/tags\/v//p'); \ - else \ - PKG_VERSION=$(echo $GITHUB_REF | sed -n 's/^refs\/tags\///p'); \ - fi - ARTIFACT_PATHNAME="bender-$PKG_VERSION-x86_64-pc-windows-msvc.tar.gz" - ARTIFACT_NAME=$(basename $ARTIFACT_PATHNAME) - echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV - echo "ARTIFACT_PATHNAME=${ARTIFACT_PATHNAME}" >> $GITHUB_ENV - - name: Create Package - run: | - cp target/release/bender.exe . - & 'C:\Program Files\Git\usr\bin\tar.exe' czf $Env:ARTIFACT_PATHNAME --owner=0 --group=0 bender.exe - - name: Upload Release Asset - uses: softprops/action-gh-release@v1 - with: - tag_name: ${{ github.event.release.tag_name }} - files: bender-*.tar.gz - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..d9aa406b1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,296 @@ +# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist +# +# Copyright 2022-2024, axodotdev +# SPDX-License-Identifier: MIT or Apache-2.0 +# +# CI that: +# +# * checks for a Git Tag that looks like a release +# * builds artifacts with dist (archives, installers, hashes) +# * uploads those artifacts to temporary workflow zip +# * on success, uploads the artifacts to a GitHub Release +# +# Note that the GitHub Release will be created with a generated +# title/body based on your changelogs. + +name: Release +permissions: + "contents": "write" + +# This task will run whenever you push a git tag that looks like a version +# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc. +# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where +# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION +# must be a Cargo-style SemVer Version (must have at least major.minor.patch). +# +# If PACKAGE_NAME is specified, then the announcement will be for that +# package (erroring out if it doesn't have the given version or isn't dist-able). +# +# If PACKAGE_NAME isn't specified, then the announcement will be for all +# (dist-able) packages in the workspace with that version (this mode is +# intended for workspaces with only one dist-able package, or with all dist-able +# packages versioned/released in lockstep). +# +# If you push multiple tags at once, separate instances of this workflow will +# spin up, creating an independent announcement for each one. However, GitHub +# will hard limit this to 3 tags per commit, as it will assume more tags is a +# mistake. +# +# If there's a prerelease-style suffix to the version, then the release(s) +# will be marked as a prerelease. +on: + pull_request: + push: + tags: + - '**[0-9]+.[0-9]+.[0-9]+*' + +jobs: + # Run 'dist plan' (or host) to determine what tasks we need to do + plan: + runs-on: "ubuntu-22.04" + outputs: + val: ${{ steps.plan.outputs.manifest }} + tag: ${{ !github.event.pull_request && github.ref_name || '' }} + tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} + publishing: ${{ !github.event.pull_request }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + submodules: recursive + - name: Install dist + # we specify bash to get pipefail; it guards against the `curl` command + # failing. otherwise `sh` won't catch that `curl` returned non-0 + shell: bash + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.31.0/cargo-dist-installer.sh | sh" + - name: Cache dist + uses: actions/upload-artifact@v6 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/dist + # sure would be cool if github gave us proper conditionals... + # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible + # functionality based on whether this is a pull_request, and whether it's from a fork. + # (PRs run on the *source* but secrets are usually on the *target* -- that's *good* + # but also really annoying to build CI around when it needs secrets to work right.) + - id: plan + run: | + dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json + echo "dist ran successfully" + cat plan-dist-manifest.json + echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v6 + with: + name: artifacts-plan-dist-manifest + path: plan-dist-manifest.json + + # Build and packages all the platform-specific things + build-local-artifacts: + name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) + # Let the initial task tell us to not run (currently very blunt) + needs: + - plan + if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} + strategy: + fail-fast: false + # Target platforms/runners are computed by dist in create-release. + # Each member of the matrix has the following arguments: + # + # - runner: the github runner + # - dist-args: cli flags to pass to dist + # - install-dist: expression to run to install dist on the runner + # + # Typically there will be: + # - 1 "global" task that builds universal installers + # - N "local" tasks that build each platform's binaries and platform-specific installers + matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} + runs-on: ${{ matrix.runner }} + container: ${{ matrix.container && matrix.container.image || null }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json + steps: + - name: enable windows longpaths + run: | + git config --global core.longpaths true + - uses: actions/checkout@v6 + with: + persist-credentials: false + submodules: recursive + - name: Install Rust non-interactively if not already installed + if: ${{ matrix.container }} + run: | + if ! command -v cargo > /dev/null 2>&1; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + fi + - name: Install dist + run: ${{ matrix.install_dist.run }} + # Get the dist-manifest + - name: Fetch local artifacts + uses: actions/download-artifact@v7 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - name: Install dependencies + run: | + ${{ matrix.packages_install }} + - name: Build artifacts + run: | + # Actually do builds and make zips and whatnot + dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json + echo "dist ran successfully" + - id: cargo-dist + name: Post-build + # We force bash here just because github makes it really hard to get values up + # to "real" actions without writing to env-vars, and writing to env-vars has + # inconsistent syntax between shell and powershell. + shell: bash + run: | + # Parse out what we just built and upload it to scratch storage + echo "paths<> "$GITHUB_OUTPUT" + dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + cp dist-manifest.json "$BUILD_MANIFEST_NAME" + - name: "Upload artifacts" + uses: actions/upload-artifact@v6 + with: + name: artifacts-build-local-${{ join(matrix.targets, '_') }} + path: | + ${{ steps.cargo-dist.outputs.paths }} + ${{ env.BUILD_MANIFEST_NAME }} + + # Build and package all the platform-agnostic(ish) things + build-global-artifacts: + needs: + - plan + - build-local-artifacts + runs-on: "ubuntu-22.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + submodules: recursive + - name: Install cached dist + uses: actions/download-artifact@v7 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/ + - run: chmod +x ~/.cargo/bin/dist + # Get all the local artifacts for the global tasks to use (for e.g. checksums) + - name: Fetch local artifacts + uses: actions/download-artifact@v7 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - id: cargo-dist + shell: bash + run: | + dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json + echo "dist ran successfully" + + # Parse out what we just built and upload it to scratch storage + echo "paths<> "$GITHUB_OUTPUT" + jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + cp dist-manifest.json "$BUILD_MANIFEST_NAME" + - name: "Upload artifacts" + uses: actions/upload-artifact@v6 + with: + name: artifacts-build-global + path: | + ${{ steps.cargo-dist.outputs.paths }} + ${{ env.BUILD_MANIFEST_NAME }} + # Determines if we should publish/announce + host: + needs: + - plan + - build-local-artifacts + - build-global-artifacts + # Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine) + if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + runs-on: "ubuntu-22.04" + outputs: + val: ${{ steps.host.outputs.manifest }} + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + submodules: recursive + - name: Install cached dist + uses: actions/download-artifact@v7 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/ + - run: chmod +x ~/.cargo/bin/dist + # Fetch artifacts from scratch-storage + - name: Fetch artifacts + uses: actions/download-artifact@v7 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - id: host + shell: bash + run: | + dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json + echo "artifacts uploaded and released successfully" + cat dist-manifest.json + echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v6 + with: + # Overwrite the previous copy + name: artifacts-dist-manifest + path: dist-manifest.json + # Create a GitHub Release while uploading all files to it + - name: "Download GitHub Artifacts" + uses: actions/download-artifact@v7 + with: + pattern: artifacts-* + path: artifacts + merge-multiple: true + - name: Cleanup + run: | + # Remove the granular manifests + rm -f artifacts/*-dist-manifest.json + - name: Create GitHub Release + env: + PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}" + ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}" + ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}" + RELEASE_COMMIT: "${{ github.sha }}" + run: | + # Write and read notes from a file to avoid quoting breaking things + echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt + + gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/* + + announce: + needs: + - plan + - host + # use "always() && ..." to allow us to wait for all publish jobs while + # still allowing individual publish jobs to skip themselves (for prereleases). + # "host" however must run to completion, no skipping allowed! + if: ${{ always() && needs.host.result == 'success' }} + runs-on: "ubuntu-22.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + submodules: recursive diff --git a/Cargo.toml b/Cargo.toml index 08930c63f..2e05e4702 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,10 @@ rust-version = "1.87.0" [workspace] members = ["crates/bender-slang"] +[profile.dist] +inherits = "release" +lto = "thin" + [dependencies] bender-slang = { path = "crates/bender-slang", optional = true} diff --git a/README.md b/README.md index 044f641fa..8bffe203c 100644 --- a/README.md +++ b/README.md @@ -46,25 +46,19 @@ Bender is built around the following core principles: ## Installation -To use Bender for a single project, the simplest is to download and use a precompiled binary. We provide binaries for all current versions of Ubuntu and CentOS, as well as generic Linux, on each release. Open a terminal and enter the following command: +The recommended way to install Bender is via the shell installer, which detects your platform and places the `bender` binary in `~/.cargo/bin` (on your `PATH`): ```sh curl --proto '=https' --tlsv1.2 https://pulp-platform.github.io/bender/init -sSf | sh ``` -The command downloads and executes a script that detects your distribution and downloads the appropriate `bender` binary of the latest release to your current directory. If you need a specific version of Bender (e.g., `0.21.0`), append ` -s -- 0.21.0` to that command. Alternatively, you can manually download a precompiled binary from [our Releases on GitHub][releases]. +To install a specific version (e.g., `0.28.0`), append ` -s -- 0.28.0` to that command. Alternatively, you can manually download a precompiled binary from [our Releases on GitHub][releases]. -If you prefer building your own binary, you need to [install Rust][rust-installation]. You can then build and install Bender for the current user with the following command: +To build from source, [install Rust][rust-installation] and run: ```sh cargo install bender ``` -If you need a specific version of Bender (e.g., `0.21.0`), append ` --version 0.21.0` to that command. +To enable optional features (including the Slang-backed `pickle` command), add `--all-features`. This may increase build time and require additional build dependencies. -To enable optional features (including the Slang-backed `pickle` command), install with: -```sh -cargo install bender --all-features -``` -This may increase build time and additional build dependencies. - -To install Bender system-wide, you can simply copy the binary you have obtained from one of the above methods to one of the system directories on your `PATH`. Even better, some Linux distributions have Bender in their repositories. We are currently aware of: +Some Linux distributions also have Bender in their repositories: ### [ArchLinux ![aur-shield](https://img.shields.io/aur/version/bender)][aur-bender] diff --git a/dist-workspace.toml b/dist-workspace.toml new file mode 100644 index 000000000..3e55bb0ae --- /dev/null +++ b/dist-workspace.toml @@ -0,0 +1,34 @@ +[workspace] +members = ["cargo:."] + +# Config for 'dist' +[dist] +# The preferred dist version to use in CI (Cargo.toml SemVer syntax) +cargo-dist-version = "0.31.0" +# CI backends to support +ci = "github" +# The installers to generate for each app +installers = ["shell", "powershell"] +# Target platforms to build apps for (Rust target-triple syntax) +targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"] +# Path that installers should place binaries in +install-path = "CARGO_HOME" +# Whether to install an updater program +install-updater = false +# Whether to pass --all-features to cargo build +all-features = true +# Whether +crt-static should be used on msvc +msvc-crt-static = false + +[dist.github-custom-runners] +# Use a slightly newer macOS runner for aarch64, +# since the default one (macos-14) uses Clang/LLVM 15.0.0. +# slang requires at least Clang/LLVM 17.0.0, which is available on macos-15. +aarch64-apple-darwin = "macos-15" +# Make sure that the minimum supported glibc version is 2.28 on Linux. +[dist.github-custom-runners.x86_64-unknown-linux-gnu] +runner = "ubuntu-22.04" +container = "quay.io/pypa/manylinux_2_28_x86_64" +[dist.github-custom-runners.aarch64-unknown-linux-gnu] +runner = "ubuntu-22.04-arm" +container = "quay.io/pypa/manylinux_2_28_aarch64"