4-task plan: workflow file, README section, version bump to 1.1.1, final verification. No PHP behavior changes; PHPUnit suite unaffected.
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@v4 → softprops/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*']. Noworkflow_dispatch. - Permission:
contents: write. - Zip filename:
projects-portfolio-v<version>.zipwhere<version>isGITHUB_REF_NAMEwith leadingvstripped. - Zip internal layout:
projects-portfolio/directory at zip root, withprojects-portfolio.phpinside 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
cpof 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 pipefailand anunzip -l "$OUT"debug print at the end so the action log self-documents the contents. - Artifact upload uses
if-no-files-found: errorso a missing zip fails the job. softprops/action-gh-release@v2is given the tag name, release name = tag name,generate_release_notes: true, andfiles: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 from1.1.0→1.1.1(headerVersion:+PROJECTS_PORTFOLIO_VERSIONconstant). - 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 headerVersion:andPROJECTS_PORTFOLIO_VERSIONfrom1.1.0to1.1.1as 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— headerVersion:andPROJECTS_PORTFOLIO_VERSIONconstant.
Interfaces:
-
Produces: in-tree version
1.1.1, header comment line* Version: 1.1.1, constantdefine( '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. Thedefineline 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"