name: Rust CI and Docker Build
on:
push:
branches: [ master ]
tags: [ 'v*' ]
pull_request:
branches: [ master ]
env:
CARGO_TERM_COLOR: always
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
# A newer push supersedes this run: on a branch or PR the run in
# progress is cancelled; on master it finishes, and only a run still
# waiting is replaced.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
build:
strategy:
matrix:
include:
- runner: arc-runner-set
arch: x86_64
- runner: ubuntu-24.04-arm
arch: aarch64
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Install system dependencies (Linux)
if: runner.os == 'Linux'
run: |
if command -v apt-get &> /dev/null; then
sudo apt-get update
sudo apt-get install -y build-essential pkg-config libssl-dev libgtk-3-dev libgdk-pixbuf2.0-dev libpango1.0-dev
elif command -v yum &> /dev/null; then
sudo yum install -y pkgconfig openssl-devel gtk3-devel gdk-pixbuf-devel pango-devel
elif command -v dnf &> /dev/null; then
sudo dnf install -y pkgconfig openssl-devel
elif command -v pacman &> /dev/null; then
sudo pacman -Sy --noconfirm pkgconf openssl
elif command -v apk &> /dev/null; then
sudo apk add --no-cache pkgconfig openssl-dev
else
echo "Package manager not found. Please install pkg-config and openssl-dev manually."
exit 1
fi
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.92"
components: rustfmt, clippy
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
- name: Check formatting
run: cargo fmt -- --check
- name: Run clippy
run: cargo clippy -- -D warnings
- name: Check
run: cargo check
- name: Build release artifact
run: cargo build --release --verbose
- name: Strip binary
run: strip target/release/ppl
# Built with `stable`, not this project's pinned toolchain. The
# pin says what *this crate* compiles with; cargo-deb and
# cargo-generate-rpm are build-time utilities that never link
# into the binary, and constraining them by the project's MSRV
# breaks the install every time the ecosystem moves past it —
# cargo-deb 3.8.0 needs rustc 1.88 while declaring 1.85.
# `--locked` keeps two runs a month apart installing the same
# bytes.
- name: Install the packaging tools
run: |
set -euo pipefail
rustup toolchain install stable --profile minimal
cargo +stable install cargo-deb --locked
cargo +stable install cargo-generate-rpm --locked
# Every CI build has to carry a distinct version, or the second
# one publishes the same filename with different bytes and the
# registry correctly refuses it with a 409 — and no machine that
# installed the first ever sees the second.
#
# `+` rather than `-`: RPM forbids `-` in a version outright, and
# in both ecosystems `0.1.0+dev.<stamp>` sorts *after* 0.1.0,
# which is what you want from a repository you added in order to
# run the latest build. A tag publishes the bare Cargo version.
- name: Stamp the package version
run: |
set -euo pipefail
base=$(grep -m1 '^version = ' Cargo.toml | cut -d'"' -f2)
if [ "${GITHUB_REF_TYPE:-}" = "tag" ]; then
version="$base"
else
version="$base+dev.$(date -u +%s)"
fi
echo "version: $version"
# Rewritten after the release build, so the binary is cached
# on the unstamped manifest and only the packaging sees this.
sed -i "0,/^version = .*/s//version = \"$version\"/" Cargo.toml
- name: Build test Debian package
run: cargo deb --no-build --no-strip
- name: Build RPM package
run: cargo generate-rpm
# `vars.CI_FORGE_URL` is what the forge injects into a run; fall
# back to what the runner already knows. Not publishing is a
# legitimate outcome — github.com has no registry at these paths.
- name: Resolve the forge URL
env:
CI_FORGE_URL: ${{ vars.CI_FORGE_URL }}
run: |
set -euo pipefail
forge_url=${CI_FORGE_URL:-${GITHUB_SERVER_URL:-}}
case "${forge_url:-}" in
"")
echo "No forge URL available; not publishing."
echo "PUBLISH=false" >> "$GITHUB_ENV"
;;
*://github.com|*://github.com/*|*://www.github.com*)
echo "Running on GitHub, which has no package registry here."
echo "PUBLISH=false" >> "$GITHUB_ENV"
;;
*)
echo "publishing to $forge_url"
echo "FORGE_URL=$forge_url" >> "$GITHUB_ENV"
echo "PUBLISH=true" >> "$GITHUB_ENV"
;;
esac
# `${{ github.token }}` is minted for this job and authorized to
# publish to THIS repository's packages and nowhere else, so
# there is no secret to create first.
#
# Pull requests don't publish: a PR build is a check, and a
# registry that carries every proposed change is not a registry
# anyone can install from.
- name: Publish the .deb and the .rpm to the forge
if: github.event_name != 'pull_request' && env.PUBLISH == 'true'
env:
REPOSITORY: ${{ github.repository }}
TOKEN: ${{ github.token }}
run: |
set -euo pipefail
for deb in target/debian/*.deb; do
echo "publishing $deb"
curl --fail-with-body -sS \
-u "gitgud-actions:$TOKEN" \
-H "Content-Type: application/vnd.debian.binary-package" \
--data-binary "@$deb" \
"$FORGE_URL/pkg/deb/$REPOSITORY/upload?dist=stable&component=main"
echo
done
for rpm in target/generate-rpm/*.rpm; do
echo "publishing $rpm"
curl --fail-with-body -sS \
-u "gitgud-actions:$TOKEN" \
-H "Content-Type: application/x-rpm" \
--data-binary "@$rpm" \
"$FORGE_URL/pkg/rpm/$REPOSITORY/upload"
echo
done
- name: How to install it
if: github.event_name != 'pull_request' && env.PUBLISH == 'true'
env:
OWNER: ${{ github.repository_owner }}
run: |
cat <<EOF
# Debian / Ubuntu
curl -fsSL $FORGE_URL/pkg/_keys/deb/$OWNER | sudo tee /etc/apt/keyrings/$OWNER.asc >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/$OWNER.asc] $FORGE_URL/pkg/deb/$OWNER/_all stable main" | sudo tee /etc/apt/sources.list.d/$OWNER.list
sudo apt update && sudo apt install neiam-ppl
# Fedora / RHEL / openSUSE — /etc/yum.repos.d/$OWNER.repo
[$OWNER]
name=$OWNER
baseurl=$FORGE_URL/pkg/rpm/$OWNER/_all
enabled=1
repo_gpgcheck=1
# cargo-generate-rpm produces unsigned packages; the forge
# signs the index, not what it was handed.
gpgcheck=0
gpgkey=$FORGE_URL/pkg/_keys/rpm/$OWNER
sudo dnf install neiam-ppl # or: sudo zypper install neiam-ppl
EOF
- name: Upload test artifact
uses: actions/upload-artifact@v4
# Artifact storage is a GitHub feature; this forge has none, so
# these steps have nothing to upload to. They used to run and
# fail with `continue-on-error`, which is a red step on every
# single run — and a build that is always a bit red teaches
# everyone to stop reading it. Skipping says the same thing
# honestly and leaves the badge meaningful.
#
# The packages are published to the forge's registries instead,
# which is the thing anyone actually installs from.
if: ${{ startsWith(github.server_url, 'https://github.com') }}
with:
name: ppl-test-${{ matrix.arch }}-linux
path: target/release/ppl
- name: Upload test Debian package
uses: actions/upload-artifact@v4
if: ${{ startsWith(github.server_url, 'https://github.com') }}
with:
name: ppl-test-${{ matrix.arch }}-linux.deb
path: target/debian/*.deb
- name: Upload test RPM package
uses: actions/upload-artifact@v4
if: ${{ startsWith(github.server_url, 'https://github.com') }}
with:
name: ppl-test-${{ matrix.arch }}-linux.rpm
path: target/generate-rpm/*.rpm
release:
name: Release
if: startsWith(github.ref, 'refs/tags/v')
needs: build
permissions:
contents: write
packages: write
strategy:
matrix:
include:
- os: ubuntu-latest
runner: arc-runner-set
name: ppl-x86_64-linux-gnu.tar.gz
archive_cmd: tar -czf
binary_ext: ""
rust: "1.92"
- os: ubuntu-24.04-arm
runner: ubuntu-24.04-arm
name: ppl-aarch64-linux-gnu.tar.gz
archive_cmd: tar -czf
binary_ext: ""
rust: "1.92"
- os: macos-latest
runner: macos-latest
name: ppl-aarch64-macos.tar.gz
archive_cmd: tar -czf
binary_ext: ""
rust: "1.92"
- os: windows-latest
runner: windows-latest
name: ppl-x86_64-windows.zip
archive_cmd: 7z a
binary_ext: ".exe"
rust: "1.92"
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
- name: Install system dependencies (self-hosted Linux)
if: runner.os == 'Linux'
run: |
if command -v apt-get &> /dev/null; then
sudo apt-get update
sudo apt-get install -y build-essential pkg-config libssl-dev libgtk-3-dev libgdk-pixbuf2.0-dev libpango1.0-dev libglib2.0-dev
elif command -v yum &> /dev/null; then
sudo yum install -y pkgconfig openssl-devel gtk3-devel gdk-pixbuf-devel pango-devel
elif command -v dnf &> /dev/null; then
sudo dnf install -y pkgconfig openssl-devel
elif command -v pacman &> /dev/null; then
sudo pacman -Sy --noconfirm pkgconf openssl
elif command -v apk &> /dev/null; then
sudo apk add --no-cache pkgconfig openssl-dev
else
echo "Package manager not found. Please install pkg-config and openssl-dev manually."
exit 1
fi
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.rust }}
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.os }}-${{ matrix.rust }}
- name: Build release binary
run: cargo build --release --verbose
- name: Strip binary (Unix)
if: matrix.os != 'windows-latest'
run: |
strip target/release/ppl${{ matrix.binary_ext }}
- name: Create release archive (Unix)
if: matrix.os != 'windows-latest'
run: |
cd target/release
tar -czf ../../${{ matrix.name }} ppl
cd ../..
- name: Create release archive (Windows)
if: matrix.os == 'windows-latest'
run: |
cd target/release
7z a ../../${{ matrix.name }} ppl.exe
cd ../..
- name: Install cargo-deb (Linux)
if: runner.os == 'Linux'
run: cargo install cargo-deb
- name: Build Debian package (Linux)
if: runner.os == 'Linux'
run: cargo deb --no-build --no-strip
- name: Install cargo-generate-rpm (Linux)
if: runner.os == 'Linux'
run: cargo install cargo-generate-rpm
- name: Build RPM package (Linux)
if: runner.os == 'Linux'
run: cargo generate-rpm
- name: Upload release archive
uses: actions/upload-artifact@v4
if: ${{ startsWith(github.server_url, 'https://github.com') }}
with:
name: ${{ matrix.name }}
path: ${{ matrix.name }}
- name: Upload Debian package
if: runner.os == 'Linux'
uses: actions/upload-artifact@v4
if: ${{ startsWith(github.server_url, 'https://github.com') }}
with:
name: ppl-${{ matrix.os }}.deb
path: target/debian/*.deb
- name: Upload RPM package
if: runner.os == 'Linux'
uses: actions/upload-artifact@v4
if: ${{ startsWith(github.server_url, 'https://github.com') }}
with:
name: ppl-${{ matrix.os }}.rpm
path: target/generate-rpm/*.rpm
create-release:
name: Create Release
runs-on: arc-runner-set
# Makes a *GitHub* Release out of artifacts a GitHub runner uploaded.
# Off GitHub it would download nothing and then fail, which is the
# permanently-red build this workflow is trying to stop having.
# Tagged builds still publish their packages — that happens in the
# build job, which runs everywhere.
if: >-
startsWith(github.ref, 'refs/tags/v') &&
startsWith(github.server_url, 'https://github.com')
needs: release
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
if: ${{ startsWith(github.server_url, 'https://github.com') }}
with:
path: artifacts
- name: Create release notes
run: |
echo "# ppl Release ${GITHUB_REF_NAME}" > release_notes.md
echo "" >> release_notes.md
echo "## Changes in this release" >> release_notes.md
echo "" >> release_notes.md
echo "## Supported Platforms" >> release_notes.md
echo "" >> release_notes.md
echo "- Linux (x86_64)" >> release_notes.md
echo "- Linux (aarch64)" >> release_notes.md
echo "- Windows (x86_64)" >> release_notes.md
echo "- macOS (x86_64 and Apple Silicon)" >> release_notes.md
echo "" >> release_notes.md
echo "## Installation" >> release_notes.md
echo "" >> release_notes.md
echo "1. Download the appropriate archive for your platform" >> release_notes.md
echo "2. Extract the binaries" >> release_notes.md
echo "3. Place them in your PATH" >> release_notes.md
echo "" >> release_notes.md
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
files: |
artifacts/*/*.tar.gz
artifacts/*/*.zip
artifacts/*/*.deb
artifacts/*/*.rpm
body_path: release_notes.md
draft: false
prerelease: ${{ contains(github.ref_name, '-') }}
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
⭐
Log in to mark this repository.
15.2 KiB · text
History
f908e46