@@ -18,16 +18,133 @@ inputs:
1818outputs :
1919 run-id :
2020 description : " UUIDv4 for this upgrade run"
21+ value : ${{ steps.run-id.outputs.run-id }}
2122 pr-url :
2223 description : " URL of the created or updated upgrade PR (empty if no changes)"
24+ value : ${{ steps.manage-pr.outputs.pr-url }}
2325 cli-upgraded :
2426 description : " Whether the Fern CLI version was upgraded (true/false)"
27+ value : ${{ steps.diff.outputs.cli-upgraded }}
2528 generators-upgraded :
2629 description : " JSON array of {generator, from, to} for each upgraded generator"
30+ value : ${{ steps.diff.outputs.generators-upgraded }}
2731
2832runs :
29- using : " node20"
30- main : " dist/index.js"
33+ using : composite
34+ steps :
35+ - name : Resolve Fern CLI
36+ id : cli
37+ uses : fern-api/actions/resolve-cli@main
38+ with :
39+ version : ${{ inputs.version }}
40+
41+ - name : Set run ID
42+ id : run-id
43+ shell : bash
44+ run : |
45+ if [ -z "${FERN_RUN_ID}" ]; then
46+ FERN_RUN_ID=$(node -e "console.log(require('crypto').randomUUID())")
47+ echo "FERN_RUN_ID=${FERN_RUN_ID}" >> "$GITHUB_ENV"
48+ echo "Generated new FERN_RUN_ID: ${FERN_RUN_ID}"
49+ else
50+ echo "Inheriting existing FERN_RUN_ID: ${FERN_RUN_ID}"
51+ fi
52+ echo "run-id=${FERN_RUN_ID}" >> "$GITHUB_OUTPUT"
53+
54+ - name : Capture before versions
55+ id : before
56+ shell : bash
57+ run : |
58+ SNAPSHOT=$(node "${{ github.action_path }}/scripts/snapshot.js")
59+ echo "snapshot=$SNAPSHOT" >> "$GITHUB_OUTPUT"
60+ echo "Captured before snapshot: $SNAPSHOT"
61+
62+ - name : Run fern upgrade
63+ shell : bash
64+ env :
65+ FERN_TOKEN : ${{ inputs.fern-token }}
66+ run : |
67+ echo "Running fern upgrade..."
68+ ${{ steps.cli.outputs.fern-cmd }} upgrade --yes || \
69+ echo "::warning::fern upgrade exited with non-zero code"
70+
71+ - name : Run fern generator upgrade
72+ shell : bash
73+ env :
74+ FERN_TOKEN : ${{ inputs.fern-token }}
75+ run : |
76+ echo "Running fern generator upgrade..."
77+ ${{ steps.cli.outputs.fern-cmd }} generator upgrade --yes || \
78+ echo "::warning::fern generator upgrade exited with non-zero code"
79+ # TODO: FER-9669 — Check automation config before running upgrades
80+
81+ - name : Compute upgrade diff
82+ id : diff
83+ shell : bash
84+ env :
85+ BEFORE_SNAPSHOT : ${{ steps.before.outputs.snapshot }}
86+ run : node "${{ github.action_path }}/scripts/diff.js"
87+
88+ - name : Push changes and manage PR
89+ id : manage-pr
90+ if : steps.diff.outputs.has-changes == 'true'
91+ shell : bash
92+ env :
93+ GH_TOKEN : ${{ inputs.github-token }}
94+ GITHUB_TOKEN : ${{ inputs.github-token }}
95+ PR_TITLE : ${{ steps.diff.outputs.pr-title }}
96+ COMMIT_MSG : ${{ steps.diff.outputs.commit-msg }}
97+ run : |
98+ BRANCH="fern/upgrade"
99+
100+ # Configure git
101+ git config user.name "github-actions[bot]"
102+ git config user.email "github-actions[bot]@users.noreply.github.com"
103+
104+ # Get default branch
105+ DEFAULT_BRANCH=$(gh api "repos/${{ github.repository }}" --jq '.default_branch')
106+ echo "Default branch: $DEFAULT_BRANCH"
107+
108+ # Warn if overwriting existing branch
109+ if git ls-remote --heads origin "$BRANCH" | grep -q "$BRANCH"; then
110+ echo "::warning::Existing $BRANCH branch will be overwritten (clean-slate strategy)"
111+ fi
112+
113+ # Clean-slate branch from default branch HEAD
114+ git fetch origin "$DEFAULT_BRANCH"
115+ git checkout -B "$BRANCH" "origin/$DEFAULT_BRANCH"
116+
117+ # Stage all changes
118+ git add -A
119+ if git diff --cached --quiet; then
120+ echo "No changes to commit"
121+ echo "pr-url=" >> "$GITHUB_OUTPUT"
122+ exit 0
123+ fi
124+
125+ # Commit and force push
126+ git commit -m "$COMMIT_MSG"
127+ git push --force origin "$BRANCH"
128+
129+ # Write PR body to temp file to avoid shell escaping issues
130+ cat > /tmp/pr-body.md << 'PREOF'
131+ ${{ steps.diff.outputs.pr-body }}
132+ PREOF
133+
134+ # Create or update PR
135+ EXISTING_PR=$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number // empty')
136+ if [ -n "$EXISTING_PR" ]; then
137+ gh pr edit "$EXISTING_PR" --title "$PR_TITLE" --body-file /tmp/pr-body.md
138+ PR_URL=$(gh pr view "$EXISTING_PR" --json url --jq '.url')
139+ echo "Updated existing PR: $PR_URL"
140+ else
141+ PR_URL=$(gh pr create --head "$BRANCH" --base "$DEFAULT_BRANCH" \
142+ --title "$PR_TITLE" --body-file /tmp/pr-body.md)
143+ echo "Created new PR: $PR_URL"
144+ fi
145+
146+ echo "pr-url=$PR_URL" >> "$GITHUB_OUTPUT"
147+ # TODO: FER-9668 — Emit upgrade telemetry
31148
32149branding :
33150 icon : " refresh-cw"
0 commit comments