Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fa034ae
fix(docs-site): mobile search improvements and dropdown persistence (…
aaronlee777 Jun 12, 2026
08904b1
docs: refresh "What is the GEP React SDK?" landing page (#2116)
larchai Jun 12, 2026
621589b
docs(SDK-759): record docs-site infrastructure decisions (#2112)
jeffredodd Jun 12, 2026
94ef7e2
docs: reframe "Deciding to build with the SDK" page (#2118)
larchai Jun 12, 2026
f46298c
feat(Employee): surface PayrollOption on EmployeeManagement barrel (#…
serikjensen Jun 12, 2026
1779f3b
feat(TimeOff)!: expose data-connected PolicySettings and TimeOffPolic…
serikjensen Jun 12, 2026
c471540
feat(Payroll): export DismissalPayPeriodSelection block (#2115)
serikjensen Jun 12, 2026
c18162b
build(deps-dev): bump @microsoft/api-extractor from 7.58.8 to 7.58.9 …
dependabot[bot] Jun 15, 2026
35d2a42
build(deps): bump react-hook-form from 7.78.0 to 7.79.0 (#2125)
dependabot[bot] Jun 15, 2026
1919b30
build(deps): bump dompurify from 3.4.9 to 3.4.10 (#2124)
dependabot[bot] Jun 15, 2026
2042b38
build(deps-dev): bump @storybook/react-vite from 10.4.3 to 10.4.4 (#2…
dependabot[bot] Jun 15, 2026
fc52779
docs: rewrite Component Types page with hooks and updated terminology…
larchai Jun 15, 2026
059e06b
feat!: remove deprecated namespace exports (Company, Employee, Contra…
mariechatfield Jun 15, 2026
98938ec
build(deps): bump esbuild from 0.25.12 to removed in /docs-site in th…
dependabot[bot] Jun 15, 2026
cc2d46e
docs: tsdoc src/components/Employee in full (#2121)
mariechatfield Jun 15, 2026
e260fd0
docs: add versioned documentation support (SDK-766) (#2076)
jeffredodd Jun 15, 2026
0033b85
build(deps): bump launch-editor from 2.13.2 to 2.14.1 in /docs-site i…
dependabot[bot] Jun 15, 2026
4ef9b2c
build(deps-dev): bump form-data from 4.0.5 to 4.0.6 in the npm_and_ya…
dependabot[bot] Jun 15, 2026
909429c
ci: launch demo-app upgrade agent on SDK publish (#2129)
serikjensen Jun 15, 2026
8d46739
docs: remove Build Pathways - SDK, Flows & API page (#2128)
larchai Jun 15, 2026
4a28854
docs: remove Hooks experimental label and fix sidebar typo (#2130)
larchai Jun 15, 2026
01f6065
chore(sdk-app): include unprocessed payrolls in entity catalog (#2133)
aaronlee777 Jun 15, 2026
4f9df2d
docs: hide Next from version dropdown and remove version banner (#2134)
jeffredodd Jun 15, 2026
cb167c7
feat: render payroll reimbursements in a DataView with empty-state CT…
aaronlee777 Jun 15, 2026
6481396
Merge origin/main into al/docs/content-restructure
jeffredodd Jun 15, 2026
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
2 changes: 1 addition & 1 deletion .claude/commands/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Do not make any file changes or git operations in dry-run mode.
git push -u origin chore/release-<version>
gh pr create --title "chore: release <version>"
```
6. Once the PR is merged, publishing happens automatically — the [Publish to NPM](https://github.com/Gusto/embedded-react-sdk/actions/workflows/publish.yaml) workflow triggers when the `chore: release` commit lands on `main` and CI passes. No manual action needed unless something goes wrong.
6. Once the PR is merged, publishing happens automatically — the [Publish to NPM](https://github.com/Gusto/embedded-react-sdk/actions/workflows/publish.yaml) workflow triggers when the `chore: release` commit lands on `main` and CI passes. The [Sync Docs Source](https://github.com/Gusto/embedded-react-sdk/actions/workflows/publish-docs.yaml) workflow then propagates the docs to `Gusto/embedded-sdk-docs` and creates or refreshes the versioned snapshot for the released minor automatically. No manual action needed unless something goes wrong.

## Changelog curation (step 4)

Expand Down
228 changes: 179 additions & 49 deletions .github/workflows/publish-docs.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,42 @@
name: Sync Docs Source

# Fires after a successful NPM publish on main. Runs TypeDoc to generate
# docs/api/ markdown, then pushes the Docusaurus source
# (docs/ + docs-site/ + .nvmrc, including the generated docs/api/ files)
# to the main branch of Gusto/embedded-sdk-docs. That repo's Buildkite
# pipeline runs the Docusaurus build and publishes the result to its
# gh-pages branch.
# Builds docs source on this repo and pushes it to Gusto/embedded-sdk-docs.
# The downstream repo's Buildkite pipeline then runs the Docusaurus build
# and publishes the result to its gh-pages branch.
#
# Versioning lives entirely in the downstream repo, not here. This repo
# only ever carries the live (current) docs in `docs/`. Versioned snapshots
# (`docs-site/versioned_docs/`, `versions.json`, `versioned_sidebars/`)
# accumulate in `embedded-sdk-docs` over time as releases land.
#
# Three triggers, all funnel through the same job:
# 1. workflow_run after Publish to NPM — the release path. If the released
# minor isn't in downstream's versions.json, creates a new snapshot.
# If it is, refreshes the existing snapshot's content from the freshly
# synced docs (content-only; structural changes to versioned docs are
# explicit edits in the downstream repo).
# 2. push to main on docs/** or docs-site/** — the live-content path.
# Syncs the latest docs source down so /docs/ refreshes. Does not touch
# versioned snapshots.
# 3. workflow_dispatch — manual run. Always allowed; useful for recovery,
# end-to-end testing, or bootstrapping the first snapshot on a clean
# downstream (it will create the snapshot if missing for the current
# package.json minor).
#
# Snapshot mechanics:
# New minor / bootstrap: `npx docusaurus docs:version <X.Y>` runs inside the
# freshly-synced downstream working tree. Docusaurus copies the current
# docs/ into versioned_docs/version-<X.Y>/, captures the sidebar, and adds
# <X.Y> to versions.json. The conditional config in docs-site/docusaurus.config.ts
# then derives lastVersion from versions.json[0], so the unprefixed /docs/
# automatically points at the newest snapshot — no manual config change.
#
# Patch refresh: walks versioned_docs/version-<X.Y>/ and refreshes the
# content of each file from the matching path in the freshly-synced docs/.
# Files in the snapshot that have no live counterpart are left as-is.
# Files in live docs/ that aren't already in the snapshot are NOT added —
# adding a doc to a released minor is an intentional change made directly
# in the downstream repo.
#
# Auth: a GitHub App installed on Gusto/embedded-sdk-docs with
# Contents: write. Credentials live in this repo's `publish-docs`
Expand All @@ -18,17 +49,22 @@ name: Sync Docs Source
# DOCS_APP_ID and DOCS_APP_PRIVATE_KEY (paste the entire .pem
# contents for the private key).
# 3. Once a manual workflow_dispatch run is green, set repo variable
# DOCS_PUBLISH_ENABLED=true to turn on auto-publish on release.
# DOCS_PUBLISH_ENABLED=true to turn on the workflow_run + push paths.
#
# Manual `workflow_dispatch` triggers fire any time (the gate below only
# guards the auto-on-release path), so the pipeline can be exercised
# end-to-end before flipping the variable.
# guards the auto paths), so the pipeline can be exercised end-to-end
# before flipping the variable.

on:
workflow_run:
workflows: [Publish to NPM]
types: [completed]
branches: [main]
push:
branches: [main]
paths:
- 'docs/**'
- 'docs-site/**'
workflow_dispatch:

concurrency:
Expand All @@ -38,12 +74,15 @@ concurrency:
jobs:
sync:
# workflow_dispatch always allowed (for manual testing). workflow_run
# only fires when DOCS_PUBLISH_ENABLED=true, so the next NPM release
# won't auto-publish docs until that variable is explicitly set.
# and push only fire when DOCS_PUBLISH_ENABLED=true, so neither an NPM
# release nor a docs push will auto-publish until that variable is
# explicitly set.
if: |
github.event_name == 'workflow_dispatch' ||
(vars.DOCS_PUBLISH_ENABLED == 'true' &&
github.event.workflow_run.conclusion == 'success')
(vars.DOCS_PUBLISH_ENABLED == 'true' && (
github.event_name == 'push' ||
(github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')
))
runs-on:
group: gusto-ubuntu-default
environment: publish-docs
Expand All @@ -60,7 +99,13 @@ jobs:

- name: Read SDK version
id: version
run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
run: |
VERSION=$(node -p "require('./package.json').version")
MINOR=$(echo "$VERSION" | cut -d. -f1,2)
{
echo "version=${VERSION}"
echo "minor=${MINOR}"
} >> "$GITHUB_OUTPUT"

- name: Install SDK dependencies for TypeDoc
run: npm ci
Expand All @@ -77,72 +122,157 @@ jobs:
owner: Gusto
repositories: embedded-sdk-docs

# Push docs source (markdown + Docusaurus config + Node pin) to
# embedded-sdk-docs/main. Its Buildkite pipeline then builds and
# publishes the result to gh-pages.
#
# docs/api/ contains a mix of tracked and generated files:
# docs/api/index.md — hand-authored, tracked in this repo
# docs/api/reference.md — generated by TypeDoc (step above)
# docs/api/{domain}/... — generated by TypeDoc (step above)
# All are copied and force-staged so the docs repo always has the
# full generated output regardless of its own .gitignore rules.
#
# Safety model: this workflow only touches paths it explicitly
# manages (docs/, docs-site/, .nvmrc). Everything else in the
# docs repo (.buildkite/, README.md, CODEOWNERS, CNAME, .github/,
# …) is left untouched, ever. A defense-in-depth check at the
# end fails the push if any staged change escapes the allowlist
# — so if someone later widens the cp/rm logic by accident, the
# push fails closed instead of silently wiping unrelated files.
# Sync live source to downstream, then create or refresh the versioned
# snapshot if appropriate. Versioning is owned by the downstream repo —
# this is the only place that knows about versioned_docs/ etc.
#
# `concurrency: publish-docs` above prevents overlapping pushes,
# so a non-force push is safe.
- name: Push docs source to embedded-sdk-docs
# Sequencing:
# 1. Clone downstream (which may already have versioned_docs/, etc.)
# 2. Wipe the source-owned paths in downstream (docs/, .nvmrc, and
# everything in docs-site/ EXCEPT the versioned files)
# 3. Copy fresh source into downstream
# 4. Run versioning logic (create new snapshot OR refresh existing
# snapshot content), but only when the trigger calls for it
# 5. Defense-in-depth: refuse to push anything outside the managed
# allowlist (docs/, docs-site/, .nvmrc)
# 6. Commit + push
- name: Sync source and update versioned snapshot in embedded-sdk-docs
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
SDK_VERSION: ${{ steps.version.outputs.version }}
MINOR: ${{ steps.version.outputs.minor }}
TRIGGER: ${{ github.event_name }}
run: |
set -euo pipefail

git clone --depth 50 \
"https://x-access-token:$GH_TOKEN@github.com/Gusto/embedded-sdk-docs.git" \
docs-repo
cd docs-repo
git config user.name "gusto-embedded-docs[bot]"
git config user.email "gusto-embedded-docs[bot]@users.noreply.github.com"

# Remove only the paths this workflow owns. Anything else in
# the docs repo (.buildkite/, README.md, etc.) stays put.
# --ignore-unmatch so first-run (no prior docs/ on the repo)
# doesn't fail.
git rm -rf --quiet --ignore-unmatch docs docs-site .nvmrc
# ---- Step 2: wipe source-owned paths, preserve versioned files ----
# docs/ and .nvmrc are entirely source-owned.
git rm -rf --quiet --ignore-unmatch docs .nvmrc

# docs-site/ is mostly source-owned, but versioned_docs/,
# versioned_sidebars/, versions.json belong to downstream.
# Move them aside so the wipe doesn't take them out.
mkdir -p /tmp/preserved
for v in versioned_docs versioned_sidebars versions.json; do
if [ -e "docs-site/$v" ]; then
mv "docs-site/$v" "/tmp/preserved/$v"
fi
done
git rm -rf --quiet --ignore-unmatch docs-site

# Copy fresh source in.
# ---- Step 3: copy fresh source in ----
cp -R ../docs .
cp -R ../docs-site .
cp ../.nvmrc .

# Strip anything that shouldn't ship with source.
rm -rf docs-site/node_modules docs-site/build

# Stage only the paths we manage. NOT `git add -A` — that
# could pick up unrelated tree changes if anything went sideways.
# Restore the versioned files (or initialize empty placeholders if
# downstream was bare — the snapshot step below populates them).
for v in versioned_docs versioned_sidebars versions.json; do
if [ -e "/tmp/preserved/$v" ]; then
mv "/tmp/preserved/$v" "docs-site/$v"
fi
done

# ---- Step 4: snapshot creation or refresh ----
# Snapshot ACTION is determined by trigger + downstream state:
# workflow_run, minor missing -> create (new minor)
# workflow_run, minor present -> refresh (patch)
# workflow_dispatch, missing -> create (bootstrap / recover)
# workflow_dispatch, present -> none
# push -> none
MINOR_IN_VERSIONS=false
if [ -f docs-site/versions.json ] \
&& jq -e --arg key "${MINOR}" 'index($key) != null' docs-site/versions.json > /dev/null 2>&1; then
MINOR_IN_VERSIONS=true
fi

SNAPSHOT_ACTION=none
if [ "$TRIGGER" = "workflow_run" ] || [ "$TRIGGER" = "workflow_dispatch" ]; then
if [ "$MINOR_IN_VERSIONS" = "false" ]; then
SNAPSHOT_ACTION=create
elif [ "$TRIGGER" = "workflow_run" ]; then
SNAPSHOT_ACTION=refresh
fi
fi
echo "Snapshot action for SDK ${SDK_VERSION} (minor ${MINOR}, trigger ${TRIGGER}): ${SNAPSHOT_ACTION}"

if [ "$SNAPSHOT_ACTION" = "create" ]; then
# docusaurus docs:version copies docs/ -> versioned_docs/version-<minor>/,
# captures the sidebar, prepends <minor> to versions.json.
# The conditional config picks up versions.json[0] as lastVersion automatically.
(cd docs-site && npm ci && npx docusaurus docs:version "${MINOR}")
echo "Created snapshot version-${MINOR} in downstream."
elif [ "$SNAPSHOT_ACTION" = "refresh" ]; then
VERSIONED_DIR="docs-site/versioned_docs/version-${MINOR}"
if [ ! -d "$VERSIONED_DIR" ]; then
echo "::error::${MINOR} is in versions.json but ${VERSIONED_DIR}/ is missing in downstream."
exit 1
fi
updated=0
orphan=0
while IFS= read -r snap_file; do
rel="${snap_file#${VERSIONED_DIR}/}"
live="docs/${rel}"
if [ -f "$live" ]; then
cp "$live" "$snap_file"
updated=$((updated + 1))
else
orphan=$((orphan + 1))
fi
done < <(find "$VERSIONED_DIR" -type f)
echo "Refreshed ${updated} file(s) in version-${MINOR}; ${orphan} orphan(s) left as-is."
fi

# ---- Step 5: stage and validate ----
# Stage only the paths we manage. NOT `git add -A` — that could
# pick up unrelated tree changes if anything went sideways.
# Force-add docs/api/ so the TypeDoc-generated files are staged
# even if the docs repo's .gitignore excludes them.
git add docs docs-site .nvmrc
git add -f docs/api

# Defense in depth: refuse to push if any staged change
# escapes the managed allowlist. No-op when the workflow is
# correct; catches future drift.
# Defense in depth: refuse to push if any staged change escapes
# the managed allowlist. No-op when the workflow is correct;
# catches future drift.
unexpected=$(git diff --cached --name-only | grep -vE '^(docs/|docs-site/|\.nvmrc$)' || true)
if [[ -n "$unexpected" ]]; then
echo "ERROR: refusing to push — staged changes outside managed paths:" >&2
echo "$unexpected" >&2
exit 1
fi

# ---- Step 6: commit and push ----
# Commit message records the trigger + snapshot action so the
# downstream history is traceable to whichever cause prompted it.
SHORT_SHA=$(git -C "${GITHUB_WORKSPACE}" rev-parse --short HEAD)
case "${TRIGGER}" in
workflow_run)
MSG="docs: sync source for SDK ${SDK_VERSION}"
;;
push)
MSG="docs: sync docs source from ${SHORT_SHA} (SDK ${SDK_VERSION})"
;;
*)
MSG="docs: sync source from ${SHORT_SHA} (SDK ${SDK_VERSION}, ${TRIGGER})"
;;
esac
if [ "$SNAPSHOT_ACTION" = "create" ]; then
MSG="${MSG} — created version-${MINOR} snapshot"
elif [ "$SNAPSHOT_ACTION" = "refresh" ]; then
MSG="${MSG} — refreshed version-${MINOR} snapshot"
fi

# Always commit (even with no file changes) so every sync run
# leaves a release-marker in the docs repo's history, matching
# 1:1 with the NPM releases that triggered it.
git commit -q --allow-empty -m "docs: sync source for SDK $SDK_VERSION"
# leaves a marker in the docs repo's history.
git commit -q --allow-empty -m "${MSG}"
git push origin main
29 changes: 29 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,32 @@ jobs:
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Read SDK version
id: version
run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"

# Launch a Cursor cloud agent in the demo repo to integrate the version
# we just published. The agent runs the demo repo's update-embedded-react-sdk
# skill end to end (upgrade and open a PR; the PR notifies codeowners via
# GitHub). jq builds the JSON body so the prompt's backticks are encoded safely.
- name: Launch demo-app upgrade agent
env:
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
SDK_VERSION: ${{ steps.version.outputs.version }}
run: |
PROMPT="Use the \`update-embedded-react-sdk\` skill to upgrade @gusto/embedded-react-sdk to ${SDK_VERSION} (just published to npm). The target version is ${SDK_VERSION}. Run the skill end to end, including opening the PR."
jq -n --arg prompt "$PROMPT" '{
prompt: { text: $prompt },
repos: [
{
url: "https://github.com/Gusto/embedded-react-sdk-demo-app",
startingRef: "main"
}
],
autoCreatePR: true,
skipReviewerRequest: true
}' | curl --fail-with-body -sS https://api.cursor.com/v1/agents \
-H "Authorization: Bearer $CURSOR_API_KEY" \
-H "Content-Type: application/json" \
-d @-
Loading
Loading