App-Ariza.git | resources/templates/ci/ | release.yml.j2


# Build a self-contained {{ app_display }} bundle for every platform
# {{ app_name }} declares in ariza.toml, prove each one runs, and publish
# them on a tag.
#
# Generated by ariza {{ ariza_version }} (`ariza scaffold-ci`) from these
# bundle.platforms:
#
#     {{ slugs | join(', ') }}
#
# Re-run scaffold-ci after changing that list: this file is rewritten in
# place, so a hand edit here is an edit you will make twice.
#
# Two triggers, and only one of them publishes anything:
#
#   * workflow_dispatch builds and smokes every lane and stops there,
#     with an optional `ref` so a recipe can be iterated on a branch.
#     A broken lane costs a run, not a tag.
#
#   * a pushed release tag ({{ tag_globs | join(' or ') }} — the
#     v-prefixed shape humans write, and the bare one mi6 creates)
#     does all of that, then publishes the
#     archives, then installs the published one on a clean machine.

name: release

on:
  workflow_dispatch:
    inputs:
      ref:
        description: >-
          Branch, tag or SHA to build. Defaults to the ref the run was
          started from.
        required: false
        type: string
  push:
    tags:
{%- for glob in tag_globs %}
      - '{{ glob }}'
{%- endfor %}

permissions:
  contents: write

env:
  LANG: en_US.UTF-8
  LC_ALL: en_US.UTF-8

jobs:
{{ lane_jobs }}

  publish:
    name: publish
    needs:
{%- for job in job_names %}
      - {{ job }}
{%- endfor %}
    # Tag-gated: everything above this line has already proved itself by
    # the time anything is published, and a dispatch run is free to fail.
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
{% if updates_enabled %}      - name: Require an exact bare update version tag
        shell: bash
        run: |
          set -euo pipefail
          if [[ ! "$GITHUB_REF_NAME" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "update-enabled releases require a bare X.Y.Z tag; got: $GITHUB_REF_NAME" >&2
            exit 1
          fi

{% endif %}      - name: Download every lane's artefact
        uses: actions/download-artifact@v7
        with:
          path: downloaded/

      - name: Flatten, and build one checksums.txt over the lot
        shell: bash
        run: |
          set -euxo pipefail
          mkdir -p release
          find downloaded -type f \( -name '*.tar.gz' \
                                 -o -name '*.zip' \
                                 -o -name '*.sha256' \) \
            -exec cp {} release/ \;

          # ariza writes a `<archive>.sha256` sidecar beside each bundle,
          # and install.sh checks it. checksums.txt is those same digests
          # in one file, for a human with `sha256sum -c`. Recomputed here
          # rather than concatenated, and then checked against the
          # sidecars: a release whose digest refuses its own archive is
          # worse than one with no digest at all.
          cd release
          : > ../checksums.txt
          for f in *; do
            case $f in *.sha256) continue ;; esac
            sha256sum "$f" >> ../checksums.txt
          done
          sort -o ../checksums.txt ../checksums.txt
          sha256sum -c -- *.sha256
          cd ..

          echo '--- checksums.txt ---'
          cat checksums.txt

      - name: Create the release
        uses: softprops/action-gh-release@v3
        with:
          tag_name: {% raw %}${{ github.ref_name }}{% endraw %}
          name: {{ app_display }} {% raw %}${{ github.ref_name }}{% endraw %}
          files: |
            release/*
            checksums.txt
          body: |
            Each archive below is a **self-contained bundle**:
            {{ app_display }}, a Rakudo runtime ({{ rakudo_tag }}), every Raku
            dependency with its bytecode already compiled, and every native
            library the application loads. There is nothing to install
            first -- no Raku, no compiler, no package manager. Unpack it
            anywhere, run `bin/{{ app_exec }}`, and delete the directory when
            you are done: that is the uninstall.

            ### Platforms
{% for floor in floors %}
            - `{{ floor.slug }}`
{%- for line in floor.note %}
              {{ line }}
{%- endfor %}
{%- endfor %}

            A bundle runs on the platform it names and no other. It carries
            compiled code, so there is no nearest match to fall back on.
{%- if repo %}

            ### Installing

            ```
            curl -fsSL https://raw.githubusercontent.com/{{ repo }}/HEAD/install.sh | sh
            ```

            That script picks the right archive for the machine it runs on,
            verifies its SHA-256, unpacks it under
            `$XDG_DATA_HOME/{{ app_exec }}/versions/` and links
            `~/.local/bin/{{ app_exec }}` at it. Windows has `install.ps1`
            beside it. Neither needs root, and `uninstall.sh` /
            `uninstall.ps1` undo exactly what they did.
{%- endif %}

            ### Verifying a download

            ```
            sha256sum -c checksums.txt
            ```

            Or one archive at a time, against the `.sha256` published beside
            it. On macOS, `shasum -a 256 -c` reads either.
          draft: false
          prerelease: false
{%- if smoke_jobs %}

{{ smoke_jobs }}
{%- endif %}
{%- if no_smoke_platforms %}

  # No clean-runner installer smoke for {{ no_smoke_platforms | join(', ') }}:
  # ariza has no GitHub-hosted runner recipe for
  # {{ 'it' if no_smoke_platforms | length == 1 else 'them' }} yet (see
  # App::Ariza::CI's %LANES). The bundle above is still built and smoked in
  # its own build lane; only the installer itself, on a clean machine, goes
  # unproven here.
{%- endif %}