Skip to content

Adding insert-date and insert-time #13

Adding insert-date and insert-time

Adding insert-date and insert-time #13

Workflow file for this run

name: build & package
on:
push:
tags: ['v*']
workflow_dispatch:
# Sibling library repo. gtcaca tracks `main` while it and ccm are developed
# together — ccm regularly needs an API added to gtcaca in the same breath, and a
# pinned SHA would build the new ccm against the old library. The cost is that a
# tag is only reproducible as long as gtcaca's `main` doesn't move; before a real
# release, pin GTCACA_REF to the gtcaca tag ccm was built against (a one-liner —
# `ref:` takes a tag, branch or SHA).
env:
GTCACA_REPO: stricaud/gtcaca
GTCACA_REF: main
jobs:
package:
name: ${{ matrix.label }}
runs-on: ${{ matrix.os }}
permissions:
contents: write # needed to attach assets to the release
# The tag being built (e.g. v0.0.3), empty for a workflow_dispatch run. Set
# once here so every step inherits it: the C build bakes it into
# `ccm --version` (see CMakeLists), and packaging/wheel.py names the wheel
# with it — the shallow CI checkout has no tags for `git describe` to find.
env:
CCM_VERSION: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || '' }}
strategy:
fail-fast: false
matrix:
include:
# Pinned to 22.04, not ubuntu-latest, to set the glibc floor: a binary
# linked against a newer glibc will not start on an older distro, and
# `latest` silently raises that floor every time GitHub rolls the
# image. 22.04's glibc 2.35 covers Debian 12 and the current LTSes; it
# is also what the manylinux tag on the wheel is derived from.
- { os: ubuntu-22.04, label: linux-x86_64 }
# macOS arm64 only for now (Apple Silicon).
- { os: macos-14, label: macos-arm64 }
- { os: windows-latest, label: windows-x86_64 }
# Every step runs in the MSYS2 UCRT64 shell on Windows, and the default shell
# elsewhere — that is what lets one build.sh serve all three.
defaults:
run:
shell: ${{ matrix.os == 'windows-latest' && 'msys2 {0}' || 'bash' }}
steps:
- name: Set up MSYS2 (Windows)
if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
# libcaca and oniguruma are prebuilt for MinGW — the whole reason the
# Windows port is cheap. ':p' prefixes for the msystem.
pacboy: >-
toolchain:p cmake:p ninja:p
libcaca:p oniguruma:p
install: zip
- name: Checkout ccm
uses: actions/checkout@v4
with: { path: ccm }
- name: Checkout gtcaca
uses: actions/checkout@v4
with:
repository: "${{ env.GTCACA_REPO }}"
ref: "${{ env.GTCACA_REF }}"
path: gtcaca
- name: Install deps (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential cmake pkg-config patchelf \
libcaca-dev libonig-dev
- name: Install deps (macOS)
if: runner.os == 'macOS'
run: |
brew update
brew install cmake pkg-config libcaca oniguruma
- name: Build & bundle (Linux/macOS)
if: runner.os != 'Windows'
working-directory: ccm
run: |
export GTCACA_SRC="$GITHUB_WORKSPACE/gtcaca"
bash packaging/build.sh
# Separate from the step above because $GITHUB_WORKSPACE is a backslashed
# Windows path the MSYS2 shell cannot cd into; derive an MSYS path instead.
- name: Build & bundle (Windows)
if: runner.os == 'Windows'
working-directory: ccm
run: |
export GTCACA_SRC="$(cd ../gtcaca && pwd)"
bash packaging/build.sh
# Exercise the *bundled* binary (not the build-tree one): proves the
# shipped dylibs/DLLs resolve through @executable_path/../lib, $ORIGIN/../lib
# or the exe's own dir. ccm is a TUI, so smoke.py drives it through a pty
# and only fails on a dynamic-loader error (see packaging/smoke.py).
- name: Smoke-test the bundle (Linux/macOS)
if: runner.os != 'Windows'
working-directory: ccm
timeout-minutes: 5
run: python3 packaging/smoke.py "$(echo dist/cacamacs-*/bin/ccm)"
- name: Smoke-test the bundle (Windows)
if: runner.os == 'Windows'
working-directory: ccm
timeout-minutes: 5
run: python packaging/smoke.py "$(echo dist/cacamacs-*/ccm.exe)"
# Repack the bundle we just smoke-tested as a wheel, so `pip install
# cacamacs` ships the exact tree the tarball/zip ship. PyPI is a binary
# channel here — there is no Python in ccm — so the wheel is that bundle
# plus two console-script shims (`cacamacs` and `ccm`). The platform tag is
# derived from the binaries themselves (glibc / LC_BUILD_VERSION); see
# packaging/wheel.py.
#
# On Windows the wheel is built and tested with the runner's *native*
# CPython in git bash, not the MSYS2 python the rest of the job uses: an
# MSYS2 interpreter reports a mingw platform tag and so refuses to install
# a win_amd64 wheel — it would reject the very artifact we ship.
- name: Set up Python for the wheel (Windows)
if: runner.os == 'Windows'
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Build & smoke-test the wheel
working-directory: ccm
shell: bash
timeout-minutes: 10
run: |
# Pick an interpreter that actually runs: on Windows a bare `python3`
# can resolve to the Store app-execution stub, which is on PATH but is
# not an interpreter.
py=
for c in python3 python; do
if command -v "$c" >/dev/null 2>&1 && "$c" -c "import sys" >/dev/null 2>&1; then
py="$c"; break
fi
done
[ -n "$py" ] || { echo "no working python found" >&2; exit 1; }
"$py" packaging/wheel.py
# Install it the way a user would and drive both console scripts:
# proves pip kept the exec bit on the binary and that the shims launch
# the bundled ccm with its libraries resolving.
"$py" -m venv wheelenv
vbin=wheelenv/bin; [ -d "$vbin" ] || vbin=wheelenv/Scripts
"$vbin/pip" install --quiet dist/*.whl
"$py" packaging/smoke.py "$vbin/cacamacs"
"$py" packaging/smoke.py "$vbin/ccm"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: cacamacs-${{ matrix.label }}
path: |
ccm/dist/*.tar.gz
ccm/dist/*.zip
ccm/dist/*.whl
- name: Attach to release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: |
ccm/dist/*.tar.gz
ccm/dist/*.zip
ccm/dist/*.whl
# Publish the per-platform wheels as `pip install cacamacs`.
#
# Uses PyPI Trusted Publishing (OIDC): the `id-token: write` permission plus a
# publisher configured on PyPI for this repo+workflow, so there is no API token
# in repo secrets. Set that up on PyPI once, before the first tag, under
# Manage project -> Publishing (or the "pending publisher" form if the project
# does not exist yet).
publish-pypi:
name: publish to PyPI
needs: package
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- name: Collect wheels from every platform
uses: actions/download-artifact@v4
with:
pattern: cacamacs-*
path: artifacts
merge-multiple: true
# gh-action-pypi-publish uploads everything in packages-dir, and the
# artifacts carry .tar.gz/.zip too — so hand it a directory of wheels only,
# or the upload is rejected.
- name: Stage wheels
run: |
mkdir -p wheels
find artifacts -name '*.whl' -exec mv {} wheels/ \;
ls -l wheels
[ -n "$(ls -A wheels)" ] || { echo "no wheels to publish" >&2; exit 1; }
- uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: wheels