Workflows
Remote sources only write local folders under your markdown root. Every recipe below just points a normal build at those folders, using the same two commands:
php bin/docsmith sync # fetch/update remote sources
php bin/docsmith build # or: php bin/docsmith build --sync
Recipe 1: Docs hub from several repositories
Sync three repositories into three targets, then build one hub with a dropdown:
// docsmith.sources.php
return [
[
'repository' => 'https://github.com/laravel/docs.git',
'ref' => '12.x',
'path' => '',
'target' => 'laravel',
],
[
'repository' => 'https://github.com/acme/auth-jobs.git',
'ref' => 'main',
'path' => 'docs',
'target' => 'auth-jobs',
],
[
'repository' => 'https://github.com/acme/blog-kit.git',
'ref' => 'main',
'path' => 'guide',
'target' => 'blog-kit',
],
];
// build.php
use Docsmith\Docsmith;
Docsmith::make()
->output(__DIR__ . '/docs')
->title('Acme Developer Portal')
->hub([
'laravel' => ['label' => 'Laravel Docs', 'source' => __DIR__ . '/md/laravel'],
'auth-jobs' => ['label' => 'Auth Jobs', 'source' => __DIR__ . '/md/auth-jobs'],
'blog-kit' => ['label' => 'Blog Kit', 'source' => __DIR__ . '/md/blog-kit'],
])
->build();
The dropdown lists Laravel Docs, Auth Jobs, and Blog Kit, each mounted at its own slug.
Recipe 2: One repository, two branches as versions
Sync the same repository twice with different refs. Name the targets after your version slugs so a single source() covers both:
// docsmith.sources.php
return [
[
'repository' => 'https://github.com/acme/auth-jobs.git',
'ref' => 'main',
'path' => 'docs',
'target' => 'v2',
],
[
'repository' => 'https://github.com/acme/auth-jobs.git',
'ref' => '1.x',
'path' => 'docs',
'target' => 'v1',
],
];
use Docsmith\Docsmith;
Docsmith::make()
->source(__DIR__ . '/md')
->output(__DIR__ . '/docs')
->versions([
['slug' => 'v2', 'label' => 'v2.0', 'default' => true],
['slug' => 'v1', 'label' => 'v1.0'],
])
->build();
Each version reads {source}/{slug}, so v2 reads md/v2 and v1 reads md/v1. If you prefer target names like auth-jobs-2x, set a source on each version explicitly instead of relying on the slug.
The flagged default version owns the site root.
Recipe 3: Hub entry with versions from synced branches
Combine both: other packages in the dropdown, plus one package with two synced branches as embedded versions:
// docsmith.sources.php - Recipe 1 manifest plus:
[
'repository' => 'https://github.com/acme/auth-jobs.git',
'ref' => '1.x',
'path' => 'docs',
'target' => 'auth-jobs-1x',
],
->hub([
'laravel' => ['label' => 'Laravel Docs', 'source' => __DIR__ . '/md/laravel'],
'auth-jobs' => [
'label' => 'Auth Jobs',
'source' => __DIR__ . '/md/auth-jobs', // backs the default version (ref: main)
'versions' => [
['slug' => 'v2', 'label' => 'v2', 'default' => true], // /auth-jobs/
['slug' => 'v1', 'label' => 'v1', 'source' => __DIR__ . '/md/auth-jobs-1x'], // /auth-jobs/v1/
],
],
])
In the built site the dropdown shows only "Auth Jobs", never "Auth Jobs v1", while its pages carry v1/v2 pills.
Recipe 4: Plain single site from one repository
No hub, no versions. Sync one repo and build it directly:
// docsmith.sources.php
return [
[
'repository' => 'https://github.com/acme/my-package.git',
'ref' => 'main',
'path' => 'docs',
'target' => 'my-package',
],
];
php bin/docsmith build --sync --source=md/my-package --output=docs
Nothing is fetched at build time unless --sync asks for it. When the lock file already matches the remote refs, repeat syncs do nothing.
GitHub Actions workflow
This .github/workflows/docs.yml works for any of the recipes above:
name: Build docs
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
tools: composer:v2
- run: composer install --no-interaction --prefer-dist --no-progress
# Syncs remote sources (incremental when docsmith.sources.lock.json
# matches) and builds in one step.
- run: php bin/docsmith build --sync
env:
ACME_PAT: ${{ secrets.ACME_PAT }} # only needed for private sources
- uses: actions/upload-pages-artifact@v3
with:
path: docs
Add a deploy job with actions/deploy-pages@v4 (enable GitHub Pages with Source: GitHub Actions), or upload to any static host.
Notes:
- Commit
docsmith.sources.lock.jsonso repeat runs sync incrementally. Delete it to force a full refresh. - Locally, tokens may also live in a
.envfile next todocsmith.sources.php. Real environment variables always take precedence. - Sync failures exit non-zero and fail the workflow.
- Private repositories need a token; see Remote Sources.
- Keep synced sources public or provide a token via repository secrets.
Rebuild automatically when a source repository updates
The workflow above only runs when the docs repository itself changes. When a synced package updates its docs, nothing tells your site to rebuild. Close that gap with GitHub's cross-repository repository_dispatch: each source repository notifies the docs repository after a push, which then syncs and rebuilds.
1. Listen for the event (docs repository)
Extend the on block of .github/workflows/docs.yml:
on:
push:
branches: [main]
repository_dispatch:
types: [content-updated]
workflow_dispatch:
The existing php bin/docsmith build --sync step needs no changes. A dispatched run simply fetches the updated sources before building.
2. Notify the docs repository (each source repository)
Add this .github/workflows/notify-docs.yml to every synced package:
name: Notify docs site
on:
push:
branches:
- main
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Trigger docs rebuild
env:
TOKEN: ${{ secrets.DOCS_DISPATCH_TOKEN }}
run: |
if [ -z "$TOKEN" ]; then
echo "DOCS_DISPATCH_TOKEN is not set"
exit 1
fi
curl --fail --show-error -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/acme/acme-docs/dispatches \
-d '{"event_type": "content-updated"}'
Replace acme/acme-docs with your docs repository. Keep --fail --show-error so HTTP errors fail the step instead of passing silently.
3. Create the access token
- Create a fine-grained personal access token in GitHub Developer Settings.
- Under Repository Access, select only the docs repository.
- Set the Contents permission to Read and write.
- Save it as
DOCS_DISPATCH_TOKENin each source repository's Actions secrets.
Fine-grained tokens keep dispatch access limited to exactly the target repository.
How it fits together
auth-jobs repo: push docs -> notify workflow -> repository_dispatch
|
acme-docs repo: build --sync <- content-updated --+
A merged PR in any synced package now ends with an up-to-date site. No manual rebuilds and no scheduled polling.