Skip to content

Commit 5be7a10

Browse files
Swimburgerclaude
andcommitted
refactor: add resolve-cli action and migrate sync-openapi to composite
Add actions/resolve-cli — a shared composite action that resolves the fern command based on a version input (auto/latest/inherit/specific). Actions use its fern-cmd output instead of duplicating resolution logic. Migrate sync-openapi from a Node.js action to a thin composite that delegates to the Fern CLI (gha pull-spec / gha sync-specs). Remove the now-dead src/, dist/, e2e/, and build config. Add version input to generate, upgrade, and verify actions with appropriate defaults (auto for generate/verify, latest for upgrade). Restore setup-cli to a simple global installer with a version input. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c366269 commit 5be7a10

13 files changed

Lines changed: 109 additions & 34823 deletions

File tree

actions/generate/action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ description: "[ALPHA] Runs fern generate on push to main and opens SDK PRs in SD
33
author: "Fern"
44

55
inputs:
6+
version:
7+
description: "Fern CLI version to use. 'auto' respects fern.config.json and falls back to latest, 'latest' always uses the newest release, 'inherit' uses the bootstrapped binary as-is, or pin to a specific version (e.g. '0.15.0')."
8+
required: false
9+
default: "auto"
610
fern-token:
711
description: "Fern token for API access and SDK repo PR creation"
812
required: true

actions/resolve-cli/action.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Resolve Fern CLI
2+
description: "Resolves the Fern CLI command based on the requested version. Outputs a fern-cmd string to use in subsequent steps."
3+
author: "Fern"
4+
5+
inputs:
6+
version:
7+
description: "Fern CLI version to use. 'auto' respects fern.config.json and falls back to latest, 'latest' always uses the newest release, 'inherit' uses whatever CLI is already on PATH, or pin to a specific version or npm tag (e.g. '0.15.0', 'beta')."
8+
required: false
9+
default: "auto"
10+
11+
outputs:
12+
fern-cmd:
13+
description: "The resolved fern command to use in subsequent steps."
14+
value: ${{ steps.resolve.outputs.fern-cmd }}
15+
16+
runs:
17+
using: composite
18+
steps:
19+
- name: Set FERN_RUN_ID
20+
shell: bash
21+
run: |
22+
if [ -z "${FERN_RUN_ID}" ]; then
23+
FERN_RUN_ID=$(node -e "console.log(require('crypto').randomUUID())")
24+
echo "FERN_RUN_ID=${FERN_RUN_ID}" >> "$GITHUB_ENV"
25+
echo "Generated new FERN_RUN_ID: ${FERN_RUN_ID}"
26+
else
27+
echo "Inheriting existing FERN_RUN_ID: ${FERN_RUN_ID}"
28+
fi
29+
30+
- name: Resolve Fern CLI version
31+
id: resolve
32+
shell: bash
33+
env:
34+
VERSION: ${{ inputs.version }}
35+
run: |
36+
# auto → npx fern-api@latest (let CLI resolve from fern.config.json)
37+
# latest → npx fern-api@latest with FERN_NO_VERSION_REDIRECTION
38+
# inherit → bare `fern` from PATH with FERN_NO_VERSION_REDIRECTION
39+
# <other> → npx fern-api@<version> with FERN_NO_VERSION_REDIRECTION
40+
if [ "$VERSION" = "auto" ]; then
41+
FERN_CMD="npx --yes fern-api@latest"
42+
elif [ "$VERSION" = "inherit" ]; then
43+
if ! command -v fern &>/dev/null; then
44+
echo "::error::version is 'inherit' but fern is not on PATH."
45+
exit 1
46+
fi
47+
FERN_CMD="fern"
48+
echo "FERN_NO_VERSION_REDIRECTION=true" >> "$GITHUB_ENV"
49+
else
50+
FERN_CMD="npx --yes fern-api@$VERSION"
51+
echo "FERN_NO_VERSION_REDIRECTION=true" >> "$GITHUB_ENV"
52+
fi
53+
54+
echo "fern-cmd=$FERN_CMD" >> "$GITHUB_OUTPUT"
55+
echo "Resolved fern command: $FERN_CMD"

actions/setup-cli/action.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: Setup Fern CLI
2-
description: "Install the Fern CLI in your GitHub Actions workflow. Requires Node.js and npm — add actions/setup-node before this step if your runner doesn't include them."
2+
description: "Install the Fern CLI globally in your GitHub Actions workflow. Requires Node.js and npm — add actions/setup-node before this step if your runner doesn't include them."
33
author: "Fern"
44

55
branding:
@@ -8,7 +8,7 @@ branding:
88

99
inputs:
1010
version:
11-
description: "Fern CLI version to install. Use 'latest' to always get the newest release, or pin to a specific version (e.g. '0.15.0') for reproducible builds."
11+
description: "Fern CLI version to install globally. Use 'latest' to get the newest release, or pin to a specific version or npm tag (e.g. '0.15.0', 'beta')."
1212
required: false
1313
default: "latest"
1414

@@ -39,11 +39,11 @@ runs:
3939
VERSION: ${{ inputs.version }}
4040
run: |
4141
if ! command -v npm &>/dev/null; then
42-
echo "Error: npm is not available. Please add a Node.js setup step before this action."
42+
echo "::error::npm is not available. Please add a Node.js setup step before this action."
4343
exit 1
4444
fi
4545
if ! command -v node &>/dev/null; then
46-
echo "Error: node is not available. Please add a Node.js setup step before this action."
46+
echo "::error::node is not available. Please add a Node.js setup step before this action."
4747
exit 1
4848
fi
4949

actions/sync-openapi/action.yml

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ description: "Keep your Fern config up to date — pull OpenAPI specs from a URL
33
author: "Fern"
44

55
inputs:
6+
version:
7+
description: "Fern CLI version to use. Use 'latest' to always get the newest release, a specific version (e.g. '0.15.0') for reproducible builds, or 'inherit' to use whatever CLI is already installed."
8+
required: false
9+
default: "latest"
610
token:
711
description: "GitHub token with contents: write and pull-requests: write on the target repository."
812
required: true
913
update_from_source:
10-
description: "Set to 'true' to run 'fern api update' and pull the latest spec from the URL configured in generators.yml. Use this for Case 1 (public URL). Set to 'false' to sync files between repositories (Case 2)."
14+
description: "Set to 'true' to run 'fern api pull' and fetch the latest spec from the URL configured in generators.yml. Set to 'false' to sync files between repositories."
1115
required: false
1216
default: "false"
1317
repository:
@@ -17,17 +21,45 @@ inputs:
1721
description: "YAML or JSON array of file/folder mappings to sync from this repo into the target repository. Each entry must have 'from' and 'to' fields (relative to repo roots), and an optional 'exclude' list of glob patterns. Only used when update_from_source is 'false'."
1822
required: false
1923
branch:
20-
description: "Branch name to create or update in the target repository. Must be a stable name — do not use dynamic or timestamped names, or PR deduplication will break. Commits accumulate on this branch across runs."
24+
description: "Branch name to create or update. Must be a stable name — do not use dynamic or timestamped names, or PR deduplication will break. Defaults to 'fern/pull-spec' for update_from_source mode and 'fern/sync-specs' for sync mode."
2125
required: false
22-
default: "fern/sync-openapi"
2326
auto_merge:
24-
description: "Set to 'true' to push directly to the branch without opening a PR. Set to 'false' to open a PR from the branch onto main. You must use 'true' when branch is 'main'."
27+
description: "Set to 'true' to push directly to the branch without opening a PR. Set to 'false' to open a PR from the branch onto main."
2528
required: false
2629
default: "false"
2730

2831
runs:
29-
using: "node20"
30-
main: "dist/index.js"
32+
using: composite
33+
steps:
34+
- name: Resolve Fern CLI
35+
id: cli
36+
uses: fern-api/actions/resolve-cli@main
37+
with:
38+
version: ${{ inputs.version }}
39+
40+
- name: Pull spec from origin
41+
if: inputs.update_from_source == 'true'
42+
shell: bash
43+
env:
44+
FERN_TOKEN: ${{ inputs.token }}
45+
run: |
46+
${{ steps.cli.outputs.fern-cmd }} gha pull-spec \
47+
--token "${{ inputs.token }}" \
48+
${{ inputs.branch != '' && format('--branch "{0}"', inputs.branch) || '' }} \
49+
${{ inputs.auto_merge == 'true' && '--auto-merge' || '' }}
50+
51+
- name: Sync files to target repository
52+
if: inputs.update_from_source != 'true'
53+
shell: bash
54+
env:
55+
FERN_TOKEN: ${{ inputs.token }}
56+
run: |
57+
${{ steps.cli.outputs.fern-cmd }} gha sync-specs \
58+
--repository "${{ inputs.repository }}" \
59+
--sources "${{ inputs.sources }}" \
60+
--token "${{ inputs.token }}" \
61+
${{ inputs.branch != '' && format('--branch "{0}"', inputs.branch) || '' }} \
62+
${{ inputs.auto_merge == 'true' && '--auto-merge' || '' }}
3163
3264
branding:
3365
icon: "refresh-cw"

0 commit comments

Comments
 (0)