# Builds Icon Studio and publishes a .deb and an .rpm to this forge's
# package registries, the way the other neiam Rust projects do.
#
# x86_64 only: that is what the desktops this runs on are, and a second
# architecture is a second runner to keep alive for no one.
#
# Nothing to configure. `${{ github.token }}` is minted for the job and
# authorised to publish to THIS repository's packages and nowhere else,
# so there is no secret to create first.
name: packages
on:
push:
branches: [master]
tags: ['v*']
pull_request:
branches: [master]
env:
CARGO_TERM_COLOR: always
# 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:
package:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: Install system dependencies
run: |
set -euo pipefail
# A hosted runner is an unprivileged user with sudo; a job
# container is already root and often ships no sudo at all, so
# hardcoding either one fails before the first package is
# fetched. Ask what we are.
if [ "$(id -u)" -eq 0 ]; then
SUDO=
elif command -v sudo >/dev/null 2>&1; then
SUDO=sudo
else
echo "Not root and no sudo; cannot install system dependencies." >&2
exit 1
fi
# eframe/winit need the windowing and GL headers; rfd is built
# against the XDG portal rather than GTK, so there is no GTK
# stack here. dpkg-dev matters more than it looks: without it
# cargo-deb cannot run dpkg-shlibdeps, and the .deb ships with
# an empty Depends that installs anywhere and then fails to
# start on a machine missing libxkbcommon.
if command -v apt-get >/dev/null 2>&1; then
$SUDO apt-get update
$SUDO apt-get install -y --no-install-recommends \
build-essential pkg-config dpkg-dev rpm \
libxkbcommon-dev libwayland-dev \
libx11-dev libxcursor-dev libxrandr-dev libxi-dev \
libgl1-mesa-dev
elif command -v dnf >/dev/null 2>&1; then
$SUDO dnf install -y gcc pkgconf-pkg-config rpm-build dpkg-dev \
libxkbcommon-devel wayland-devel \
libX11-devel libXcursor-devel libXrandr-devel libXi-devel \
mesa-libGL-devel
else
echo "Unsupported package manager." >&2
exit 1
fi
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
- name: Check formatting
run: cargo fmt -- --check
- name: Run clippy
run: cargo clippy --all-targets -- -D warnings
# Includes the comparison against the icons the original studio
# shipped, so a rendering regression stops the release rather than
# being packaged.
- name: Run tests
run: cargo test --verbose
- name: Build release binary
run: cargo build --release --verbose
- name: Strip binary
run: strip target/release/icon-studio
# The icons and desktop entry are committed, but regenerating them
# proves presets/icon-studio.toml still renders — the packaged icon
# and the document that describes it cannot drift apart.
- name: Regenerate the application icon
run: |
set -euo pipefail
cargo run --release --example make_app_icon
git --no-pager diff --stat -- assets/icons || true
# Built with stable, not pinned: cargo-deb has repeatedly needed a
# newer rustc than its own declared MSRV admits. These are
# build-time utilities that never link into the binary, so holding
# them to this crate's toolchain buys nothing and breaks whenever
# the ecosystem moves. `--locked` keeps two runs a month apart
# installing the same bytes.
- name: Install the packaging tools
run: |
set -euo pipefail
cargo install cargo-deb --locked
cargo 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 nothing 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 to run the latest build.
# A tag publishes the bare Cargo version.
#
# One stamp for the whole job, so the .deb and .rpm from a single
# run agree about what they are.
- name: Stamp the package version
id: 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"
echo "version=$version" >> "$GITHUB_OUTPUT"
# Rewritten after the release build, so the binary is cached
# against the unstamped manifest and only packaging sees this.
sed -i "0,/^version = .*/s//version = \"$version\"/" Cargo.toml
# The build cache can restore a target/ that still holds packages
# from an earlier run. The publish step globs these directories, so
# a stale .deb would be re-uploaded under its old version alongside
# the new one.
- name: Clear previous package output
run: rm -rf target/debian target/generate-rpm
- name: Build the Debian package
run: cargo deb --no-build --no-strip
- name: Build the RPM package
run: cargo generate-rpm
- name: Show what was built
run: ls -l target/debian/*.deb target/generate-rpm/*.rpm
# `vars.CI_FORGE_URL` is a forge built-in, but an older forge build
# will not inject it; fall back to what the runner already knows.
- 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:-}}
if [ -z "$forge_url" ]; then
echo "No forge URL available; not publishing."
echo "PUBLISH=false" >> "$GITHUB_ENV"
exit 0
fi
echo "publishing to $forge_url"
echo "FORGE_URL=$forge_url" >> "$GITHUB_ENV"
echo "PUBLISH=true" >> "$GITHUB_ENV"
# Pull requests do not publish: a PR build is a check, and a
# registry carrying every proposed change is not one anyone can
# install from.
- name: Publish the .deb and the .rpm
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 "ci:$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 "ci:$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-icon-studio
# 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
EOF
neiam
/icon-studio
public · Issues · Pulls · Labels · Forks · Compare · Actions failure · Badges · Packages
⭐
Log in to mark this repository.
8.9 KiB · text
History
ee23a90