# Puts the downloadable builds on the repository's Releases page. # # Nothing here leaves GitHub: a release is exactly as visible as the repository it sits # on. This is *not* the PyPI publish — that is `release.yml`, it is a separate act, and it # does not run from here. # # Triggered by pushing a version tag, which is the moment a release exists in git anyway: # # git tag -a v0.3.0 -m "MeshTerm 0.3.0" # git push origin v0.3.0 # # The binaries are built by `installers.yml`, called rather than copied, so the files # people download are made exactly the way the ones CI checks on every push are. # # Once the release exists, `website` puts it on meshterm.net: it rebuilds that site from # the tagged tree — the landing and About pages carry the version — and pushes the result # to jpmartineau/meshterm.net, which GitHub Pages serves. It writes with a deploy key # scoped to that one repository (secret SITE_DEPLOY_KEY); that repo's README makes one. name: GitHub release on: push: tags: ["v*"] workflow_dispatch: inputs: tag: description: "Existing tag to build a release from (e.g. v0.2.0)" required: true type: string prerelease: description: "Mark as a pre-release (keeps it out of 'Latest')" type: boolean default: false permissions: contents: read jobs: build: uses: ./.github/workflows/installers.yml publish: name: create the release needs: build runs-on: ubuntu-latest timeout-minutes: 10 permissions: # The one job that needs it: creating a release writes to the repository. contents: write steps: - uses: actions/checkout@v4 with: ref: ${{ inputs.tag || github.ref }} # Every platform's artifact, flattened into one directory of files to attach. - uses: actions/download-artifact@v4 with: # The build uploads one artifact nobody should ever download: the unsigned # Windows binary it hands to SignPath. Everything meant for the release page is # named `meshterm-…`, so the pattern is the filter. pattern: meshterm-* path: artifacts merge-multiple: true - name: Gather the binaries and their checksums id: gather shell: bash run: | mkdir -p release find artifacts -type f -exec mv {} release/ \; ls -lh release/ # One combined checksum file is easier to verify against than five loose ones. (cd release && cat *.sha256 > SHA256SUMS && rm -f *.sha256) tag="${{ inputs.tag || github.ref_name }}" echo "tag=$tag" >> "$GITHUB_OUTPUT" echo "version=${tag#v}" >> "$GITHUB_OUTPUT" - name: Take the release notes from the changelog id: notes shell: bash env: VERSION: ${{ steps.gather.outputs.version }} run: | # The section for this version, between its own heading and the next one. If the # changelog has nothing for it, say so plainly rather than inventing notes. # # Extracted once, into the file, and the *file* is what gets tested. It used to # run twice — once down a `| sed | head -1 | grep -q .` pipeline to decide, then # again for real — and this step runs under `bash -e -o pipefail`, where that # pipeline is a race it can lose. `head -1` exits the moment it has its line and # closes the pipe; if `sed` still has bytes to write it dies on SIGPIPE, pipefail # promotes that to a failed condition, and a version with a perfectly good # changelog section publishes "No changelog entry" instead. It only bites once a # section outgrows one buffered write, which is why every entry under 4 KB was # fine and 0.3.1 was not — while 0.3.0, the same size, happened to win. awk -v v="$VERSION" ' $0 ~ "^## \\[" v "\\]" {found=1; next} found && /^## \[/ {exit} found {print} ' CHANGELOG.md > notes.md if ! grep -q '[^[:space:]]' notes.md; then echo "No changelog entry for $VERSION." > notes.md fi echo "--- notes ---"; cat notes.md - name: Create it env: GH_TOKEN: ${{ github.token }} TAG: ${{ steps.gather.outputs.tag }} PRERELEASE: ${{ inputs.prerelease && '--prerelease' || '' }} run: | gh release create "$TAG" release/* \ --title "MeshTerm ${TAG#v}" \ --notes-file notes.md \ --verify-tag \ $PRERELEASE echo "https://github.com/${{ github.repository }}/releases/tag/$TAG" website: name: put the version on meshterm.net needs: publish # A pre-release stays out of "Latest", so it stays off the landing page too. if: ${{ !inputs.prerelease }} runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Check for the deploy key env: SITE_DEPLOY_KEY: ${{ secrets.SITE_DEPLOY_KEY }} run: | if [ -z "$SITE_DEPLOY_KEY" ]; then echo "::error::SITE_DEPLOY_KEY is not set; the meshterm.net README says how to make it." exit 1 fi - uses: actions/checkout@v4 with: ref: ${{ inputs.tag || github.ref }} path: meshterm - uses: actions/checkout@v4 with: repository: jpmartineau/meshterm.net ssh-key: ${{ secrets.SITE_DEPLOY_KEY }} path: site - uses: actions/setup-python@v5 with: python-version: "3.12" - name: Rebuild the site from this release run: | python -m pip install --quiet -r site/requirements.txt python site/build.py --meshterm meshterm - name: Publish it working-directory: site env: TAG: ${{ inputs.tag || github.ref_name }} run: | git add -A if git diff --cached --quiet; then echo "meshterm.net already shows ${TAG#v}." exit 0 fi git config user.name "github-actions[bot]" git config user.email "41898341+github-actions[bot]@users.noreply.github.com" git commit -m "MeshTerm ${TAG#v}" git push