Adding insert-date and insert-time #13
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |