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
117 changes: 117 additions & 0 deletions .github/actions/deploy-subdir/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name: Assemble Pages subdirectory
description: >-
Overlays a freshly built app onto the assembled-site storage branch, adds the
SPA fallback (.nojekyll + 404.html), uploads the merged site as a Pages
artifact, and persists the merged tree back to the storage branch. This lets
each micro app deploy independently while GitHub Pages still serves a single
site (see README "Hosting").

inputs:
source-dir:
description: Freshly built directory to publish (e.g. dist/apps/portfolio/browser).
required: true
target-subdir:
description: Subdirectory within the site. Empty for the site root (the shell).
required: false
default: ''
storage-branch:
description: Branch that stores the full assembled site between deploys.
required: false
default: pages-content
preserve:
description: >-
Space-separated top-level entries to keep when publishing the site root,
so independent micro-app subdirectories survive a shell redeploy.
required: false
default: 'portfolio storybook'
github-token:
description: Token used to read and update the storage branch.
required: true

runs:
using: composite
steps:
- name: Assemble merged site 🧩
shell: bash
env:
SOURCE_DIR: ${{ inputs.source-dir }}
TARGET_SUBDIR: ${{ inputs.target-subdir }}
STORAGE_BRANCH: ${{ inputs.storage-branch }}
PRESERVE: ${{ inputs.preserve }}
GH_TOKEN: ${{ inputs.github-token }}
run: |
set -euo pipefail

if [ ! -d "$SOURCE_DIR" ]; then
echo "::error::source-dir '$SOURCE_DIR' does not exist" >&2
exit 1
fi

REPO_URL="https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"

rm -rf _site _storage
mkdir -p _site

# Pull the current full site from the storage branch (if it exists).
if git ls-remote --exit-code --heads "$REPO_URL" "$STORAGE_BRANCH" >/dev/null 2>&1; then
git clone --quiet --depth 1 --branch "$STORAGE_BRANCH" "$REPO_URL" _storage
( cd _storage && tar -cf - --exclude=.git . ) | ( cd _site && tar -xf - )
rm -rf _storage
fi

# Overlay the freshly built app into its slot.
if [ -z "$TARGET_SUBDIR" ] || [ "$TARGET_SUBDIR" = "." ]; then
# Site root (shell): replace root entries but keep sibling micro apps.
keep=".git .nojekyll $PRESERVE"
shopt -s dotglob nullglob
for entry in _site/*; do
name="$(basename "$entry")"
case " $keep " in
*" $name "*) continue ;;
esac
rm -rf "$entry"
done
shopt -u dotglob nullglob
cp -R "$SOURCE_DIR"/. _site/
else
rm -rf "_site/${TARGET_SUBDIR}"
mkdir -p "_site/${TARGET_SUBDIR}"
cp -R "$SOURCE_DIR"/. "_site/${TARGET_SUBDIR}/"
fi

# SPA fallback + disable Jekyll processing.
touch _site/.nojekyll
if [ -f _site/index.html ]; then
cp _site/index.html _site/404.html
fi

echo "Assembled site tree:"
find _site -maxdepth 2 -mindepth 1 | sort

- name: Upload Pages artifact 📦
uses: actions/upload-pages-artifact@v5
with:
path: _site

- name: Persist assembled site to storage branch 💾
shell: bash
env:
TARGET_SUBDIR: ${{ inputs.target-subdir }}
STORAGE_BRANCH: ${{ inputs.storage-branch }}
GH_TOKEN: ${{ inputs.github-token }}
run: |
set -euo pipefail
REPO_URL="https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
SLOT="${TARGET_SUBDIR:-/ (shell)}"

cd _site
rm -rf .git
git init -q
git add -A
git -c user.name="github-actions[bot]" \
-c user.email="41898282+github-actions[bot]@users.noreply.github.com" \
commit -q -m "deploy: update ${SLOT} (${GITHUB_SHA})" || {
echo "Nothing to persist."; exit 0;
}
git branch -M "$STORAGE_BRANCH"
git push -f "$REPO_URL" "$STORAGE_BRANCH"
63 changes: 63 additions & 0 deletions .github/workflows/deploy-portfolio.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Deploy portfolio

# The portfolio Module Federation remote is served (and exposes its
# remoteEntry.json) at:
# http://codestar.nl/nx-reference/portfolio/
# Only apps/portfolio (and shared libs) changes trigger this workflow, so the
# remote deploys independently of the shell.
on:
push:
branches: [main]
paths:
- 'apps/portfolio/**'
- 'libs/**'
- 'package.json'
- 'package-lock.json'
- 'nx.json'
- 'tsconfig.base.json'
- '.github/workflows/deploy-portfolio.yml'
- '.github/actions/deploy-subdir/**'
workflow_dispatch:

permissions:
contents: write
pages: write
id-token: write

# Serialize with the other Pages deploys so storage-branch writes never race.
concurrency:
group: pages
cancel-in-progress: false

jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Checkout 🛎️
uses: actions/checkout@v7

- name: Use Node.js 24 🟢
uses: actions/setup-node@v6
with:
node-version: '24'
cache: 'npm'

- name: Install dependencies 🔧
run: npm ci

- name: Build portfolio remote 🏗️
run: npx nx build portfolio --configuration=production

- name: Assemble /portfolio 🧩
uses: ./.github/actions/deploy-subdir
with:
source-dir: dist/apps/portfolio/browser
target-subdir: portfolio
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Deploy to GitHub Pages 🚀
id: deployment
uses: actions/deploy-pages@v5
71 changes: 71 additions & 0 deletions .github/workflows/deploy-shell.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Deploy shell

# The shell (Module Federation host) is served at the site root:
# http://codestar.nl/nx-reference/
# Only apps/demo (and shared libs) changes trigger this workflow — a portfolio
# remote change never rebuilds the shell, demonstrating module-federation
# loose coupling.
on:
push:
branches: [main]
paths:
- 'apps/demo/src/**'
- 'apps/demo/public/**'
- 'apps/demo/federation.config.js'
- 'apps/demo/federation.manifest.prod.json'
- 'apps/demo/project.json'
- 'apps/demo/tsconfig*.json'
- 'libs/**'
- 'package.json'
- 'package-lock.json'
- 'nx.json'
- 'tsconfig.base.json'
- '.github/workflows/deploy-shell.yml'
- '.github/actions/deploy-subdir/**'
workflow_dispatch:

permissions:
contents: write
pages: write
id-token: write

# Serialize with the other Pages deploys so storage-branch writes never race.
concurrency:
group: pages
cancel-in-progress: false

jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Checkout 🛎️
uses: actions/checkout@v7

- name: Use Node.js 24 🟢
uses: actions/setup-node@v6
with:
node-version: '24'
cache: 'npm'

- name: Install dependencies 🔧
run: npm ci

- name: Build shell 🏗️
run: npx nx build demo --configuration=production

- name: Apply production federation manifest 🔗
run: cp apps/demo/federation.manifest.prod.json dist/apps/demo/browser/federation.manifest.json

- name: Assemble site root 🧩
uses: ./.github/actions/deploy-subdir
with:
source-dir: dist/apps/demo/browser
target-subdir: ''
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Deploy to GitHub Pages 🚀
id: deployment
uses: actions/deploy-pages@v5
65 changes: 65 additions & 0 deletions .github/workflows/deploy-storybook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Deploy storybook

# The aggregated Storybook catalog is served at:
# http://codestar.nl/nx-reference/storybook/
# Triggered by Storybook config, story files, or shared library changes.
on:
push:
branches: [main]
paths:
- 'apps/demo/.storybook/**'
- 'libs/**'
- '**/*.stories.ts'
- '**/*.stories.tsx'
- '**/*.mdx'
- 'tsconfig.doc.json'
- 'package.json'
- 'package-lock.json'
- '.github/workflows/deploy-storybook.yml'
- '.github/actions/deploy-subdir/**'
workflow_dispatch:

permissions:
contents: write
pages: write
id-token: write

# Serialize with the other Pages deploys so storage-branch writes never race.
concurrency:
group: pages
cancel-in-progress: false

jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Checkout 🛎️
uses: actions/checkout@v7

- name: Use Node.js 24 🟢
uses: actions/setup-node@v6
with:
node-version: '24'
cache: 'npm'

- name: Install dependencies 🔧
run: npm ci

- name: Build Storybook 📚
run: |
npm run docs:json
npx nx run demo:build-storybook

- name: Assemble /storybook 🧩
uses: ./.github/actions/deploy-subdir
with:
source-dir: dist/storybook/demo
target-subdir: storybook
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Deploy to GitHub Pages 🚀
id: deployment
uses: actions/deploy-pages@v5
12 changes: 6 additions & 6 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0

- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
Expand All @@ -37,11 +37,11 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0

- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
Expand All @@ -58,11 +58,11 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0

- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
Expand Down
Loading