Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/wiki
Submodule wiki deleted from 961cfb
12 changes: 11 additions & 1 deletion .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,18 @@ jobs:
safe-directories: |
${{ github.workspace }}/.github/wiki

- name: Refresh wiki preview pointer for release pull request
- name: Detect legacy Wiki gitlink
if: ${{ steps.create_pr.outputs.pull-request-number != '' }}
id: legacy_wiki
run: |
if git ls-files --stage -- .github/wiki | grep -q '^160000 '; then
echo 'present=true' >> "$GITHUB_OUTPUT"
else
echo 'present=false' >> "$GITHUB_OUTPUT"
fi

- name: Refresh wiki preview pointer for release pull request
if: ${{ steps.create_pr.outputs.pull-request-number != '' && steps.legacy_wiki.outputs.present == 'true' }}
id: refresh_release_preview
uses: ./.dev-tools-actions/.github/actions/wiki/refresh-preview-pointer
with:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/retry-transient-failures.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ on:
- Maintain Wiki Publication
- Update Wiki Preview
- Update Wiki
- Fast Forward Wiki Update
types:
- completed

Expand Down
122 changes: 122 additions & 0 deletions .github/workflows/wiki-direct.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
name: Publish Wiki Directly

on:
workflow_call:

permissions:
contents: read

jobs:
generate:
runs-on: ubuntu-latest
timeout-minutes: 20
outputs:
generated: ${{ steps.generate.outputs.generated }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- name: Checkout the shared dev-tools actions
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: php-fast-forward/dev-tools
ref: d5a3b7eec9896f9ea50974ff09b23c32887acbc0
path: .dev-tools-actions
persist-credentials: false
- name: Resolve PHP version
id: php
uses: ./.dev-tools-actions/.github/actions/php/resolve-version
- name: Setup PHP and dependencies
uses: ./.dev-tools-actions/.github/actions/php/setup-composer
with:
php-version: ${{ steps.php.outputs.php-version }}
root-version: dev-main
install-options: --prefer-dist --no-progress --no-interaction --no-plugins --no-scripts
- name: Install the pinned Markdown renderer
working-directory: .dev-tools-actions
env:
COMPOSER_ROOT_VERSION: dev-main
run: composer install --prefer-dist --no-progress --no-interaction --no-scripts
- name: Generate API pages
id: generate
run: |
has_api=$(php -r 'require ".dev-tools-actions/vendor/autoload.php"; echo FastForward\DevTools\Container\ContainerFactory::get(FastForward\DevTools\Project\ProjectCapabilitiesResolverInterface::class)->resolve()->canGenerateApiDocumentation() ? "true" : "false";')
echo "generated=${has_api}" >> "$GITHUB_OUTPUT"
if [ "$has_api" = false ]; then
echo 'No autoloaded PHP API directories; skip Wiki generation and publication.'
exit 0
fi
mkdir -p vendor/bin vendor/saggre/phpdocumentor-markdown/themes/markdown
cp .dev-tools-actions/vendor/bin/phpdoc vendor/bin/phpdoc
chmod +x vendor/bin/phpdoc
rsync -a --delete .dev-tools-actions/vendor/saggre/phpdocumentor-markdown/themes/markdown/ vendor/saggre/phpdocumentor-markdown/themes/markdown/
if [ "$GITHUB_REPOSITORY" = php-fast-forward/dev-tools ]; then
./bin/dev-tools wiki --target=.dev-tools/wiki-generated --cache-dir="${RUNNER_TEMP}/wiki-phpdoc-cache"
else
export DEV_TOOLS_BINARY="$GITHUB_WORKSPACE/.dev-tools-actions/bin/dev-tools"
export DEV_TOOLS_AUTOLOAD="$GITHUB_WORKSPACE/.dev-tools-actions/vendor/autoload.php"
export DEV_TOOLS_AUTO_RESOLVE_AUTOLOAD="$DEV_TOOLS_AUTOLOAD"
export DEV_TOOLS_RUNTIME_SOURCE=workflow
./.dev-tools-actions/bin/dev-tools wiki --target=.dev-tools/wiki-generated --cache-dir="${RUNNER_TEMP}/wiki-phpdoc-cache"
fi
test -s .dev-tools/wiki-generated/Home.md
Comment thread
coisa marked this conversation as resolved.
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
if: steps.generate.outputs.generated == 'true'
with:
name: wiki
path: .dev-tools/wiki-generated
Comment thread
coisa marked this conversation as resolved.
if-no-files-found: error

publish:
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' && needs.generate.outputs.generated == 'true'
needs: generate
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: write
concurrency:
group: ${{ github.repository }}-wiki-publication
cancel-in-progress: false
queue: max
steps:
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: wiki
path: wiki-generated
- name: Publish API pages
env:
GH_TOKEN: ${{ github.token }}
run: |
current=$(gh api "repos/${GITHUB_REPOSITORY}/commits/main" --jq .sha)
if [ "$current" != "$GITHUB_SHA" ]; then
echo 'A newer main run will publish the current documentation.'
exit 0
fi
git -c credential.helper= -c 'credential.helper=!gh auth git-credential' clone "https://github.com/${GITHUB_REPOSITORY}.wiki.git" wiki
if find wiki-generated wiki -path wiki/.git -prune -o \( -type l -o -name AGENTS.md \) -print -quit | grep -q .; then
echo 'Unexpected symlink or agent instruction page.' >&2
exit 1
fi
if find wiki-generated -type f ! -name '*.md' -print -quit | grep -q .; then
echo 'Generated Wiki payload must contain only Markdown.' >&2
exit 1
fi
# classes/ and functions/ are phpDocumentor-owned API namespaces.
# Pages outside those namespaces are preserved.
for namespace in classes functions; do
mkdir -p "wiki-generated/${namespace}" "wiki/${namespace}"
rsync -a --delete "wiki-generated/${namespace}/" "wiki/${namespace}/"
done
cp wiki-generated/Home.md wiki/Home.md
git -C wiki add --all
if ! git -C wiki diff --cached --quiet; then
git -C wiki config user.name 'github-actions[bot]'
git -C wiki config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git -C wiki commit -m "Update Wiki from ${GITHUB_SHA}"
current=$(gh api "repos/${GITHUB_REPOSITORY}/commits/main" --jq .sha)
if [ "$current" != "$GITHUB_SHA" ]; then
echo 'Main advanced during generation; skip outdated publication.'
exit 0
fi
git -C wiki -c credential.helper= -c 'credential.helper=!gh auth git-credential' push origin HEAD
fi
20 changes: 6 additions & 14 deletions .github/workflows/wiki-maintenance-entry.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
name: Maintain Wiki
name: Legacy Wiki Maintenance

on:
workflow_dispatch:
schedule:
- cron: '17 3 * * *'
pull_request_target:
types: [closed]

concurrency:
group: update-wiki-maintenance-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions: {}

jobs:
maintenance:
permissions:
contents: write
pull-requests: read
uses: ./.github/workflows/wiki-maintenance.yml
secrets: inherit
migration:
runs-on: ubuntu-latest
steps:
- run: echo 'Wiki publication now runs through wiki.yml without a submodule.'
20 changes: 8 additions & 12 deletions .github/workflows/wiki.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
name: Update Wiki
name: Fast Forward Wiki Update
Comment thread
coisa marked this conversation as resolved.

on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:

concurrency:
group: update-wiki-preview-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: write # Ceiling for the isolated publisher; generation remains read-only.

jobs:
preview:
permissions:
actions: write
contents: write
pull-requests: read
uses: ./.github/workflows/wiki-preview.yml
secrets: inherit
wiki:
uses: ./.github/workflows/wiki-direct.yml
Comment thread
coisa marked this conversation as resolved.
6 changes: 0 additions & 6 deletions .gitmodules

This file was deleted.

13 changes: 9 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ other managed assets through `composer dev-tools:sync`.

Release and publishing behavior is driven primarily through
`.github/workflows/tests.yml`, `changelog.yml`, `reports.yml`, `wiki.yml`,
`wiki-preview.yml`, `wiki-maintenance.yml`, `auto-assign.yml`, and
`wiki-direct.yml`, `auto-assign.yml`, and
`label-sync.yml`, with reusable local workflow building blocks grouped under
`.github/actions/` and packaged consumer workflow wrappers living under
`resources/github-actions/`. Contract-specific templates in
Expand All @@ -167,6 +167,11 @@ installed by `dev-tools:sync`; read each companion guide before copying one
into a consumer repository. Packaged skills live under `.agents/skills/`
alongside mirrored project-agent prompts under `.agents/agents/`.

The active `wiki.yml` entry and packaged wrapper call `wiki-direct.yml` for
read-only generation on pull requests and direct publication from `main`.
The maintenance entry is manual-only compatibility guidance; legacy reusable
`wiki-preview.yml` and `wiki-maintenance.yml` remain for unmigrated callers.

**Package Details:**

- Type: `composer-plugin`
Expand Down Expand Up @@ -198,22 +203,22 @@ composer dev-tools
- `README.md`: high-level command surface, architecture overview, and consumer-facing context
- `docs/commands/`: command-specific behavior and option details
- `docs/usage/` and `docs/internals/`: workflow, reporting, release, and implementation notes
- `.github/workflows/`: CI and release automation truth, especially `tests.yml`, `reports.yml`, `review.yml`, `wiki.yml`, `wiki-preview.yml`, `wiki-maintenance.yml`, `changelog.yml`, `auto-assign.yml`, and `label-sync.yml`
- `.github/workflows/`: CI and release automation truth, especially `tests.yml`, `reports.yml`, `review.yml`, `wiki.yml`, `wiki-direct.yml`, `changelog.yml`, `auto-assign.yml`, and `label-sync.yml`
- `.github/actions/`: shared workflow building blocks for `php`, `project-board`, `github-pages`, `review`, `summary`, `wiki`, `changelog`, and `label-sync`
- `resources/github-actions/`: consumer-facing workflow wrappers synchronized by `dev-tools:sync`
- [resources/github-actions-optional/test-statuses.md](resources/github-actions-optional/test-statuses.md): explicit opt-in guide for Dependabot status aliases; verify source workflow identity, PHP matrix and protection contexts before adopting the checkout-free template
- `.github/pull_request_template.md`: expected PR structure and reviewer checklist
- `src/Sync/`: shared packaged-directory synchronization primitives used by `skills` and `agents`
- `.agents/skills/`: packaged procedural skills shipped to consumer repositories
- `.agents/agents/`: repository-specific role prompts mirrored through `.github/agents`
- `.github/wiki`: generated or synchronized wiki content published by repo workflows
- `.dev-tools/wiki-generated`: local Markdown output from normal sync; wiki publication operates on a separate artifact and Wiki checkout

## Additional Notes

- **GrumPHP**: Automatically runs on pre-commit (configured in `grumphp.yml`)
- **Rector**: Custom rules in `src/Rector/` for automated refactoring
- **Documentation**: Sphinx-based docs in `docs/` directory
- **Wiki**: Pull-request preview publication starts in `.github/workflows/wiki.yml`, while merged publication and preview cleanup run through `.github/workflows/wiki-maintenance.yml`
- **Wiki**: `.github/workflows/wiki.yml` delegates to `wiki-direct.yml`; pull requests generate without write credentials and only `main` publishes to the separate Wiki repository. `Home.md`, `classes/` and `functions/` are generated; preserve manually maintained pages outside those surfaces. Normal sync does not initialize a Wiki submodule; `wiki --init` remains an explicit legacy option.
- **GitHub Actions**: Reusable workflows live in `.github/workflows/`, local workflow actions live in `.github/actions/`, and consumer wrappers are synchronized from `resources/github-actions/`
- **Dependency Health CI**: `.github/workflows/tests.yml` always runs the dependency-health job, and its default `max-outdated` input is `-1` so outdated packages are reported without failing CI on count alone
- **Sync Preview Modes**: `dev-tools:sync --dry-run`, `--check`, and `--interactive` intentionally skip wiki, skills, and agents because those flows do not yet expose non-destructive verification
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Composer(deps): Update ergebnis/phpunit-agent-reporter requirement from ^0.3 to ^1.0 (#356)
- GitHub Actions(deps): Bump actions/checkout from 6 to 7 (#354)
- GitHub Actions(deps): Bump EndBug/add-and-commit from 10 to 11 (#358)
- Publish generated API pages directly to the GitHub Wiki from main without parent submodule-pointer commits, while pull requests generate read-only artifacts.
- Generate local wiki Markdown in .dev-tools/wiki-generated during normal sync instead of initializing a Wiki submodule; retain explicit wiki --init for legacy use.

### Fixed

- Isolate native Pages PR builds from production deployment queues, preserve full repository history in generated metrics, and retry downloaded identity hashes during CDN propagation.

- Keep required per-version statuses current across normal and Dependabot reruns through checkout-free lifecycle publishers using verified GitHub run and job metadata.
- Keep Composer audit and nested dependency-health checks plugin-free after CI installs without plugins, so consumer allowlists do not block vulnerability or dependency analysis.
- Isolate completed per-version status publication from repository-controlled test jobs, preserve access to private GitHub job metadata, and disable persisted checkout credentials in the reusable test workflow.
Expand Down
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ composer update-composer-json --force

# Installs and synchronizes dev-tools scripts, GitHub Actions workflows,
# .editorconfig, .gitignore rules, packaged skills, packaged agents, and the
# repository wiki submodule in .github/wiki
# local wiki Markdown in .dev-tools/wiki-generated
composer dev-tools:sync
```

Expand All @@ -193,6 +193,14 @@ to synthesize API pages. When `.github/wiki` is absent and no wiki has been
initialized yet, `wiki` now skips generation with a warning instead of failing
the whole automation run.

Normal `dev-tools:sync` generates local Markdown in `.dev-tools/wiki-generated`
without creating a Git submodule. The packaged `wiki.yml` workflow publishes
generated API pages directly to the GitHub Wiki from `main`; pull requests
generate a read-only artifact. Existing workflow wrappers require an explicit
migration or `composer dev-tools:sync --overwrite` to adopt these changes. See
[the workflow guide](docs/usage/github-actions.rst) for publication and page
ownership details.

The changelog commands manage Keep a Changelog 1.1.0 files without requiring
extra tooling in the consumer repository. `changelog:entry` bootstraps a
missing changelog file on first use, `changelog:check` enforces meaningful
Expand Down Expand Up @@ -329,7 +337,7 @@ skills they depend on.
| `composer funding` | Synchronizes managed funding metadata between `composer.json` and `.github/FUNDING.yml`. |
| `composer codeowners` | Generates managed `.github/CODEOWNERS` content from local repository metadata. |
| `composer gitattributes` | Manages export-ignore rules in `.gitattributes`. |
| `composer dev-tools:sync` | Updates scripts, CODEOWNERS, funding metadata, workflow stubs, `.editorconfig`, `.gitignore`, `.gitattributes`, wiki setup, packaged skills, and packaged agents. |
| `composer dev-tools:sync` | Updates scripts, CODEOWNERS, funding metadata, workflow stubs, `.editorconfig`, `.gitignore`, `.gitattributes`, local wiki Markdown, packaged skills, and packaged agents. |
| `vendor/bin/dev-tools self-update` / `composer dev-tools:self-update` | Updates the local DevTools package, or the Composer global installation when the active binary is globally installed. |

`--working-dir`/`-d` changes the project root used by the standalone binary.
Expand Down Expand Up @@ -370,7 +378,7 @@ authoring.
the console application itself.
- `Consumer Sync Pipeline` - `dev-tools:sync` refreshes `composer.json`,
CODEOWNERS, funding metadata, workflow stubs, repository defaults, git
metadata files, packaged Git hooks, and, in normal mode, the wiki submodule
metadata files, packaged Git hooks, and, in normal mode, local wiki Markdown
plus packaged skills and packaged project agents.

## 🤝 Contributing
Expand Down
Loading
Loading