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
32 changes: 29 additions & 3 deletions deploy/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ inputs:
description: Working directory for the project (for monorepo setups)
required: false
default: "."
package-manager:
description: >-
Package manager used to run tailor-sdk (pnpm, npm, yarn, or bun).
Defaults to npx when empty, so Bun uses its own runtime instead of
relying on an ambient Node, and the locally-installed version is used.
required: false
default: ""
platform-client-id:
description: OAuth2 client ID for Tailor Platform machine user
required: true
Expand All @@ -37,13 +44,32 @@ runs:
CLIENT_ID: ${{ inputs.platform-client-id }}
CLIENT_SECRET: ${{ inputs.platform-client-secret }}

- name: Resolve tailor-sdk runner
shell: bash
env:
PACKAGE_MANAGER: ${{ inputs.package-manager }}
# RUN is one of a fixed set of literals chosen by the case below (never
# user input), so writing it to GITHUB_ENV cannot inject code.
run: | # zizmor: ignore[github-env]
case "$PACKAGE_MANAGER" in
pnpm) RUN="pnpm exec" ;;
yarn) RUN="yarn" ;;
bun) RUN="bunx" ;;
npm|"") RUN="npx" ;;
*)
echo "::error::Unsupported package-manager '$PACKAGE_MANAGER' (expected pnpm, npm, yarn, or bun)"
exit 1
;;
esac
echo "TAILOR_SDK_RUN=$RUN" >> "$GITHUB_ENV"

- name: Login to Tailor Platform
shell: bash
working-directory: ${{ inputs.working-directory }}
env:
TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID: ${{ inputs.platform-client-id }}
TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET: ${{ inputs.platform-client-secret }}
run: npx tailor-sdk login --machineuser
run: $TAILOR_SDK_RUN tailor-sdk login --machineuser

- name: Validate workspace-id
shell: bash
Expand All @@ -60,11 +86,11 @@ runs:
working-directory: ${{ inputs.working-directory }}
env:
TAILOR_PLATFORM_WORKSPACE_ID: ${{ inputs.workspace-id }}
run: npx tailor-sdk generate
run: $TAILOR_SDK_RUN tailor-sdk generate

- name: Deploy
shell: bash
working-directory: ${{ inputs.working-directory }}
env:
TAILOR_PLATFORM_WORKSPACE_ID: ${{ inputs.workspace-id }}
run: npx tailor-sdk apply --yes
run: $TAILOR_SDK_RUN tailor-sdk apply --yes
47 changes: 47 additions & 0 deletions generate-check/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Check Tailor Platform generated files
description: >-
Run tailor-sdk generate and fail if it produces changes, catching generated
files (seed data, enum constants, etc.) that were not regenerated and
committed. Requires Node.js and dependencies to be installed by the caller.

inputs:
package-manager:
description: Package manager used to run tailor-sdk (pnpm, npm, yarn, or bun)
required: true
working-directory:
description: Working directory for the project (for monorepo setups)
required: false
default: "."

runs:
using: composite
steps:
- name: Generate
shell: bash
working-directory: ${{ inputs.working-directory }}
env:
PACKAGE_MANAGER: ${{ inputs.package-manager }}
run: |
# Run the locally-installed tailor-sdk with each package manager's own
# runner, so the pinned version is used and Bun does not depend on an
# ambient Node/npx being present on the runner.
case "$PACKAGE_MANAGER" in
pnpm) pnpm exec tailor-sdk generate ;;
npm) npx tailor-sdk generate ;;
yarn) yarn tailor-sdk generate ;;
bun) bunx tailor-sdk generate ;;
*)
echo "::error::Unsupported package-manager '$PACKAGE_MANAGER' (expected pnpm, npm, yarn, or bun)"
exit 1
;;
esac

- name: Check generated files are committed
shell: bash
run: |
CHANGES=$(git status --porcelain)
if [ -n "$CHANGES" ]; then
echo "$CHANGES"
echo "::error::Generated files are out of date. Run 'tailor-sdk generate' locally and commit the result."
exit 1
fi
30 changes: 28 additions & 2 deletions plan/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ inputs:
description: Working directory for the project (for monorepo setups)
required: false
default: "."
package-manager:
description: >-
Package manager used to run tailor-sdk (pnpm, npm, yarn, or bun).
Defaults to npx when empty, so Bun uses its own runtime instead of
relying on an ambient Node, and the locally-installed version is used.
required: false
default: ""
platform-client-id:
description: OAuth2 client ID for Tailor Platform machine user
required: true
Expand Down Expand Up @@ -53,13 +60,32 @@ runs:
CLIENT_ID: ${{ inputs.platform-client-id }}
CLIENT_SECRET: ${{ inputs.platform-client-secret }}

- name: Resolve tailor-sdk runner
shell: bash
env:
PACKAGE_MANAGER: ${{ inputs.package-manager }}
# RUN is one of a fixed set of literals chosen by the case below (never
# user input), so writing it to GITHUB_ENV cannot inject code.
run: | # zizmor: ignore[github-env]
case "$PACKAGE_MANAGER" in
pnpm) RUN="pnpm exec" ;;
yarn) RUN="yarn" ;;
bun) RUN="bunx" ;;
npm|"") RUN="npx" ;;
*)
echo "::error::Unsupported package-manager '$PACKAGE_MANAGER' (expected pnpm, npm, yarn, or bun)"
exit 1
;;
esac
echo "TAILOR_SDK_RUN=$RUN" >> "$GITHUB_ENV"

- name: Login to Tailor Platform
shell: bash
working-directory: ${{ inputs.working-directory }}
env:
TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID: ${{ inputs.platform-client-id }}
TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET: ${{ inputs.platform-client-secret }}
run: npx tailor-sdk login --machineuser
run: $TAILOR_SDK_RUN tailor-sdk login --machineuser

- name: Merge base branch
if: github.event_name == 'pull_request'
Expand All @@ -79,7 +105,7 @@ runs:
TAILOR_PLATFORM_WORKSPACE_ID: ${{ inputs.workspace-id }}
run: |
set +e
OUTPUT=$(npx tailor-sdk apply --dry-run --yes 2>&1)
OUTPUT=$($TAILOR_SDK_RUN tailor-sdk apply --dry-run --yes 2>&1)
EXIT_CODE=$?
set -e

Expand Down
65 changes: 65 additions & 0 deletions setup/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Set up Tailor Platform toolchain
description: >-
Set up Node.js (or Bun) and install project dependencies for the configured
package manager, so subsequent steps can run tailor-sdk. The caller is
responsible for checking out the repository first.

inputs:
package-manager:
description: Package manager to use (pnpm, npm, yarn, or bun)
required: true
node-version-file:
description: File to read the Node.js version from
required: false
default: package.json
install-command:
description: >-
Override the dependency-install command (e.g. a filtered monorepo
install). When empty, a frozen-lockfile install for the selected
package manager is used.
required: false
default: ""
working-directory:
description: Working directory to install dependencies in (for monorepo setups)
required: false
default: "."

runs:
using: composite
steps:
- name: Set up pnpm
if: inputs.package-manager == 'pnpm'
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8

- name: Set up Node.js
if: inputs.package-manager != 'bun'
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: ${{ inputs.node-version-file }}
cache: ${{ inputs.package-manager }}

- name: Set up Bun
if: inputs.package-manager == 'bun'
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- name: Install dependencies
shell: bash
working-directory: ${{ inputs.working-directory }}
env:
PACKAGE_MANAGER: ${{ inputs.package-manager }}
INSTALL_COMMAND: ${{ inputs.install-command }}
run: |
if [ -n "$INSTALL_COMMAND" ]; then
eval "$INSTALL_COMMAND"
Comment on lines +52 to +53
else
case "$PACKAGE_MANAGER" in
pnpm) pnpm install --frozen-lockfile ;;
npm) npm ci ;;
yarn) yarn install --frozen-lockfile ;;
bun) bun install --frozen-lockfile ;;
*)
echo "::error::Unsupported package-manager '$PACKAGE_MANAGER' (expected pnpm, npm, yarn, or bun)"
exit 1
;;
esac
fi
38 changes: 38 additions & 0 deletions tag-guard/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Guard tag reachability from a branch
description: >-
Determine whether the pushed tag's commit is reachable from a target branch,
so a tag-triggered deploy can be limited to tags cut from that branch. The
caller must check out the repository with full history (fetch-depth: 0).

inputs:
target-branch:
description: Branch the tag must be reachable from (e.g. main)
required: true

outputs:
on-branch:
description: "'true' when the tag commit is reachable from the target branch, otherwise 'false'"
value: ${{ steps.guard.outputs.on-branch }}

runs:
using: composite
steps:
- name: Check tag reachability
id: guard
shell: bash
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
run: |
# Accept both short names (main) and fully-qualified refs (refs/heads/main).
BRANCH="${TARGET_BRANCH#refs/heads/}"
git fetch origin "$BRANCH"
# GITHUB_SHA may be a tag object for annotated tags; peel to its commit
# so --is-ancestor (which expects commits) is reliable.
COMMIT="$(git rev-parse "${GITHUB_SHA}^{commit}")"
if git merge-base --is-ancestor "$COMMIT" "origin/$BRANCH"; then
echo "on-branch=true" >> "$GITHUB_OUTPUT"
else
# A tag outside the target branch is not an error — just skip.
echo "on-branch=false" >> "$GITHUB_OUTPUT"
echo "::notice::Tag $GITHUB_REF_NAME is not reachable from $BRANCH; skipping deploy."
fi