diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000000..81c68a882f --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,131 @@ +# GitHub Workflows Deployment Guide + +This directory contains the GitHub Actions workflows used to build Pixels and publish the `daily-latest` release. + +## Workflows in this directory + +- `build-pixels.yml`: reusable workflow that builds the project and optionally packages the output. +- `pr-build-check.yml`: runs the reusable build workflow for pull requests targeting `master`. +- `remove-daily-latest.yml`: reusable workflow that removes existing assets from the `daily-latest` release before a new daily build is published. +- `daily-build.yml`: scheduled and manual workflow that calls `remove-daily-latest.yml`, calls `build-pixels.yml`, updates the `daily-latest` tag, publishes the release with `gh release`, and removes old artifacts. + +## Required secret + +The release-related workflows use a repository secret named `PIXELS_DEVELOP`. + +It is currently referenced by: + +- `daily-build.yml` +- `remove-daily-latest.yml` + +`PIXELS_DEVELOP` is the secret name stored in GitHub. + +Inside workflow steps, that same secret value is passed to tools using the variable or input names that those tools expect: + +- `GH_TOKEN`: environment variable consumed by the GitHub CLI `gh` +- `github_token`: action input consumed by `c-hive/gha-remove-artifacts` + +Example: + +```yaml +env: + GH_TOKEN: ${{ secrets.PIXELS_DEVELOP }} +``` + +This does not create a second secret. It only maps the repository secret `PIXELS_DEVELOP` to the runtime environment variable name required by `gh`. + +## What the token needs to do + +`PIXELS_DEVELOP` must be able to: + +- read and update releases +- delete release assets +- create and move the `daily-latest` tag +- remove old GitHub Actions artifacts + +In practice, use one of these options: + +1. Fine-grained personal access token for this repository with at least: + `Contents: Read and write` + `Actions: Read and write` +2. Classic personal access token with `repo` scope + +If your organization restricts PAT usage, use the option that your GitHub organization allows. + +## How to create the secret + +### Option 1: Create a fine-grained personal access token + +1. In GitHub, open `Settings` for the account that will own the token. +2. Open `Developer settings`. +3. Open `Personal access tokens` -> `Fine-grained tokens`. +4. Click `Generate new token`. +5. Set: + - Token name: `pixels-daily-build` or similar + - Resource owner: the owner of this repository + - Repository access: `Only select repositories`, then select this repository + - Repository permissions: + - `Contents`: `Read and write` + - `Actions`: `Read and write` +6. Choose an expiration that matches your security policy. +7. Generate the token and copy it immediately. + +### Option 2: Create a classic personal access token + +1. In GitHub, open `Settings` for the account that will own the token. +2. Open `Developer settings`. +3. Open `Personal access tokens` -> `Tokens (classic)`. +4. Click `Generate new token`. +5. Grant the `repo` scope. +6. Generate the token and copy it immediately. + +## How to add the token as `PIXELS_DEVELOP` + +### Repository secret in the GitHub UI + +1. Open the repository on GitHub. +2. Go to `Settings` -> `Secrets and variables` -> `Actions`. +3. Open the `Secrets` tab. +4. Click `New repository secret`. +5. Set: + - Name: `PIXELS_DEVELOP` + - Secret: paste the token value +6. Click `Add secret`. + +### Repository secret with GitHub CLI + +```bash +gh secret set PIXELS_DEVELOP +``` + +GitHub CLI will prompt for the token value. + +## First-time verification + +After adding the secret: + +1. Open `Actions` in the repository. +2. Run `Pixels Daily Build and Release` with `Run workflow`. +3. Confirm that: + - the `remove` job can delete old `daily-latest` assets + - the `release` job can update the `daily-latest` tag + - the workflow can publish the new `daily-latest` release + - the `cleanup-artifact` job can remove old artifacts + +## Common failure modes + +- `Resource not accessible by integration`: + the token does not have enough permissions, or the organization blocks the token type. +- `secret not found`: + the secret name is not exactly `PIXELS_DEVELOP`. +- release deletion or tag update fails: + the token owner does not have push-level access to this repository. + +## References + +- GitHub Docs: Using secrets in GitHub Actions + https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets +- GitHub Docs: Managing your personal access tokens + https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token +- GitHub Docs: Permissions required for fine-grained personal access tokens + https://docs.github.com/en/rest/authentication/permissions-required-for-fine-grained-personal-access-tokens diff --git a/.github/workflows/daily-build.yml b/.github/workflows/daily-build.yml index 16db61f1d9..3c27529879 100644 --- a/.github/workflows/daily-build.yml +++ b/.github/workflows/daily-build.yml @@ -5,11 +5,15 @@ on: - cron: '30 1 * * *' workflow_dispatch: +permissions: + contents: write + actions: write + jobs: remove: uses: ./.github/workflows/remove-daily-latest.yml secrets: - gh_token: ${{ secrets.PIXELS_DEVELOP }} + PIXELS_DEVELOP: ${{ secrets.PIXELS_DEVELOP }} build: uses: ./.github/workflows/build-pixels.yml @@ -32,28 +36,35 @@ jobs: - name: Update daily-latest tag to latest commit run: | - git tag -d daily-latest || true - git push origin --delete daily-latest || true - git tag daily-latest - git push origin daily-latest + git tag -f daily-latest + git push origin refs/tags/daily-latest --force env: GH_TOKEN: ${{ secrets.PIXELS_DEVELOP }} - name: Create or Update Daily Release - uses: softprops/action-gh-release@v2 - with: - tag_name: daily-latest - name: "Pixels Daily Build ${{ needs.build.outputs.build_date }}" - body: | - Automated daily build created at ${{ needs.build.outputs.build_date }}. - Environment: - - Commit: ${{ needs.build.outputs.commit_hash }} - - Java: ${{ needs.build.outputs.java_version }} - - CMake: ${{ needs.build.outputs.cmake_version }} - - C++: ${{ needs.build.outputs.cxx_version }} - files: ./downloaded_package/pixels-*.tar.gz - prerelease: true - draft: false + run: | + cat > release-notes.md </dev/null 2>&1; then + gh release edit daily-latest \ + --title "Pixels Daily Build ${{ needs.build.outputs.build_date }}" \ + --notes-file release-notes.md \ + --prerelease + else + gh release create daily-latest \ + --title "Pixels Daily Build ${{ needs.build.outputs.build_date }}" \ + --notes-file release-notes.md \ + --prerelease + fi + + gh release upload daily-latest ./downloaded_package/pixels-*.tar.gz --clobber env: GH_TOKEN: ${{ secrets.PIXELS_DEVELOP }} diff --git a/.github/workflows/remove-daily-latest.yml b/.github/workflows/remove-daily-latest.yml index 32331cd54c..a0b29490a9 100644 --- a/.github/workflows/remove-daily-latest.yml +++ b/.github/workflows/remove-daily-latest.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: workflow_call: secrets: - gh_token: + PIXELS_DEVELOP: required: true jobs: @@ -24,4 +24,4 @@ jobs: gh release delete-asset daily-latest "$a" -y done env: - GH_TOKEN: ${{ secrets.gh_token }} + GH_TOKEN: ${{ secrets.PIXELS_DEVELOP }}