forked from Solo-Web-Works/Projects-Portfolio
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.
This commit is contained in:
@@ -0,0 +1,293 @@
|
|||||||
|
# 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*']`. 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.0` → `1.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:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
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:
|
||||||
|
```bash
|
||||||
|
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**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
|
||||||
|
## 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:
|
||||||
|
```bash
|
||||||
|
grep -n "Building a Release" README.md
|
||||||
|
```
|
||||||
|
Expected: one matching line, located after the "Connect Your Gitea Repo" section.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
```php
|
||||||
|
define( 'PROJECTS_PORTFOLIO_VERSION', '1.1.0' );
|
||||||
|
```
|
||||||
|
Replace with:
|
||||||
|
```php
|
||||||
|
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:
|
||||||
|
```bash
|
||||||
|
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**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
```bash
|
||||||
|
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**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git status
|
||||||
|
# If clean, skip. Otherwise:
|
||||||
|
git add -A
|
||||||
|
git commit -m "Final verification fixes"
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user