Files
Projects-Portfolio/plans/2026-08-11-release-workflow.md
T
Keith Solomon 67a28e0037 Add release workflow implementation plan
4-task plan: workflow file, README section, version bump to 1.1.1,
final verification. No PHP behavior changes; PHPUnit suite unaffected.
2026-08-11 06:45:10 -05:00

10 KiB

Release Workflow Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Add a GitHub Actions workflow that, on every v* tag push, builds projects-portfolio-v<version>.zip from an allowlist of runtime files and publishes it both as a workflow artifact and as an attachment to a matching GitHub release.

Architecture: Single workflow file at .github/workflows/release.yml. One job (release) on ubuntu-latest performs: checkout → bash build step (allowlisted cp -r into a staging dir, then zip -r) → actions/upload-artifact@v4softprops/action-gh-release@v2. Uses the runner-provided GITHUB_TOKEN with contents: write permission.

Tech Stack: GitHub Actions YAML, bash, zip CLI (preinstalled on ubuntu-latest), actions/checkout@v4, actions/upload-artifact@v4, softprops/action-gh-release@v2.

Global Constraints

  • Workflow file lives at .github/workflows/release.yml.
  • Trigger: on.push.tags: ['v*']. No workflow_dispatch.
  • Permission: contents: write.
  • Zip filename: projects-portfolio-v<version>.zip where <version> is GITHUB_REF_NAME with leading v stripped.
  • Zip internal layout: projects-portfolio/ directory at zip root, with projects-portfolio.php inside it (WordPress install-from-zip convention).
  • Allowlisted source paths copied into staging: projects-portfolio.php, README.md, LICENSE, admin/, assets/, includes/, languages/, templates/.
  • Excluded paths (no cp of these): composer.json, composer.lock, vendor/, tests/, phpunit.xml, phpunit.xml.dist, .phpunit.result.cache, plans/, specs/, .github/, .gitignore, .vscode/, .claude/.
  • Build step uses set -euo pipefail and an unzip -l "$OUT" debug print at the end so the action log self-documents the contents.
  • Artifact upload uses if-no-files-found: error so a missing zip fails the job.
  • softprops/action-gh-release@v2 is given the tag name, release name = tag name, generate_release_notes: true, and files: pointing at the zip.
  • README gets a "Building a Release" section after "Connect Your Gitea Repo".
  • First release is v1.1.1: implementation includes a version bump from 1.1.01.1.1 (header Version: + PROJECTS_PORTFOLIO_VERSION constant).
  • No PHP files outside of the version bump are touched. The PHPUnit suite is unaffected.

File Structure

Created:

  • .github/workflows/release.yml — the workflow.

Modified:

  • README.md — adds a "Building a Release" section after the existing "Connect Your Gitea Repo" section.
  • projects-portfolio.php — bumps header Version: and PROJECTS_PORTFOLIO_VERSION from 1.1.0 to 1.1.1 as part of the first-release rollout.

No other files touched. No tests added.


Task 1: Add the release workflow file

Files:

  • Create: .github/workflows/release.yml

Interfaces:

  • Produces: a workflow that triggers on v* tag push and produces a release zip + GitHub release.

  • Step 1: Create .github/workflows/release.yml

Create the directory if missing, then create the file with this exact content:

name: Release

on:
  push:
    tags:
      - 'v*'

permissions:
  contents: write

jobs:
  release:
    name: Build & publish plugin zip
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Build plugin zip
        working-directory: ${{ github.workspace }}
        run: |
          set -euo pipefail
          VERSION="${GITHUB_REF_NAME#v}"
          STAGE="dist/staging"
          OUT="dist/projects-portfolio-v${VERSION}.zip"

          rm -rf dist
          mkdir -p "$STAGE/projects-portfolio"

          cp projects-portfolio.php "$STAGE/projects-portfolio/"
          cp README.md             "$STAGE/projects-portfolio/"
          cp LICENSE               "$STAGE/projects-portfolio/"
          cp -r admin/             "$STAGE/projects-portfolio/"
          cp -r assets/            "$STAGE/projects-portfolio/"
          cp -r includes/          "$STAGE/projects-portfolio/"
          cp -r languages/         "$STAGE/projects-portfolio/"
          cp -r templates/         "$STAGE/projects-portfolio/"

          ( cd "$STAGE" && zip -r "../../$OUT" projects-portfolio )

          echo "Built $OUT"
          unzip -l "$OUT"

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: projects-portfolio-v${{ github.ref_name }}
          path: dist/projects-portfolio-*.zip
          if-no-files-found: error

      - name: Create GitHub release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ github.ref_name }}
          name: ${{ github.ref_name }}
          generate_release_notes: true
          files: dist/projects-portfolio-*.zip
  • Step 2: Validate YAML syntax locally

Run from the project root:

php -r "require 'vendor/autoload.php';" 2>/dev/null || true
# PHP doesn't have a built-in YAML parser; use Python's if available
python -c "import yaml,sys; yaml.safe_load(open('.github/workflows/release.yml').read()); print('OK')"

If python is not on PATH, use any other YAML validator you have. If none is available, skip this step — GitHub's own workflow validation will catch syntax errors on the next push.

Expected (if python is available): OK on stdout, exit 0.

  • Step 3: Commit
git add .github/workflows/release.yml
git commit -m "Add GitHub Actions release workflow"

Task 2: Add "Building a Release" section to README

Files:

  • Modify: README.md

Interfaces:

  • Produces: a "Building a Release" section placed after the "Connect Your Gitea Repo" section (which was added in the previous feature).

  • Step 1: Insert the new section

Find the existing ## Connect Your Gitea Repo section in README.md. Locate the heading ## Building a Release (it does not yet exist; that's the insertion target).

Insert the following block directly after the closing line of the Gitea repo subsection (Paste it into the plugin settings screen under **Gitea API Token**.) and before any subsequent ## heading:


## Building a Release

Releases are automated via GitHub Actions. To cut a new release:

1. Bump `PROJECTS_PORTFOLIO_VERSION` and the plugin header `Version:` in `projects-portfolio.php`.
2. Commit and push to `main`.
3. Tag the release commit: `git tag -a v1.1.0 -m "v1.1.0 — short summary"`.
4. Push the tag: `git push origin v1.1.0`.

The `.github/workflows/release.yml` workflow runs and:

- Builds `projects-portfolio-v<version>.zip` containing only the runtime files (`projects-portfolio.php`, `admin/`, `assets/`, `includes/`, `languages/`, `templates/`, `README.md`, `LICENSE`).
- Uploads the zip as a workflow artifact.
- Creates (or updates) the matching GitHub Release with the zip attached.

Dev-only paths (`composer.json`, `composer.lock`, `vendor/`, `tests/`, `plans/`, `specs/`, `.github/`, `.gitignore`, `.vscode/`, `.claude/`) are intentionally excluded.
  • Step 2: Verify with grep

Run:

grep -n "Building a Release" README.md

Expected: one matching line, located after the "Connect Your Gitea Repo" section.

  • Step 3: Commit
git add README.md
git commit -m "Document automated release process in README"

Task 3: Bump version to 1.1.1 for first automated release

Files:

  • Modify: projects-portfolio.php — header Version: and PROJECTS_PORTFOLIO_VERSION constant.

Interfaces:

  • Produces: in-tree version 1.1.1, header comment line * Version: 1.1.1, constant define( 'PROJECTS_PORTFOLIO_VERSION', '1.1.1' );.

  • Step 1: Update the plugin header

In projects-portfolio.php, in the file header comment block near the top, change:

 * Version:     1.1.0

to:

 * Version:     1.1.1
  • Step 2: Update the version constant

In projects-portfolio.php, find the line:

define( 'PROJECTS_PORTFOLIO_VERSION', '1.1.0' );

Replace with:

define( 'PROJECTS_PORTFOLIO_VERSION', '1.1.1' );
  • Step 3: Run the test suite to confirm no regression

Run: php vendor/bin/phpunit Expected: OK (24 tests, 45 assertions) (same as before — no PHP behavior change).

  • Step 4: Verify with grep

Run:

grep -n "Version:" projects-portfolio.php | head -1
grep -n "PROJECTS_PORTFOLIO_VERSION" projects-portfolio.php

Expected output:

  • First grep: a line containing * Version: 1.1.1.

  • Second grep: two lines — the define(...) and (possibly) usage sites. The define line must show '1.1.1'.

  • Step 5: Commit

git add projects-portfolio.php
git commit -m "Bump version to 1.1.1 for first automated release"

Task 4: Final verification

Files: none (verification only).

  • Step 1: Confirm all three commits landed

Run:

git log --oneline -5

Expected (most recent at top): three commits from this plan are visible:

  • "Bump version to 1.1.1 for first automated release"

  • "Document automated release process in README"

  • "Add GitHub Actions release workflow"

  • Step 2: Confirm working tree is clean

Run: git status Expected: nothing to commit, working tree clean.

  • Step 3: Run full PHPUnit suite

Run: php vendor/bin/phpunit Expected: OK (24 tests, 45 assertions).

  • Step 4: Confirm workflow file content

Run:

head -30 .github/workflows/release.yml

Expected: matches the YAML produced in Task 1, with name: Release, on.push.tags: ['v*'], permissions.contents: write, and the release job.

  • Step 5: Confirm README has the new section

Run:

grep -c "Building a Release" README.md

Expected: 1.

  • Step 6: Note (do NOT execute): the first automated release

The user will tag v1.1.1 and push the tag themselves, which triggers the workflow. The workflow file is in place; the in-tree version is bumped; the first release will produce a zip with this code. The implementer does NOT push the tag or the branch — that's the user's call (their existing git history is ahead of origin/main).

  • Step 7: Final commit if anything changed
git status
# If clean, skip. Otherwise:
git add -A
git commit -m "Final verification fixes"