Skip to content

Latest commit

History

325 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Tailor Platform Actions

Reusable GitHub Actions for Tailor Platform.

Versioning

Pin usage to a major tag (e.g. tailor-platform/actions/deploy@v2) or a full commit SHA — see each release's notes for the exact SHA. v2 targets the Tailor Platform SDK's tailor CLI. If you're still on the SDK's pre-rename tailor-sdk CLI, use @v1 instead; that line is maintained on the maintenance/v1 branch, not main.

Actions

Deploy an application to Tailor Platform. Handles token acquisition, code generation, and deployment.

The action targets the workspace by workspace-id only. Workspace creation/provisioning happens outside this action (e.g. via the Tailor Platform console or CLI). Pass the workspace ID from a GitHub Environment variable (vars.TAILOR_PLATFORM_WORKSPACE_ID).

Prerequisites: The caller is responsible for checkout, Node.js setup, package manager setup, and dependency installation. This keeps the action package-manager agnostic.

Usage

jobs:
deploy:
runs-on: ubuntu-latestenvironment: productionpermissions:
contents: readsteps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4with:
node-version-file: package.jsoncache: pnpm
- run: pnpm install --frozen-lockfile
- uses: tailor-platform/actions/deploy@v2with:
workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}

Inputs

NameRequiredDefaultDescription
workspace-idYesWorkspace ID (from a GitHub Environment variable, e.g. vars.TAILOR_PLATFORM_WORKSPACE_ID)
working-directoryNo.Working directory (for monorepo setups)
platform-client-idYesOAuth2 client ID for machine user
platform-client-secretYesOAuth2 client secret for machine user

Outputs

NameDescription
workspace-idWorkspace ID passed in
app-urlApplication URL (GraphQL endpoint) of the deployed workspace. Available to subsequent steps, e.g. for passing to a static website build slot.

Secrets and variables setup

# Machine user credentials (repository or environment secrets)
gh secret set TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID
gh secret set TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET
# Workspace ID (GitHub Environment variable — one per environment)
gh variable set TAILOR_PLATFORM_WORKSPACE_ID --env production

Scaffold with Tailor SDK CLI

The tailor setup command generates a workflow file using this action together with the install action, with package manager auto-detection.


Show planned changes by running dry-run against the target workspace. Merges the base branch and runs tailor deploy --dry-run, then comments the result on the PR.

The action targets the workspace by workspace-id only. When workspace-id is empty (workspace not yet provisioned), the action skips the dry-run and reports that the workspace is not provisioned yet — the job succeeds. This covers the chicken-and-egg situation of running plan on a PR before the first deploy.

Prerequisites: Same as deploy - checkout, Node.js setup, package manager setup, and dependency installation.

Usage

jobs:
plan:
runs-on: ubuntu-latestif: github.event_name == 'pull_request'environment: productionpermissions:
contents: readpull-requests: writesteps:
- uses: actions/checkout@v4with:
fetch-depth: 0
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4with:
node-version-file: package.jsoncache: pnpm
- run: pnpm install --frozen-lockfile
- uses: tailor-platform/actions/plan@v2with:
workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}label: productionplatform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}github-token: ${{ secrets.GITHUB_TOKEN }}

Inputs

NameRequiredDefaultDescription
workspace-idNoWorkspace ID to run dry-run against (from a GitHub Environment variable, e.g. vars.TAILOR_PLATFORM_WORKSPACE_ID). When empty, the dry-run is skipped and the action reports that the workspace is not provisioned yet.
labelNoHuman-readable label for the PR comment heading and marker (e.g. the workspace name). Falls back to workspace-id, then "workspace".
working-directoryNo.Working directory (for monorepo setups)
platform-client-idYesOAuth2 client ID for machine user
platform-client-secretYesOAuth2 client secret for machine user
github-tokenNoGitHub token for commenting on PR. When omitted, no PR comment is posted (step summary only).

Outputs

NameDescription
workspace-idWorkspace ID passed in (empty when not provisioned yet)
exit-codeExit code of the dry-run (empty when skipped)

Step summary

The action always writes the result to the job's step summary (status emoji, workspace identifier, and the full output in a <details> block). This is the primary signal when the action runs outside of a pull request (e.g. on a tag push for deploy approval).

PR Comment

When github-token is provided and the event is a pull request, the action posts (or updates) a comment with the dry-run output:

  • Success: Shows the planned changes
  • Failure: Shows the error output

When workspace-id is not set, no PR comment is posted — the step summary records the "not yet provisioned" state instead.

The comment is keyed per workspace via a <!-- tailor-plan: KEY --> marker (KEY is the label input if provided, otherwise workspace-id, otherwise "workspace"), so multiple environments can post separate comments on the same PR. The comment is automatically updated on subsequent runs.


Set up the Tailor Platform toolchain (Node.js and package manager). Does not install project dependencies — use the install action for that.


Run tailor generate and fail if it produces uncommitted changes. Catches generated files (seed data, enum constants, etc.) that were regenerated but not committed.

Inputs

NameRequiredDefaultDescription
package-managerYesPackage manager (pnpm, npm, yarn, or bun)
working-directoryNo.Working directory (for monorepo setups)
ignoreNoNewline-separated list of file paths to exclude from the check (e.g. .npmrc created by earlier steps)

Guard that a pushed tag is reachable from a target branch before allowing a deploy to proceed. Skips gracefully when the tag is outside the branch (not an error).


Detect drift between the generated GitHub Actions workflows and the current config/repo state. Drift findings emit ::warning:: annotations and write a step summary without failing the job by default. Set fail-on-drift to true to fail on unsuppressed findings. Execution and configuration errors always fail the job.

Inputs

NameRequiredDefaultDescription
package-managerYesPackage manager (pnpm, npm, yarn, or bun)
working-directoryNo.Working directory (for monorepo setups)
ignoreNoComma-separated drift rule keys to suppress (e.g. "default-branch,template-version"). Each warning includes its rule key
fail-on-driftNofalseFail the job when the check finds unsuppressed workflow drift

Validate seed data against the generated schema, detecting JSONL records that do not match their target type. Requires tailor generate to have run first.

Inputs

NameRequiredDefaultDescription
working-directoryNo.Working directory (for monorepo setups)

Deploy a built static website to Tailor Platform and output its public URL. Run this after the deploy action in the same job (authentication is reused).

Inputs

NameRequiredDefaultDescription
workspace-idYesWorkspace ID (from a GitHub Environment variable, e.g. vars.TAILOR_PLATFORM_WORKSPACE_ID)
nameYesStatic website name as defined in tailor.config.ts
dist-dirYesPath to the built static website files
working-directoryNo.Working directory (for monorepo setups)
package-managerNoPackage manager (pnpm, npm, yarn, or bun). Defaults to npx.

Outputs

NameDescription
site-urlPublic URL of the deployed static website

Send a deployment notification. Currently supports Slack via Bot token and channel ID.

Usage

steps:
# ... deploy steps ...
- if: always()uses: tailor-platform/actions/notify@v2with:
provider: slackstatus: ${{ job.status }}workspace-name: my-app-prodslack-channel-id: ${{ vars.SLACK_DEPLOY_CHANNEL_ID }}slack-token: ${{ secrets.SLACK_BOT_TOKEN }}

Inputs

NameRequiredDefaultDescription
providerYesNotification provider. Currently only slack is supported.
statusYesDeployment status. Accepts success, failure, or cancelled (any non-success value is reported as a failure). Pass ${{ job.status }}.
workspace-nameNoWorkspace name shown in the message
slack-channel-idNoSlack channel ID. When empty, the notification is silently skipped.
slack-tokenNoSlack Bot token with chat:write permission. When empty, the notification is silently skipped.

Deploy a per-PR preview workspace. On the first push to a PR the workspace is created; subsequent pushes reuse the existing workspace (identified by the workspace ID recorded in the PR comment by preview-comment). Run on pull_request events (not closed).

Prerequisites: Same as deploy — checkout, Node.js, package manager, and dependency installation.

Usage

jobs:
preview:
runs-on: ubuntu-latestif: github.event.action != 'closed' && !github.event.pull_request.draftpermissions:
contents: readpull-requests: writesteps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4with:
node-version-file: package.jsoncache: pnpm
- run: pnpm install --frozen-lockfile
- id: previewuses: tailor-platform/actions/preview-deploy@v2with:
workspace-name-prefix: my-appregion: us-westorganization-id: ${{ vars.TAILOR_PLATFORM_ORGANIZATION_ID }}platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: tailor-platform/actions/preview-comment@v2with:
workspace-id: ${{ steps.preview.outputs.workspace-id }}workspace-name: ${{ steps.preview.outputs.workspace-name }}status: ${{ job.status }}app-url: ${{ steps.preview.outputs.app-url }}github-token: ${{ secrets.GITHUB_TOKEN }}mention: "true"

Inputs

NameRequiredDefaultDescription
workspace-name-prefixYesPrefix for the workspace name. The full name is {prefix}-pr-{PR number} (max 57 chars).
regionYesWorkspace region for creation (e.g. us-west, asia-northeast). Only used on first run.
organization-idNoOrganization ID for workspace creation. Defaults to TAILOR_PLATFORM_ORGANIZATION_ID env var.
folder-idNoFolder ID for workspace creation
working-directoryNo.Working directory (for monorepo setups)
package-managerNoPackage manager (pnpm, npm, yarn, or bun). Defaults to npx.
platform-client-idYesOAuth2 client ID for machine user
platform-client-secretYesOAuth2 client secret for machine user
github-tokenYesGitHub token for reading PR comments to find an existing workspace ID

Outputs

NameDescription
workspace-idWorkspace ID of the preview deployment
workspace-nameFull workspace name (e.g. my-app-pr-42)
app-urlApplication URL (GraphQL endpoint) of the preview workspace

Post or update a PR comment with preview deployment status, workspace ID, app URL, and optional @mention. Typically called after preview-deploy. The comment is keyed by workspace name so multiple preview environments can coexist on one PR.

Inputs

NameRequiredDefaultDescription
workspace-idYesWorkspace ID of the preview deployment
workspace-nameYesWorkspace name (from preview-deploy output)
statusYesDeployment status: success, failure, or deleted
app-urlNoApplication URL to show in the comment
github-tokenYesGitHub token with pull-requests: write
mentionNoSet to "true" to @mention the commit author (falls back to PR author if commit is by a bot)

Check that all dependencies use allowed licenses, based on the Google licenseclassifier categories (reciprocal, notice, unencumbered). Fails the job when a dependency's license isn't in the allowed set.

Prerequisites: The caller is responsible for checkout, Node.js setup, pnpm setup, and dependency installation.

Usage

jobs:
check-licenses:
runs-on: ubuntu-latesttimeout-minutes: 10permissions:
contents: readsteps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4with:
node-version-file: package.jsoncache: pnpm
- run: pnpm install --frozen-lockfile
- uses: tailor-platform/actions/check-licenses@v2with:
license-groups: ${{ vars.LICENSE_GROUPS }}additional-licenses: ${{ vars.ALLOWED_LICENSES }}denied-licenses: ${{ vars.DENIED_LICENSES }}# examples/nextjs-app pulls in @img/sharp-libvips-* (LGPL-3.0-or-later)# transitively via next's built-in image optimization, used# unmodified as a prebuilt binary — the standard case LGPL's# dynamic-linking allowance covers.package-exceptions: | {"LGPL-3.0-or-later": [["nextjs-app", "next"]]}

Inputs

NameRequiredDefaultDescription
license-groupsNoreciprocal,notice,unencumberedWhich Google licenseclassifier categories to allow. Comma- or newline-separated. Including reciprocal (weak-copyleft licenses like MPL/EPL/CDDL) is a licensing-policy decision, not a fixed fact, so it's configurable rather than hardcoded — source it from a LICENSE_GROUPS GitHub Variable.
additional-licensesNoExtra individually-allowed SPDX license identifiers, beyond the selected license-groups. Comma- or newline-separated. Source this from an ALLOWED_LICENSES GitHub Variable (organization-level, Terraform-managed) so every consuming repo shares one allowlist.
denied-licensesNoSPDX license identifiers to remove from the allow set, even if they belong to a selected group. Comma- or newline-separated. Source this from a DENIED_LICENSES GitHub Variable, kept alongside LICENSE_GROUPS / ALLOWED_LICENSES even while empty, so denying a license later is a Variable update, not a workflow edit.
package-exceptionsNoApprove specific dependency routes to an otherwise-disallowed license, independent of the inputs above. A JSON object mapping a license string to an array of dependency chains — see Package exceptions below. Unlike the other inputs, this one is tied to one repo's specific dependency tree, so declare it directly in that repo's workflow instead of a shared GitHub Variable.
working-directoryNo.Working directory (for monorepo setups)

Package exceptions

Allowing a license outright (additional-licenses) silently blesses every future dependency under that license — approving one package's LGPL-licensed prebuilt binary shouldn't approve LGPL in general. package-exceptions instead approves a specific route to a license, expressed as a dependency chain:

{ "LGPL-3.0-or-later": [["nextjs-app", "next"]] }

Each chain is an ordered list of package names (the workspace project name first; * globs allowed elsewhere). A package can be reached multiple ways (e.g. two different workspace projects both depending on it) — pnpm why <package> --recursive --json finds every such route, and the package is excused only if every route matches some declared chain; approving one route never excuses a different, unreviewed route to the same package. Within a route, other dependencies may appear between the chain's listed names, and the chain doesn't need to end at the violating package itself: ["nextjs-app", "next"] approves this license for anything reached via nextjs-app's use of next, not one exact package — useful since a native dependency like sharp/libvips ships a different package name per OS/arch (@img/sharp-libvips-linux-x64, @img/sharp-libvips-darwin-arm64, ...); one chain covers all of them without enumerating every platform variant.

Managing the allowlist

license-groups, additional-licenses, and denied-licenses are policy decisions shared across repos, not implementation details — they live in GitHub Variables rather than in this action's code, so they can change without a workflow edit or a new action release. Managed via Terraform as single organization-level variables so the values aren't duplicated per repo:

resource"github_actions_organization_variable""license_groups" {
variable_name="LICENSE_GROUPS"visibility="selected"selected_repository_ids=[
data.github_repository.erp_kit.repo_id,
data.github_repository.sdk.repo_id,
data.github_repository.app_shell.repo_id,
]
value="reciprocal,notice,unencumbered"
}
resource"github_actions_organization_variable""allowed_licenses" {
variable_name="ALLOWED_LICENSES"visibility="selected"selected_repository_ids=[
data.github_repository.erp_kit.repo_id,
data.github_repository.sdk.repo_id,
data.github_repository.app_shell.repo_id,
]
value="BlueOak-1.0.0,WTFPL,Unknown,OFL-1.1"
}
# Empty for now — kept so denying a specific license later is a value# update here, not a new input wired through every consuming workflow.resource"github_actions_organization_variable""denied_licenses" {
variable_name="DENIED_LICENSES"visibility="selected"selected_repository_ids=[
data.github_repository.erp_kit.repo_id,
data.github_repository.sdk.repo_id,
data.github_repository.app_shell.repo_id,
]
value=""
}

package-exceptions isn't managed this way — see the Usage example above.


Regression-only gate against pnpm-lock.yaml changes: fails only when a pull request or push introduces a security advisory that wasn't already present in the lockfile at the base commit. Pre-existing advisories elsewhere in the lockfile don't block unrelated changes — pair this with a scheduled pnpm audit --fix workflow (run independent of any PR) to clear those over time.

Prerequisites: The caller is responsible for checkout (with fetch-depth: 0 — the base commit's lockfile must be reachable) and pnpm setup. pnpm audit resolves advisories from the lockfile alone, so no dependency install is needed. A resolved base commit that isn't reachable in the checkout (most commonly a missing fetch-depth: 0) fails the job outright rather than silently skipping — silently no-op'ing would defeat the gate for exactly the callers who most need it.

Usage

jobs:
lockfile-audit:
runs-on: ubuntu-latesttimeout-minutes: 5permissions:
contents: readsteps:
- uses: actions/checkout@v4with:
fetch-depth: 0
- uses: pnpm/action-setup@v4with:
run_install: false
- uses: tailor-platform/actions/lockfile-audit@v2

Inputs

NameRequiredDefaultDescription
audit-levelNomoderateMinimum severity to report, passed through to pnpm audit --audit-level. One of low, moderate, high, critical.
base-shaNoCommit to diff the lockfile against, overriding the default auto-detection (the pull request's base commit, or the pushed ref's previous tip). Mainly for workflow_dispatch runs, where neither of those is available from the event payload.
working-directoryNo.Working directory containing pnpm-lock.yaml (for monorepo setups)

Runs pnpm audit --fix against pnpm-lock.yaml (update mode, falling back to override mode when update alone can't clear an advisory), verifying the result still installs before keeping it. Meant for a standalone scheduled/dispatched workflow that clears pre-existing advisories independent of any specific PR — pair with lockfile-audit's regression-only gate, which only blocks new advisories.

This action does not commit or open a pull request; it only fixes the lockfile in the working tree and reports what changed. Pair it with a commit/PR step of your own so you control where a changeset gets inserted (if runtime-deps-changed calls for one).

Prerequisites: The caller is responsible for checkout and pnpm setup.

Usage

jobs:
lockfile-audit-fix:
runs-on: ubuntu-latesttimeout-minutes: 15permissions:
contents: readsteps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4with:
run_install: false
- uses: tailor-platform/actions/lockfile-audit-fix@v2id: fix# commit pnpm-lock.yaml / pnpm-workspace.yaml / package.json and open# a PR yourself when steps.fix.outputs.changed == 'true'

Inputs

NameRequiredDefaultDescription
audit-levelNomoderateMinimum severity to report, passed through to pnpm audit --audit-level. One of low, moderate, high, critical.
working-directoryNo.Working directory containing pnpm-lock.yaml (for monorepo setups)

Outputs

NameDescription
changed'true' if pnpm-lock.yaml, pnpm-workspace.yaml, and/or package.json changed — pnpm writes an override it can't express as a plain version bump to pnpm-workspace.yaml (creating it if it doesn't exist) or to package.json's pnpm.overrides, depending on pnpm version and whether the repo already has a pnpm-workspace.yaml
runtime-deps-changed'true' if any non-private package's runtime (non-dev) dependencies changed, per pnpm-lock.yaml — devDependencies-only and pnpm-workspace.yaml/package.json-overrides-only changes don't affect consumers
changed-namesNewline-separated names of packages whose runtime dependencies changed
summaryMarkdown summary of fixed and remaining advisories, for use as a PR body

Commits a known, bounded list of file paths via GitHub's Git Data API (blob -> tree -> commit -> ref) and idempotently creates or updates a pull request for them — without running git commit locally or depending on a third-party action. Pair with lockfile-audit-fix (or any step that leaves modified files in the working tree) to open a PR for the result.

Commits created this way are automatically shown as "Verified" on GitHub when using the default GITHUB_TOKEN or a GitHub App installation token, satisfying a required_signatures branch protection rule with no GPG key material. A classic/fine-grained PAT still works but produces unsigned commits.

This is deliberately not a general-purpose alternative to peter-evans/create-pull-request: paths must be a known, caller-supplied list of files that already exist in the checkout (e.g. files a prior step just modified), not an arbitrary repo-wide diff — this action never inspects the working tree's git status, doesn't support deletions, and reads each listed path directly.

Each run re-parents the new commit on the base branch's current head and force-moves the target branch to it, so the branch always holds a single commit rebased on the latest base. A consequence: any commit a human pushed to that branch directly is discarded on the next run — same behavior as peter-evans/create-pull-request's default mode.

A pull request created with the default GITHUB_TOKEN does not trigger pull_request-triggered workflows (GitHub suppresses recursive workflow runs from its own token) — the created PR gets no CI. Use a GitHub App installation token instead if the PR needs to run your normal CI.

Prerequisites: The caller is responsible for checkout and setting up Node.js (e.g. actions/setup-node) — unlike lockfile-audit/lockfile-audit-fix, this action doesn't otherwise depend on pnpm. The token needs contents: write and pull-requests: write permissions, and the repository's Settings → Actions → General → Workflow permissions → "Allow GitHub Actions to create and approve pull requests" must be enabled — GitHub rejects PR creation from GITHUB_TOKEN with a 403 otherwise (confirmed against a real repository: the commit and branch are created successfully, and PR creation is the step that fails).

Usage

jobs:
lockfile-audit-fix:
runs-on: ubuntu-latesttimeout-minutes: 15permissions:
contents: writepull-requests: writesteps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4with:
run_install: false
- uses: tailor-platform/actions/lockfile-audit-fix@v2id: fix
- uses: tailor-platform/actions/create-signed-pr@v2if: steps.fix.outputs.changed == 'true'with:
token: ${{ secrets.GITHUB_TOKEN }}paths: | pnpm-lock.yaml pnpm-workspace.yamlbranch: chore/lockfile-audit-fixcommit-message: "fix(deps): automated lockfile security fix"title: "fix(deps): automated lockfile security fix"body: ${{ steps.fix.outputs.summary }}labels: | security

Inputs

NameRequiredDefaultDescription
tokenYesGitHub token with contents: write and pull-requests: write permissions. GITHUB_TOKEN or a GitHub App installation token for Verified (signed) commits; a PAT works but produces unsigned commits.
pathsYesNewline-separated list of repo-root-relative file paths to commit. Each must exist in the local checkout.
branchYesBranch to create or force-update with the new commit.
baseNo(repository default branch)Base branch to commit onto and open the pull request against.
commit-messageYesCommit message for the new commit.
titleYesPull request title.
bodyNo""Pull request body.
labelsNo""Newline-separated list of labels to add to the pull request. Each label must already exist in the repository; a failure here is logged as a warning rather than failing the action, since the commit and PR are already created by this point.
api-base-urlNo""Override the GitHub REST API base URL (e.g. for GHES, or to point at a test double). Defaults to $GITHUB_API_URL, then https://api.github.com.

Outputs

NameDescription
changed'true' if a new commit was created (the tree differed from the base branch's)
pull-request-numberThe pull request's number, or empty if none exists
pull-request-urlThe pull request's URL, or empty if none exists
commit-shaThe new commit's sha, or empty if nothing changed

Run zizmor's security audit — missing SHA pins, pull_request_target misuse, script injection via untrusted input, overly broad permissions, etc. — against this repository's workflows and action definitions.

Prerequisites: The caller is responsible for checkout.

Usage

jobs:
lint-github-actions:
runs-on: ubuntu-latesttimeout-minutes: 10permissions:
contents: readsteps:
- uses: actions/checkout@v4
- uses: tailor-platform/actions/lint-github-actions@v2

To lint only the workflow/action files changed in a PR instead of the whole repository, pass paths — a list of paths forwarded as-is to zizmor, which splits it on whitespace, so both space- and newline-separated lists work (you can use whichever the upstream changed-files action produces). Guard the step with if: so it's skipped when nothing matching changed — an empty paths string is not the same as omitting it and would make zizmor fail with no files to audit:

jobs:
lint-github-actions:
runs-on: ubuntu-latesttimeout-minutes: 10permissions:
contents: readsteps:
- uses: actions/checkout@v4
- uses: tj-actions/changed-files@v46id: changedwith:
files: | .github/workflows/** **/action.yaml - uses: tailor-platform/actions/lint-github-actions@v2if: steps.changed.outputs.any_changed == 'true'with:
paths: ${{ steps.changed.outputs.all_changed_files }}

Inputs

NameRequiredDefaultDescription
pathsNo.List of paths to audit — space- or newline-separated, either works. Defaults to the whole repository; pass the output of a changed-files action to lint only changed files. An empty string is not the same as omitting this input — it makes zizmor fail with no paths to audit, so guard the step with if: instead.
zizmor-advanced-securityNofalseUpload zizmor's findings to the repository's Security tab (GitHub Advanced Security) as SARIF instead of plain workflow annotations. Requires GHAS to be enabled on the repository.
github-tokenNo${{ github.token }}GitHub token for zizmor's online audits

Delete the preview workspace when a PR is closed. Reads the workspace ID from the PR comment posted by preview-comment and deletes the workspace. Run on pull_requestclosed events.

Usage

jobs:
preview-cleanup:
runs-on: ubuntu-latestif: github.event.action == 'closed'permissions:
contents: readpull-requests: writesteps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4with:
node-version-file: package.jsoncache: pnpm
- run: pnpm install --frozen-lockfile
- uses: tailor-platform/actions/preview-cleanup@v2with:
workspace-name-prefix: my-appplatform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}github-token: ${{ secrets.GITHUB_TOKEN }}

Inputs

NameRequiredDefaultDescription
workspace-name-prefixYesSame prefix used in preview-deploy
working-directoryNo.Working directory (for monorepo setups)
package-managerNoPackage manager (pnpm, npm, yarn, or bun). Defaults to npx.
platform-client-idYesOAuth2 client ID for machine user
platform-client-secretYesOAuth2 client secret for machine user
github-tokenYesGitHub token with pull-requests: write for reading and updating the PR comment

Decide whether the diff between two commits touches any path you care about, and resolve the true fork point (git merge-base) between them via the compare API's merge_base_commit — not sha-base's moving tip, which would otherwise mix in unrelated changes made to the base branch after the two commits diverged. Useful for skipping expensive work on an irrelevant push/PR while still reusing a base-branch snapshot found at the correct fork point (pair with find-base-run).

Usage

jobs:
check-relevance:
runs-on: ubuntu-latestpermissions:
contents: readsteps:
- uses: tailor-platform/actions/relevance@v2id: relevancewith:
sha-base: ${{ github.event.pull_request.base.sha }}sha-head: ${{ github.event.pull_request.head.sha }}relevant-paths: | tailor.config.ts tailordb/github-token: ${{ secrets.GITHUB_TOKEN }}outputs:
relevant: ${{ steps.relevance.outputs.relevant }}fork-sha: ${{ steps.relevance.outputs.fork-sha }}

Inputs

NameRequiredDefaultDescription
sha-baseYesBase commit to diff from. Pass the all-zero SHA (0000000000000000000000000000000000000000, as GitHub does for a branch's first push) to always treat the diff as relevant.
sha-headYesHead commit to diff to
relevant-pathsNoNewline-separated list of paths that make the diff relevant. A line ending in / matches as a prefix against changed file paths; anything else must match a changed file path exactly. Empty means no path makes the diff relevant on its own — only sha-base being the all-zero SHA, or the compare API's file list hitting its 300-entry cap (treated as possibly truncated), will set relevant=true.
github-tokenYesGitHub token for the compare API call

Outputs

NameDescription
relevant"true" or "false"
fork-shaThe true fork point (merge-base) between sha-base and sha-head. Empty when sha-base is the all-zero SHA (no prior commit to compare against, so there is no fork point to resolve).

Search a workflow's successful runs on a given branch, newest-first, for the most recent one at or before a given commit (the "fork point"). Useful for reusing a base-branch artifact at the correct point in history instead of the branch's moving tip, which would otherwise mix in changes made after the two commits diverged — pair with relevance, which resolves the fork point via the compare API's merge_base_commit.

Deliberately returns no match (rather than falling back to the latest run) when nothing at-or-before the fork point is found among the checked candidates — a later run could include changes merged into the branch after the fork point, which is the exact mismatch this action exists to avoid. Treat an empty run-id as "no usable base" and degrade accordingly (e.g. render everything as newly added), not as an error.

Usage

jobs:
find-base:
runs-on: ubuntu-latestpermissions:
contents: readactions: readsteps:
- uses: tailor-platform/actions/find-base-run@v2id: findwith:
workflow-file: schema-export.yamlbase-ref: ${{ github.event.pull_request.base.ref }}fork-sha: ${{ steps.relevance.outputs.fork-sha }}github-token: ${{ secrets.GITHUB_TOKEN }}outputs:
run-id: ${{ steps.find.outputs.run-id }}

Inputs

NameRequiredDefaultDescription
workflow-fileYesFilename of the workflow whose run history to search (e.g. schema-export.yaml), not its display name
base-refYesBranch to search runs on
fork-shaYesCommit to find a run at or before
max-candidate-runsNo1000Safety cap on how many candidate runs to check, on top of retention-days. Must be a positive integer.
retention-daysNo90Only consider runs created within this many days. Set this to match whatever artifact retention period your runs use — a run outside that window has nothing left to download regardless of whether it matches. Must be a positive integer.
github-tokenYesGitHub token with actions: read permission

Outputs

NameDescription
run-idID of the matching run, or empty if none of the checked candidates are at or before fork-sha.

License

MIT

About

Reusable GitHub Actions workflows for Tailor Platform

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages