diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 9c9be7c..8d4177a 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -3,12 +3,12 @@ This directory contains the GitHub workflows for this template. Each workflow and any supporting files will be documented here. -### [Build LaTeX](./build-latex.yml) +## [Build LaTeX](./build-latex.yml) [build-latex.yml](./build-latex.yml) is a reusable workflow that can be used to build a LaTeX document, and upload the resulting PDF as an artifact. -### [Build Release](./build-release.yml) +## [Build Release](./build-release.yml) [build-release.yml](./build-release.yml) contains the main build workflow for this repo. It will: @@ -28,7 +28,7 @@ this, edit the following line: DOCUMENT_BASE_NAME: ${{ github.event.repository.name }} ``` -### [Create From Template](./create-from-template.yml) +## [Create From Template](./create-from-template.yml) [create-from-template.yml](./create-from-template.yml) is designed to run only once, when a new repository is created from the template. On the first `push` @@ -41,7 +41,7 @@ specification. > Remove this section after creating your repo from this template, as the > workflow will be deleted. -### [Fast Forward](./fast-forward.yml) +## [Fast Forward](./fast-forward.yml) A workflow that allows using the `/fast-forward` command to complete a PR, and merge it with the `git merge --ff-only` strategy. This is paired with the @@ -71,7 +71,7 @@ Replacing `FF_PAT` with the name of your access token. > [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens), > this workflow will not be able to trigger other workflows when merging. -### [Lint Commits](./lint-commits.yml) +## [Lint Commits](./lint-commits.yml) [lint-commits.yml](./lint-commits.yml) uses [git-cliff](https://git-cliff.org/) to lint all commits in the repo with every PR, ensuring that they conform to the @@ -84,11 +84,27 @@ The main [cliff.toml](../../cliff.toml) is used as the configuration file to configure `git-cliff`, which should require conventional commits for this workflow to function correctly. +## [Prep Build](./prep-build.yml) + +[Prep Build](./prep-build.yml) is a reusable workflow that can be used to +prepare the variables used to build the LaTeX document, and prepare the +changelog and upload it as an artifact. + +The prepared variables are: + +- The CHANGELOG (both as an artifact and variable containing the contents) +- The versioned document name +- The bumped version number + ## [Pull Request](./pull-request.yml) -This workflow simply monitors the commits in a PR, and checks whether they can -be fast-forwarded. This is paired with the [fast forward](#fast-forward) -workflow. +This workflow simply monitors the commits in a PR, checks whether they can be +fast-forwarded, and generates a preview CHANGELOG and PDF file that are posted +as comments on the PR to allow review of the generated contents. + +This is paired with the [fast forward](#fast-forward) workflow to close PRs +using the `git merge --ff-only` strategy. -This workflow is optional, and you can remove this workflow along with the -[fast forward](#fast-forward) workflow to use GitHub's default merge strategies. +The `check-fast-forward` job in this workflow is optional, and you can remove +this job along with the [fast forward](#fast-forward) workflow to use GitHub's +default merge strategies. diff --git a/.github/workflows/build-latex.yml b/.github/workflows/build-latex.yml index ec29e85..914f4f1 100644 --- a/.github/workflows/build-latex.yml +++ b/.github/workflows/build-latex.yml @@ -3,8 +3,8 @@ # # GitHub Actions workflow to build a LaTeX document. # -# Note that this workflow is intended to be called by other workflows, after the -# repo has been checked out. It is not intended to be run directly. +# Note that this workflow is intended to be called by other workflows. It is not +# intended to be run directly. name: Build LaTeX Document @@ -16,22 +16,43 @@ env: on: workflow_call: inputs: - document-name: - description: "The name to use for the generated PDF document (without the .pdf extension)." + artifact-name: + description: "The artifact name to upload the generated .pdf under." required: true type: string - artifact-name: - description: "The name to use for the uploaded PDF artifact." + checkout-ref: + description: "The git ref to checkout for building the document." + required: false + default: ${{ github.ref }} + type: string + checkout-repository: + description: "The git repo to checkout when building the document." + required: false + default: ${{ github.repository }} + type: string + document-name: + description: "The file name to use for the generated PDF document (without the .pdf extension)." required: true type: string + outputs: + artifact-url: + description: "The URL of the uploaded PDF artifact." + value: ${{ jobs.build-latex.outputs.artifact_url }} jobs: build-latex: name: Build LaTeX Document runs-on: ubuntu-latest + outputs: + artifact_url: ${{ steps.upload-pdf.outputs.artifact-url }} steps: - name: Checkout Repository uses: actions/checkout@v5 + with: + # Checkout the specified ref and repository to ensure this workflow + # can be used for PRs from fork repos. + ref: ${{ inputs.checkout-ref }} + repository: ${{ inputs.checkout-repository }} # Install packages required to build LaTeX documents. This includes: # - texlive: The core LaTeX distribution. @@ -71,9 +92,11 @@ jobs: name: Build LaTeX document run: | # Create the build directory if it doesn't exist. + echo "Ensuring ${{ env.BUILD_DIR }} exists..." mkdir -p ${{ env.BUILD_DIR }} # Build the document using latexmk. + echo "Building LaTeX document with latexmk..." latexmk \ -pdf \ -interaction=nonstopmode \ @@ -83,12 +106,13 @@ jobs: main.tex # Output the path to the generated PDF as a step output. - echo "pdf=build/${{ inputs.document-name }}.pdf" >> $GITHUB_OUTPUT + echo "LaTeX document built at ${{ env.BUILD_DIR }}/${{ inputs.document-name }}.pdf" + echo "pdf=${{ env.BUILD_DIR }}/${{ inputs.document-name }}.pdf" >> $GITHUB_OUTPUT # Upload the generated PDF as an artifact for use in subsequent jobs. - id: upload-pdf name: Upload PDF Artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: ${{ inputs.artifact-name }} path: ${{ steps.build-latex.outputs.pdf }} diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 08a0a0b..f89ec39 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -9,7 +9,9 @@ name: Build and Release Document # Define environment variables for reuse in the workflow, so that they can be # easily updated in one place. env: - CLIFF_OUTPUT: CHANGELOG.md + CHANGELOG_ARTIFACT_NAME: changelog + CHANGELOG_NAME: CHANGELOG.md + DOCUMENT_ARTIFACT_NAME: latex-build DOCUMENT_BASE_NAME: ${{ github.event.repository.name }} # Releases will be triggered by changes pushed to main. @@ -22,71 +24,60 @@ permissions: contents: write # To create tags and releases. jobs: - prep: - name: Prepare Version and Changelog + eval: + name: Evaluate Workflow Preconditions runs-on: ubuntu-latest outputs: - changelog: ${{ steps.git-cliff.outputs.content }} - version: ${{ steps.sanitise-version.outputs.version }} - filename: ${{ steps.generate-filename.outputs.filename }} + changelog_artifact_name: ${{ env.CHANGELOG_ARTIFACT_NAME }} + changelog_name: ${{ env.CHANGELOG_NAME }} + document_artifact_name: ${{ env.DOCUMENT_ARTIFACT_NAME }} + document_base_name: ${{ env.DOCUMENT_BASE_NAME }} + should_run: ${{ steps.evaluate_run_conditions.outputs.should_run }} steps: - name: Checkout Repository uses: actions/checkout@v5 - with: - fetch-depth: 0 # Fetch full history for changelog generation. - - # Use git-cliff to generate a changelog and determine the next version. - # - # This will generate a changelog for all unreleased changes and bump the - # version based on commit messages since the last tag. - - name: git-cliff - id: git-cliff - uses: orhun/git-cliff-action@v4 - with: - version: latest - config: cliff.toml - args: "--unreleased --bump" - env: - OUTPUT: ${{ env.CLIFF_OUTPUT }} - # Upload the generated changelog for use in subsequent jobs. - - id: upload-changelog - name: Upload Changelog Artifact - uses: actions/upload-artifact@v4 - with: - name: changelog - path: ${{ env.CLIFF_OUTPUT }} - if-no-files-found: error - - # Sanitise the version number to ensure it has a single 'v' prefix. - - name: Sanitise Version - id: sanitise-version + # Evaluate whether the workflow should run or not. + - name: Evaluate Run Conditions + id: evaluate_run_conditions run: | - version="${{ steps.git-cliff.outputs.version }}" - version="v${version//v}" - echo "Sanitised version: $version" - echo "version=$version" >> $GITHUB_OUTPUT + # This workflow should not run for the initial commit in the repo, as + # the initial template document is not a meaningful release to + # publish. + echo "Checking current commit count..." + if [ "$(git rev-list --count HEAD)" -eq 1 ]; then + # If this is running on the first commit, do not run the workflow. + echo "Initial commit detected; skipping workflow run." + echo "should_run=false" >> $GITHUB_OUTPUT + else + # Otherwise, the workflow should run. + echo "Multiple commits detected; running workflow." + echo "should_run=true" >> $GITHUB_OUTPUT + fi - # Generate the file name for the PDF based on the base name and version. - - name: Generate File Name - id: generate-filename - run: | - echo "Generating filename for version ${{ steps.git-cliff.outputs.version }}" - filename="${{ env.DOCUMENT_BASE_NAME }}_${{ steps.sanitise-version.outputs.version }}" - echo "Generated filename: $filename" - echo "filename=$filename" >> $GITHUB_OUTPUT + prep: + name: Prepare Version and Changelog + needs: [eval] + if: ${{ needs.eval.outputs.should_run == 'true' }} + uses: ./.github/workflows/prep-build.yml + with: + changelog-artifact-name: ${{ needs.eval.outputs.changelog_artifact_name }} + changelog-name: ${{ needs.eval.outputs.changelog_name }} + document-base-name: ${{ needs.eval.outputs.document_base_name }} build: name: Build LaTeX Document + needs: [eval, prep] + if: ${{ needs.eval.outputs.should_run == 'true' }} uses: ./.github/workflows/build-latex.yml - needs: prep with: - artifact-name: latex-build - document-name: ${{ needs.prep.outputs.filename }} + artifact-name: ${{ needs.eval.outputs.document_artifact_name }} + document-name: ${{ needs.prep.outputs.document-name }} release: name: Create Release - needs: [prep, build] + needs: [eval, prep, build] + if: ${{ needs.eval.outputs.should_run == 'true' }} runs-on: ubuntu-latest steps: - name: Checkout Repository @@ -94,15 +85,15 @@ jobs: - name: Download Build Artifacts id: download-latex - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: - name: latex-build + name: ${{ needs.eval.outputs.document_artifact_name }} - name: Download Changelog Artifact id: download-changelog - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: - name: changelog + name: ${{ needs.eval.outputs.changelog_artifact_name }} # Create a draft release with the generated changelog and attach the PDF. # This is needed for repos that use "immutable releases", since otherwise @@ -118,7 +109,7 @@ jobs: body: ${{ needs.prep.outputs.changelog }} files: | ${{ steps.download-latex.outputs.download-path }}/*.pdf - ${{ steps.download-changelog.outputs.download-path }}/${{ env.CLIFF_OUTPUT }} + ${{ steps.download-changelog.outputs.download-path }}/${{ needs.eval.outputs.changelog_name }} env: GIT_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/create-from-template.yml b/.github/workflows/create-from-template.yml index ca2a7f2..2f8c5c8 100644 --- a/.github/workflows/create-from-template.yml +++ b/.github/workflows/create-from-template.yml @@ -33,6 +33,7 @@ jobs: # Remove this workflow file from the new repository. - name: "Remove Template Specific Files" run: | + echo "Removing create-from-template.yml workflow file..." rm -f "./.github/workflows/create-from-template.yml" # Amend the initial commit with the removed workflow, and change the @@ -40,11 +41,13 @@ jobs: - name: "Update Initial Commit" run: | # Configure the git user to the GitHub Actions actor. + echo "Configuring git user..." git config user.name "${{ github.actor }}" git config user.email "${{ github.actor }}@users.noreply.github.com" # Add the changes and amend the initial commit, updating the commit # message. + echo "Amending initial commit..." git add . git commit --amend -m "chore: initial commit" git push --force-with-lease diff --git a/.github/workflows/lint-commits.yml b/.github/workflows/lint-commits.yml index 9243a1e..e3c3acd 100644 --- a/.github/workflows/lint-commits.yml +++ b/.github/workflows/lint-commits.yml @@ -61,13 +61,18 @@ jobs: # This will also output a preview of the changelog that would be generated # for the PR. - name: Lint Commits and Preview Changelog - run: git cliff --config cliff.toml + run: | + # Run git-cliff to lint commits. The config ensures that this will + # return an error if any unconventional commits are found. + echo "Linting commits with git-cliff..." + git cliff --config cliff.toml # Determine the proposed version bump based on the commits in the PR. - name: Propose Version Bump id: version-bump run: | # Use git-cliff to get the proposed version bump. + echo "Getting proposed version bump..." version="$(git-cliff --bumped-version)" # Strip any leading 'v' if present to get a clean version number. diff --git a/.github/workflows/prep-build.yml b/.github/workflows/prep-build.yml new file mode 100644 index 0000000..8bc5838 --- /dev/null +++ b/.github/workflows/prep-build.yml @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) 2025 Nathaniel Struselis +# +# GitHub Actions workflow to prepare variables for building the LaTeX document. +# +# Note that this workflow is intended to be called by other workflows. It is not +# intended to be run directly. + +name: Build LaTeX Document + +# Define environment variables for reuse in the workflow, so that they can be +# easily updated in one place. +env: + BUILD_DIR: build + +on: + workflow_call: + inputs: + changelog-artifact-name: + description: "The artifact name to upload the CHANGELOG under." + required: false + default: "changelog" + type: string + changelog-name: + description: "The filename of the CHANGELOG to generate." + required: false + default: "CHANGELOG.md" + type: string + checkout-ref: + description: "The git ref to checkout when generating the CHANGELOG." + required: false + default: ${{ github.ref }} + type: string + checkout-repository: + description: "The git repo to checkout when generating the CHANGELOG." + required: false + default: ${{ github.repository }} + type: string + document-base-name: + description: "The base name to use for the generated PDF document (without the .pdf extension). The version number will be appended to this base name." + required: false + default: ${{ github.event.repository.name }} + type: string + outputs: + changelog: + description: "The generated CHANGELOG content." + value: ${{ jobs.prep.outputs.changelog }} + document-name: + description: "The name of the generated .pdf document, including version number but excluding the .pdf extension." + value: ${{ jobs.prep.outputs.filename }} + version: + description: "The bumped version number." + value: ${{ jobs.prep.outputs.version }} + +jobs: + prep: + name: Prepare Version and Changelog + runs-on: ubuntu-latest + outputs: + changelog: ${{ steps.git-cliff.outputs.content }} + filename: ${{ steps.generate-filename.outputs.filename }} + version: ${{ steps.sanitise-version.outputs.version }} + steps: + - name: Checkout Repository + uses: actions/checkout@v5 + with: + fetch-depth: 0 # Fetch full history for changelog generation. + # Checkout the specified ref and repository to ensure this workflow + # can be used for PRs from fork repos. + ref: ${{ inputs.checkout-ref }} + repository: ${{ inputs.checkout-repository }} + + # Use git-cliff to generate a changelog and determine the next version. + # + # This will generate a changelog for all unreleased changes and bump the + # version based on commit messages since the last tag. + - name: git-cliff + id: git-cliff + uses: orhun/git-cliff-action@v4 + with: + version: latest + config: cliff.toml + args: "--unreleased --bump" + env: + OUTPUT: ${{ inputs.changelog-name }} + + # Upload the generated changelog for use in subsequent jobs. + - id: upload-changelog + name: Upload Changelog Artifact + uses: actions/upload-artifact@v5 + with: + name: ${{ inputs.changelog-artifact-name }} + path: ${{ inputs.changelog-name }} + if-no-files-found: error + + # Sanitise the version number to ensure it has a single 'v' prefix. + - name: Sanitise Version + id: sanitise-version + run: | + echo "Getting new version number..." + version="${{ steps.git-cliff.outputs.version }}" + echo "Original version: $version" + version="v${version//v}" + echo "Sanitised version: $version" + echo "version=$version" >> $GITHUB_OUTPUT + + # Generate the file name for the PDF based on the base name and version. + - name: Generate File Name + id: generate-filename + run: | + echo "Generating filename for version ${{ steps.sanitise-version.outputs.version }}..." + filename="${{ inputs.document-base-name }}_${{ steps.sanitise-version.outputs.version }}" + echo "Generated filename: $filename" + echo "filename=$filename" >> $GITHUB_OUTPUT diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index bb27d13..ff37313 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -1,10 +1,17 @@ -# Workflow to check whether the commits in a PR can be fast-forwarded, and post -# a comment on the PR with the result. +# SPDX-License-Identifier: MIT +# Copyright (c) 2025 Nathaniel Struselis # -# This workflow is based on the example from sequoia-pgp/fast-forward GitHub, -# which is licensed under GPL v2: https://github.com/sequoia-pgp/fast-forward. +# GitHub Actions workflow to check whether the commits in a PR can be +# fast-forwarded, build a preview PDF and changelog, and post comments on the PR +# with the fast forward status and previews. -name: Check Pull Request for Fast Forward +name: Check PR Fast Forward and Post Document Preview + +# Define environment variables for reuse in the workflow, so that they can be +# easily updated in one place. +env: + BOT_USER: github-actions[bot] + PR_COMMENT_TITLE: "# Document Preview" on: pull_request: @@ -29,4 +36,93 @@ jobs: uses: sequoia-pgp/fast-forward@v1 with: merge: false - comment: always \ No newline at end of file + comment: always + + changelog-preview: + name: Prepare Preview Version and Changelog + uses: ./.github/workflows/prep-build.yml + with: + # Checkout the PR head ref and repo to ensure the real commit information + # is available, and ensure PRs from forks are supported. + checkout-ref: ${{ github.event.pull_request.head.ref }} + checkout-repository: ${{ github.event.pull_request.head.repo.full_name }} + + build-preview: + name: Build LaTeX Document Preview + needs: [changelog-preview] + uses: ./.github/workflows/build-latex.yml + with: + artifact-name: preview-build + # Checkout the PR head ref and repo to ensure the real commit information + # is available, and ensure PRs from forks are supported. + checkout-ref: ${{ github.event.pull_request.head.ref }} + checkout-repository: ${{ github.event.pull_request.head.repo.full_name }} + document-name: ${{ needs.changelog-preview.outputs.document-name }} + + publish-preview: + name: Upload Preview Document and Changelog + needs: [changelog-preview, build-preview] + runs-on: ubuntu-latest + + # Permissions required to post / update comments on the PR with the preview + # document and changelog. + permissions: + pull-requests: write + issues: write + + steps: + - name: Download Preview Build Artifacts + id: download-latex-preview + uses: actions/download-artifact@v6 + with: + name: preview-build + + # Generate the comment to post on the PR containing the PDF and CHANGELOG + # previews. + - name: Generate PR Comment Content + id: generate-pr-comment + run: | + echo "Generating PR comment content..." + + comment_content=$(cat <> $GITHUB_OUTPUT + echo "$comment_content" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + # Find if there is an existing preview comment on the PR. If there is, it + # can be edited instead of creating a new comment. + - name: Find Existing Preview Comment + uses: peter-evans/find-comment@v4 + id: find-comment + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: ${{ env.BOT_USER }} + body-includes: ${{ env.PR_COMMENT_TITLE }} + direction: last + + # If no existing comment was found, create a new comment on the PR with + # the preview document and changelog. + - name: Create PR Preview Comment + if: ${{ steps.find-comment.outputs.comment-id == '' }} + uses: peter-evans/create-or-update-comment@v5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.pull_request.number }} + body: ${{ steps.generate-pr-comment.outputs.comment_content }} + + # If an existing comment was found, update it with the new preview + # document and changelog. + - name: Update PR Preview Comment + if: ${{ steps.find-comment.outputs.comment-id != '' }} + uses: peter-evans/create-or-update-comment@v5 + with: + comment-id: ${{ steps.find-comment.outputs.comment-id }} + body: ${{ steps.generate-pr-comment.outputs.comment_content }} + edit-mode: replace diff --git a/front_matter/document_revision.tex b/front_matter/document_revision.tex index b65a278..0a0122d 100644 --- a/front_matter/document_revision.tex +++ b/front_matter/document_revision.tex @@ -14,5 +14,5 @@ % preamble/authors.tex to link the initials here to a name. Without doing % this, only the initials will appear for the document authors. % Example entry for NS in preamble/authors.tex: - \vhEntry{0.1.1}{2025/10/15}{NS}{Initial template version} + \vhEntry{0.1.2}{2025/11/13}{NS}{Initial template version} \end{versionhistory}