Skip to content
Closed
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
31 changes: 30 additions & 1 deletion .github/workflows/auto-extract.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,61 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check extraction automation availability
id: config
env:
APP_ID: ${{ secrets.APP_ID }}
APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
run: |
if [ "${{ github.repository }}" != "emdash-cms/emdash" ]; then
Comment on lines +23 to +27

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] The config step interpolates ${{ github.repository }} directly into the run: script. github.repository is GitHub-controlled (owner/name), so this isn't a script-injection vector, but the same PR's codeql.yml change passes the value through env: REPOSITORY: and references $REPOSITORY (lines 79/82) — the recommended hardening pattern. For consistency within this PR, do the same here, and in auto-format.yml:25 and release.yml:40, which have the identical construct.

Suggested change
env:
APP_ID: ${{ secrets.APP_ID }}
APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
run: |
if [ "${{ github.repository }}" != "emdash-cms/emdash" ]; then
env:
APP_ID: ${{ secrets.APP_ID }}
APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
REPOSITORY: ${{ github.repository }}
run: |
if [ "$REPOSITORY" != "emdash-cms/emdash" ]; then

echo "enabled=false" >> "$GITHUB_OUTPUT"
exit 0
fi

if [ -z "$APP_ID" ] || [ -z "$APP_PRIVATE_KEY" ]; then
echo "enabled=false" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "enabled=true" >> "$GITHUB_OUTPUT"

- name: Skip extraction automation outside canonical repo
if: steps.config.outputs.enabled != 'true'
run: echo "Locale auto-extract is only enabled on emdash-cms/emdash."

- name: Generate token
if: steps.config.outputs.enabled == 'true'
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}

- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
if: steps.config.outputs.enabled == 'true'
with:
token: ${{ steps.app-token.outputs.token }}
# Intentional: the "Commit and push" step below pushes the
# extracted catalogs back to main using this credential.
persist-credentials: true

- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
if: steps.config.outputs.enabled == 'true'

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
if: steps.config.outputs.enabled == 'true'
with:
node-version: 22
cache: pnpm

- run: pnpm install --frozen-lockfile
if: steps.config.outputs.enabled == 'true'

- run: pnpm locale:extract
if: steps.config.outputs.enabled == 'true'

- name: Check for changes
if: steps.config.outputs.enabled == 'true'
id: diff
run: |
git add -A
Expand All @@ -60,7 +89,7 @@ jobs:
fi

- name: Commit and push
if: steps.diff.outputs.changed == 'true'
if: steps.config.outputs.enabled == 'true' && steps.diff.outputs.changed == 'true'
run: |
git config user.name "emdashbot[bot]"
git config user.email "emdashbot[bot]@users.noreply.github.com"
Expand Down
37 changes: 32 additions & 5 deletions .github/workflows/auto-format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,38 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check formatter automation availability
id: config
env:
APP_ID: ${{ secrets.APP_ID }}
APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
run: |
if [ "${{ github.repository }}" != "emdash-cms/emdash" ]; then
echo "enabled=false" >> "$GITHUB_OUTPUT"
exit 0
fi

if [ -z "$APP_ID" ] || [ -z "$APP_PRIVATE_KEY" ]; then
echo "enabled=false" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "enabled=true" >> "$GITHUB_OUTPUT"

- name: Skip formatter automation outside canonical repo
if: steps.config.outputs.enabled != 'true'
run: echo "Auto-format pushback is only enabled on emdash-cms/emdash."

- name: Generate token
if: steps.config.outputs.enabled == 'true'
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}

- name: Get PR details
if: steps.config.outputs.enabled == 'true'
id: pr
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
Expand All @@ -40,7 +64,7 @@ jobs:
# --- Same-repo PRs: checkout and push directly ---

- name: Checkout (same-repo)
if: steps.pr.outputs.is_fork == 'false'
if: steps.config.outputs.enabled == 'true' && steps.pr.outputs.is_fork == 'false'
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ steps.pr.outputs.ref }}
Expand All @@ -52,22 +76,25 @@ jobs:
# --- Fork PRs: checkout the fork at the pinned SHA ---

- name: Checkout (fork)
if: steps.pr.outputs.is_fork == 'true'
if: steps.config.outputs.enabled == 'true' && steps.pr.outputs.is_fork == 'true'
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
repository: ${{ steps.pr.outputs.full_name }}
ref: ${{ steps.pr.outputs.sha }}
persist-credentials: false

- name: Setup Node
if: steps.config.outputs.enabled == 'true'
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22

- name: Run formatter
if: steps.config.outputs.enabled == 'true'
run: npx oxfmt --ignore-path .gitignore

- name: Check for changes
if: steps.config.outputs.enabled == 'true'
id: diff
run: |
git add -A
Expand All @@ -80,7 +107,7 @@ jobs:
# --- Same-repo: push directly ---

- name: Commit and push (same-repo)
if: steps.pr.outputs.is_fork == 'false' && steps.diff.outputs.changed == 'true'
if: steps.config.outputs.enabled == 'true' && steps.pr.outputs.is_fork == 'false' && steps.diff.outputs.changed == 'true'
run: |
git config user.name "emdashbot[bot]"
git config user.email "emdashbot[bot]@users.noreply.github.com"
Expand All @@ -90,7 +117,7 @@ jobs:
# --- Fork: push via git with GIT_ASKPASS ---

- name: Commit and push (fork)
if: steps.pr.outputs.is_fork == 'true' && steps.diff.outputs.changed == 'true'
if: steps.config.outputs.enabled == 'true' && steps.pr.outputs.is_fork == 'true' && steps.diff.outputs.changed == 'true'
id: push-fork
run: |
git config user.name "emdashbot[bot]"
Expand All @@ -112,7 +139,7 @@ jobs:
APP_TOKEN: ${{ steps.app-token.outputs.token }}

- name: Comment on push failure
if: steps.push-fork.outputs.push_failed == 'true'
if: steps.config.outputs.enabled == 'true' && steps.push-fork.outputs.push_failed == 'true'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.app-token.outputs.token }}
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/cla.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ jobs:
CLAssistant:
runs-on: ubuntu-latest
steps:
- name: Skip CLA outside canonical repo
if: github.repository != 'emdash-cms/emdash'
run: echo "CLA enforcement is only enabled on emdash-cms/emdash."

- name: "CLA Assistant"
if: (github.event.issue.pull_request && (github.event.comment.body == 'recheck' || startsWith(github.event.comment.body, 'I have read the CLA Document and I hereby sign the CLA'))) || github.event_name == 'pull_request_target'
if: github.repository == 'emdash-cms/emdash' && ((github.event.issue.pull_request && (github.event.comment.body == 'recheck' || startsWith(github.event.comment.body, 'I have read the CLA Document and I hereby sign the CLA'))) || github.event_name == 'pull_request_target')
uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -32,7 +36,7 @@ jobs:

label:
needs: CLAssistant
if: always() && (github.event_name == 'pull_request_target' || github.event.issue.pull_request)
if: always() && github.repository == 'emdash-cms/emdash' && (github.event_name == 'pull_request_target' || github.event.issue.pull_request)
runs-on: ubuntu-latest
steps:
- name: Label CLA status
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,14 @@ jobs:
env:
EVENT_NAME: ${{ github.event_name }}
CHANGED: ${{ steps.changes.outputs.code }}
REPOSITORY: ${{ github.repository }}
run: |
# Fork sync PRs should not fail on upstream's existing alert backlog.
if [ "$EVENT_NAME" = "pull_request" ] && [ "$REPOSITORY" != "emdash-cms/emdash" ]; then
echo "analyze=false" >> "$GITHUB_OUTPUT"
exit 0
fi

if [ "$EVENT_NAME" != "pull_request" ] || [ "$CHANGED" = "true" ]; then
echo "analyze=true" >> "$GITHUB_OUTPUT"
else
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/preview-releases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,25 @@ jobs:
name: Publish Preview
runs-on: ubuntu-latest
steps:
- name: Skip preview publishing outside canonical repo
if: github.repository != 'emdash-cms/emdash'
run: echo "pkg.pr.new publishing is only enabled on emdash-cms/emdash."

- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
if: github.repository == 'emdash-cms/emdash'
with:
persist-credentials: false
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
if: github.repository == 'emdash-cms/emdash'
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
if: github.repository == 'emdash-cms/emdash'
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
if: github.repository == 'emdash-cms/emdash'
- run: pnpm build
if: github.repository == 'emdash-cms/emdash'
# Publish a preview for every public package via globs rather than a
# hardcoded list. This keeps preview installs self-consistent: when
# `emdash`'s preview references a sibling like @emdash-cms/registry-client
Expand All @@ -44,3 +53,4 @@ jobs:
# pkg.pr.new skips `private: true` packages automatically, so the test
# fixtures under packages/plugins/* are excluded without enumerating them.
- run: pnpm exec pkg-pr-new publish --pnpm './packages/*' './packages/plugins/*'
if: github.repository == 'emdash-cms/emdash'
39 changes: 34 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,38 @@ jobs:
id-token: write
pull-requests: write
steps:
- name: Check release automation availability
id: config
env:
APP_ID: ${{ secrets.APP_ID }}
APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
run: |
if [ "${{ github.repository }}" != "emdash-cms/emdash" ]; then
echo "enabled=false" >> "$GITHUB_OUTPUT"
exit 0
fi

if [ -z "$APP_ID" ] || [ -z "$APP_PRIVATE_KEY" ]; then
echo "enabled=false" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "enabled=true" >> "$GITHUB_OUTPUT"

- name: Skip release automation outside canonical repo
if: steps.config.outputs.enabled != 'true'
run: echo "Release automation is only enabled on emdash-cms/emdash."

- name: Generate token
if: steps.config.outputs.enabled == 'true'
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}

- name: Checkout
if: steps.config.outputs.enabled == 'true'
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
Expand All @@ -48,26 +72,31 @@ jobs:
persist-credentials: true

- name: Setup pnpm
if: steps.config.outputs.enabled == 'true'
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8

- name: Setup Node
if: steps.config.outputs.enabled == 'true'
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: pnpm
registry-url: https://registry.npmjs.org

- name: Install dependencies
if: steps.config.outputs.enabled == 'true'
run: pnpm install --frozen-lockfile

- name: Build packages
if: steps.config.outputs.enabled == 'true'
run: pnpm build

- name: Block 1.x releases (we are in 0.x)
if: steps.config.outputs.enabled == 'true'
run: node .github/scripts/check-no-major.mjs

- name: Create Release Pull Request or Publish
if: ${{ !inputs.publish-only }}
if: ${{ steps.config.outputs.enabled == 'true' && !inputs.publish-only }}
id: changesets
Comment on lines 98 to 100
uses: changesets/action@a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d # v1.9.0
with:
Expand All @@ -85,23 +114,23 @@ jobs:
# below neither runs changesets/action nor creates GitHub releases, so
# assets for that path must be backfilled manually.
- name: Attach plugin tarballs to releases
if: ${{ steps.changesets.outputs.published == 'true' }}
if: ${{ steps.config.outputs.enabled == 'true' && steps.changesets.outputs.published == 'true' }}
run: node .github/scripts/attach-plugin-tarballs.mjs
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.publishedPackages }}

- name: Publish (manual)
if: ${{ inputs.publish-only }}
if: ${{ steps.config.outputs.enabled == 'true' && inputs.publish-only }}
run: node .github/scripts/release.mjs publish
Comment on lines 124 to 126

sync-templates:
name: Sync Templates
needs: release
if: >-
needs.release.outputs.published == 'true' ||
inputs.publish-only
github.repository == 'emdash-cms/emdash' &&
(needs.release.outputs.published == 'true' || inputs.publish-only)
permissions:
Comment on lines 131 to 134
contents: read
uses: ./.github/workflows/sync-templates.yml
Expand Down
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22.22.2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] This adds a pinned Node 22.22.2. Nothing in the repo consumes .nvmrc — CI pins Node via floating node-version: 22 or node-version-file: package.json (against engines.node: ">=22"), and no workflow references .nvmrc. So on upstream the file is advisory-only and introduces a third source of truth for the Node version that diverges from the established convention. It reads as a fork-local convenience. If upstream doesn't want to maintain a pinned patch version, drop it from this PR; if it does, align it with the repo's node-version strategy rather than adding an unconsumed pin.

2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ For human-facing contributor info (setup, repo layout, PR policy, changesets, i1

## Workflow

**CRITICAL: If this repository is being worked from a fork, check upstream before doing substantive work.** Run `git fetch upstream --prune` and compare your branch or `origin/main` against `upstream/main` first. If the fork is substantially behind, sync or explicitly account for that drift before editing code.

Run `pnpm lint:json | jq '.diagnostics | length'` before starting and confirm it's clean -- if it's failing after your edits, your changes caused it.

During work:
Expand Down
Loading