diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 05dc293..1eb81a2 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -1,54 +1,107 @@
name: Build Docs
on:
- release:
- types: [published]
- workflow_dispatch:
+ pull_request:
+ paths: ['src/**', 'docs/**', 'tools/*docs.php', 'phpdoc.dist.xml', '.github/workflows/docs.yml']
push:
+ branches: [main]
+ paths: ['src/**', 'docs/**', 'tools/*docs.php', 'phpdoc.dist.xml', '.github/workflows/docs.yml']
+ workflow_dispatch:
permissions:
- contents: write
+ contents: read
+
+concurrency:
+ group: documentation-${{ github.ref }}
+ cancel-in-progress: false
jobs:
- docs:
- runs-on: ubuntu-latest
- # A published release, a manual dispatch, or a push whose head commit message
- # contains "build docs" - the convention DiscordPHP uses, so the site is not
- # rebuilt and redeployed on every commit.
- if: >-
- github.event_name == 'release'
- || github.event_name == 'workflow_dispatch'
- || (github.event_name == 'push' && contains(github.event.head_commit.message, 'build docs'))
+ build:
+ runs-on: ubuntu-24.04
+ timeout-minutes: 15
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
+ - name: Checkout source
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ persist-credentials: false
- name: Setup PHP
- uses: shivammathur/setup-php@v2
+ uses: shivammathur/setup-php@db91e1a0e48e84637d325a7ee4d2677e146ceec4 # 2.36.0
with:
php-version: '8.4'
extensions: iconv, mbstring
- tools: composer
-
- # The DiscordPHP family's build of phpDocumentor, carrying its patches for
- # `?T|null` types. Not on Packagist, hence the explicit repository.
- - name: Install phpDocumentor
+ coverage: none
+ tools: composer:2.9.8
+ - name: Install local PlantUML and Graphviz for the class diagram
+ run: |
+ sudo apt-get update -qq
+ sudo apt-get install --yes --no-install-recommends graphviz plantuml
+ - name: Checkout pinned phpDocumentor toolchain
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ repository: discord-php/phpdoc-tool
+ ref: 40e5911a592e5fc4407096cebd5fb4aaf2e9df6f
+ path: phpdoc-tool
+ persist-credentials: false
+ - name: Install locked toolchain and reviewed nullable-type patches
run: >-
- composer create-project discord-php/phpdoc-tool:^1.0 phpdoc-tool
- --no-interaction --no-progress
- --repository='{"type":"vcs","url":"https://github.com/discord-php/phpdoc-tool"}'
-
- - name: Build the reference
- run: php tools/build-docs.php
-
- - name: Disable Jekyll
- # Without this, GitHub Pages hides every path beginning with an underscore.
- run: touch build/.nojekyll
+ composer install --working-dir=phpdoc-tool --no-dev --no-interaction
+ --no-scripts --prefer-dist --no-progress
+ - name: Generate and validate public output
+ env:
+ PHPDOC_PLANTUML: plantuml
+ PHPDOC_PLANTUML_BIN: /usr/bin/plantuml
+ run: |
+ php tools/build-docs.php
+ php tools/check-docs.php
+ - name: Archive only generated public files
+ run: tar --directory build -cf "$RUNNER_TEMP/artifact.tar" .
+ - name: Retain Pages artifact for one day
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ with:
+ name: github-pages
+ path: ${{ runner.temp }}/artifact.tar
+ retention-days: 1
+ if-no-files-found: error
- - name: Publish to gh-pages
- uses: JamesIves/github-pages-deploy-action@v4
+ publish:
+ needs: build
+ if: >-
+ github.event_name != 'pull_request' &&
+ github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
+ runs-on: ubuntu-24.04
+ timeout-minutes: 8
+ permissions:
+ contents: write # GitHub cannot branch-scope this; only generated gh-pages is written.
+ pages: write
+ id-token: write
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Checkout repository metadata for gh-pages publisher
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ ref: ${{ github.sha }}
+ persist-credentials: false
+ - name: Download this run's generated site
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
+ with:
+ name: github-pages
+ path: pages-artifact
+ - name: Restore the validated site
+ run: |
+ mkdir site
+ tar -xf pages-artifact/artifact.tar --directory site
+ - name: Preserve generated gh-pages copy
+ uses: JamesIves/github-pages-deploy-action@fa24774553152dd7873cd16ebd8d959b010c5445 # v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: gh-pages
- folder: build
+ folder: site
clean: true
+ clean-exclude: CNAME
+ # GITHUB_TOKEN pushes do not themselves trigger a branch Pages build.
+ # Explicitly deploy the same artifact instead of assuming gh-pages is live.
+ - name: Publish the exact Pages artifact
+ id: deployment
+ uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
diff --git a/README.md b/README.md
index b96f0d9..6d2b60c 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,9 @@ reachable from PHP.
## Requirements
+[Documentation and guides](https://valgorithms.github.io/YoutubePHP/) ยท
+[GitHub Actions uploader setup](https://valgorithms.github.io/YoutubePHP/guides/github-actions-uploader.html)
+
- PHP 8.4 or newer
- ext-json, ext-mbstring
diff --git a/docs/github-actions-uploader.md b/docs/github-actions-uploader.md
index 1703d6d..e3e0c02 100644
--- a/docs/github-actions-uploader.md
+++ b/docs/github-actions-uploader.md
@@ -7,7 +7,7 @@ schedule. A PR producing a video must never receive the channel credentials.
YouTubePHP supplies the API client, OAuth refresh and multipart media calls. It
does **not** supply Google consent, GitHub environment configuration, artifact
provenance, human content approval or a durable upload journal. Those are the
-repository integration's responsibility. The [small PHP example](../examples/ReviewedUpload.php)
+repository integration's responsibility. The [small PHP example](https://github.com/Valgorithms/YoutubePHP/blob/main/examples/ReviewedUpload.php)
is tested with a fake transport; it deliberately has no executable CLI or default
journal. The [Civ13 example](civ13-uploader-example.md) links a complete, separately
tested integration, including its controller and setup helper. **Copying the two
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..2a324ed
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,15 @@
+# YouTubePHP guides
+
+YouTubePHP is an asynchronous ReactPHP client for the YouTube Data API v3.
+The generated class reference documents the API surface. These guides explain
+how to connect it to a reviewed application.
+
+- [GitHub Actions uploader setup](github-actions-uploader.md): Google consent,
+ protected credentials, workflow templates, library calls and required controller
+ safeguards for a manually approved video upload.
+- [Civ13 uploader case study](civ13-uploader-example.md): the exact tested source,
+ successful run, durable receipt and fixes behind a working deployment.
+- [Building and publishing these docs](publishing.md): the pinned phpDocumentor
+ toolchain, local validation and bounded GitHub Pages deployment.
+
+Source and issues: [Valgorithms/YoutubePHP](https://github.com/Valgorithms/YoutubePHP).
diff --git a/docs/publishing.md b/docs/publishing.md
new file mode 100644
index 0000000..12dad9d
--- /dev/null
+++ b/docs/publishing.md
@@ -0,0 +1,57 @@
+# Building and publishing the documentation
+
+`phpdoc.dist.xml` builds the API reference from `src/` and Markdown guides from
+`docs/`. Only the generated `build/` directory is published. No credentials,
+client JSON, source dependencies or private evidence trees belong in that output.
+
+The existing DiscordPHP-family phpDocumentor toolchain is pinned in the workflow
+to `40e5911a592e5fc4407096cebd5fb4aaf2e9df6f`, with its own committed Composer lock
+and reviewed nullable-type patches. Its Composer patch plugin is intentional;
+the uploader consumer's no-plugin installation policy is a different project.
+Graphviz `dot` and local PlantUML must be installed for the generated class diagram.
+Set `PHPDOC_PLANTUML=plantuml` and `PHPDOC_PLANTUML_BIN` to the local PlantUML
+executable (CI uses `/usr/bin/plantuml`). The Composer distribution does not bundle
+the binary assumed by its default renderer. No remote diagram service is used.
+The configuration
+also explicitly sets `graphs.enabled=true`; phpDocumentor disables graph rendering
+by default even though its default template emits a diagram-page link.
+
+For a local build, install that toolchain in `phpdoc-tool/` as its own project,
+or point `PHPDOC` at an existing trusted toolchain's `vendor/bin/phpdoc`. Then run:
+
+```bash
+php tools/build-docs.php
+php tools/check-docs.php
+php -S 127.0.0.1:8000 -t build
+```
+
+The checker verifies required API/guide pages, all local href/src targets with
+HTML base semantics, output size (32 MiB), regular files, and absence of common
+private-file/diagnostic/token patterns. These are bounded smoke checks, not a
+claim that an arbitrary secret is detectable. Review source content before merging.
+The docs builder keeps tool diagnostics out of public HTML buffers.
+
+The Build Docs workflow validates PRs without deploying. Default-branch docs/source
+pushes and manual default-branch dispatches generate and validate the site, retain
+one artifact for one day, then publish that same artifact. Builds use read-only
+repository permissions; only the default-branch publish job receives Contents
+write (for `gh-pages`), Pages write and the OIDC token used by `deploy-pages`.
+Jobs use standard public Ubuntu runners, timeouts, no schedule or paid service.
+
+The `gh-pages` branch contains generated files. `CNAME`, if present, is preserved;
+do not add unrelated content to a generated branch. No custom domain is configured
+by this change. GitHub-token pushes alone do not trigger branch-based Pages builds,
+so the workflow also uses GitHub's Pages artifact deployment explicitly. Configure
+the repository's Pages publishing source as **GitHub Actions**. The Pages settings
+and `github-pages` environment are separate from any YouTube upload environment;
+this workflow never accesses Google credentials or changes upload gates.
+
+Before calling the site live, verify the deployment's source revision, successful
+publish job, configured Pages URL and anonymous responses for the landing page,
+API reference, uploader guide and case study. Source generation alone is not a
+live deployment. The default address is
+`https://valgorithms.github.io/YoutubePHP/`.
+
+References: [phpDocumentor configuration](https://docs.phpdoc.org/guide/references/configuration.html),
+[custom Pages workflows](https://docs.github.com/en/pages/getting-started-with-github-pages/using-custom-workflows-with-github-pages),
+[Pages publishing source](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site).
diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml
index b29bc49..2eb8338 100644
--- a/phpdoc.dist.xml
+++ b/phpdoc.dist.xml
@@ -15,7 +15,14 @@
'],
+ ['