Skip to content

Commit 8621287

Browse files
nsheapsclaude
andauthored
Add checkout-as-app action and enhance github-app-auth (#9)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9a4d595 commit 8621287

2 files changed

Lines changed: 193 additions & 4 deletions

File tree

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
name: 'Checkout as GitHub App'
2+
description: 'Authenticate as a GitHub App and checkout the repository with the app token baked into the remote URL, so subsequent git operations use the app credentials.'
3+
4+
branding:
5+
icon: 'download'
6+
color: 'blue'
7+
8+
inputs:
9+
# ── GitHub App Auth inputs ──
10+
app-id:
11+
description: 'GitHub App ID'
12+
required: true
13+
14+
private-key:
15+
description: 'GitHub App private key'
16+
required: true
17+
18+
owner:
19+
description: 'Repository owner for the GitHub App token (defaults to current repository owner)'
20+
required: false
21+
default: ${{ github.repository_owner }}
22+
23+
# ── Checkout inputs (passthrough to actions/checkout) ──
24+
repository:
25+
description: 'Repository name with owner. For example, actions/checkout'
26+
required: false
27+
default: ${{ github.repository }}
28+
29+
ref:
30+
description: 'The branch, tag or SHA to checkout. When checking out the repository that triggered a workflow, this defaults to the reference or SHA for that event. Otherwise, uses the default branch.'
31+
required: false
32+
default: ''
33+
34+
path:
35+
description: 'Relative path under $GITHUB_WORKSPACE to place the repository'
36+
required: false
37+
default: ''
38+
39+
clean:
40+
description: 'Whether to execute git clean -ffdx && git reset --hard HEAD before fetching'
41+
required: false
42+
default: 'true'
43+
44+
filter:
45+
description: 'Partially clone against a given filter. Overrides sparse-checkout if set.'
46+
required: false
47+
default: ''
48+
49+
sparse-checkout:
50+
description: 'Do a sparse checkout on given patterns. Each pattern should be separated with new lines.'
51+
required: false
52+
default: ''
53+
54+
sparse-checkout-cone-mode:
55+
description: 'Specifies whether to use cone-mode when doing a sparse checkout.'
56+
required: false
57+
default: 'true'
58+
59+
fetch-depth:
60+
description: 'Number of commits to fetch. 0 indicates all history for all branches and tags.'
61+
required: false
62+
default: '1'
63+
64+
fetch-tags:
65+
description: 'Whether to fetch tags, even if fetch-depth > 0.'
66+
required: false
67+
default: 'false'
68+
69+
show-progress:
70+
description: 'Whether to show progress status output when fetching.'
71+
required: false
72+
default: 'true'
73+
74+
lfs:
75+
description: 'Whether to download Git-LFS files'
76+
required: false
77+
default: 'false'
78+
79+
submodules:
80+
description: 'Whether to checkout submodules: true to checkout submodules or recursive to recursively checkout submodules.'
81+
required: false
82+
default: 'false'
83+
84+
set-safe-directory:
85+
description: 'Add repository path as safe.directory for the checkout.'
86+
required: false
87+
default: 'true'
88+
89+
github-server-url:
90+
description: 'The base URL for the GitHub instance that you are trying to clone from, it will use environment defaults to fetch from the same instance that the workflow is running from unless specified.'
91+
required: false
92+
default: ''
93+
94+
persist-credentials:
95+
description: 'Whether to configure the token or SSH key with the local git config. Defaults to true so the app token persists for subsequent git operations.'
96+
required: false
97+
default: 'true'
98+
99+
outputs:
100+
# ── Auth outputs (from github-app-auth) ──
101+
token:
102+
description: 'GitHub App token'
103+
value: ${{ steps.auth.outputs.token }}
104+
105+
app-slug:
106+
description: 'GitHub App slug name'
107+
value: ${{ steps.auth.outputs.app-slug }}
108+
109+
user-id:
110+
description: 'GitHub App bot user ID'
111+
value: ${{ steps.auth.outputs.user-id }}
112+
113+
user-name:
114+
description: 'GitHub App bot user name (app slug with [bot] suffix)'
115+
value: ${{ steps.auth.outputs.user-name }}
116+
117+
user-email:
118+
description: 'GitHub App bot email address'
119+
value: ${{ steps.auth.outputs.user-email }}
120+
121+
# ── Checkout outputs ──
122+
ref:
123+
description: 'The branch, tag or SHA that was checked out'
124+
value: ${{ steps.checkout.outputs.ref }}
125+
126+
commit:
127+
description: 'The commit SHA that was checked out'
128+
value: ${{ steps.checkout.outputs.commit }}
129+
130+
runs:
131+
using: 'composite'
132+
steps:
133+
# ── Step 1: Authenticate as GitHub App (skip its built-in checkout) ──
134+
- name: Authenticate as GitHub App
135+
id: auth
136+
uses: ./.github/actions/github-app-auth
137+
with:
138+
app-id: ${{ inputs.app-id }}
139+
private-key: ${{ inputs.private-key }}
140+
owner: ${{ inputs.owner }}
141+
skip-checkout: 'true'
142+
143+
# ── Step 2: Checkout with app token baked into the remote URL ──
144+
- name: Checkout repository as GitHub App
145+
id: checkout
146+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
147+
with:
148+
token: ${{ steps.auth.outputs.token }}
149+
repository: ${{ inputs.repository }}
150+
ref: ${{ inputs.ref }}
151+
path: ${{ inputs.path }}
152+
clean: ${{ inputs.clean }}
153+
filter: ${{ inputs.filter }}
154+
sparse-checkout: ${{ inputs.sparse-checkout }}
155+
sparse-checkout-cone-mode: ${{ inputs.sparse-checkout-cone-mode }}
156+
fetch-depth: ${{ inputs.fetch-depth }}
157+
fetch-tags: ${{ inputs.fetch-tags }}
158+
show-progress: ${{ inputs.show-progress }}
159+
lfs: ${{ inputs.lfs }}
160+
submodules: ${{ inputs.submodules }}
161+
set-safe-directory: ${{ inputs.set-safe-directory }}
162+
github-server-url: ${{ inputs.github-server-url }}
163+
persist-credentials: ${{ inputs.persist-credentials }}

‎.github/actions/github-app-auth/action.yml‎

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ inputs:
1919
required: false
2020
default: ${{ github.repository_owner }}
2121

22+
skip-checkout:
23+
description: 'Skip the checkout step (useful when called from checkout-as-app)'
24+
required: false
25+
default: 'false'
26+
2227
outputs:
2328
token:
2429
description: 'GitHub App token'
@@ -36,6 +41,10 @@ outputs:
3641
description: 'GitHub App bot user name (app slug with [bot] suffix)'
3742
value: ${{ steps.get-user-id.outputs.user-name }}
3843

44+
user-email:
45+
description: 'GitHub App bot email address'
46+
value: ${{ steps.get-user-id.outputs.user-email }}
47+
3948
runs:
4049
using: 'composite'
4150
steps:
@@ -51,8 +60,12 @@ runs:
5160
id: get-user-id
5261
shell: bash
5362
run: |
54-
echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
55-
echo "user-name=${{ steps.app-token.outputs.app-slug }}[bot]" >> "$GITHUB_OUTPUT"
63+
USER_ID=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)
64+
USER_NAME="${{ steps.app-token.outputs.app-slug }}[bot]"
65+
USER_EMAIL="${USER_ID}+${USER_NAME}@users.noreply.github.com"
66+
echo "user-id=${USER_ID}" >> "$GITHUB_OUTPUT"
67+
echo "user-name=${USER_NAME}" >> "$GITHUB_OUTPUT"
68+
echo "user-email=${USER_EMAIL}" >> "$GITHUB_OUTPUT"
5669
env:
5770
GH_TOKEN: ${{ steps.app-token.outputs.token }}
5871

@@ -63,13 +76,26 @@ runs:
6376
run: |
6477
gh auth setup-git
6578
echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV
79+
echo "Wrote GH_TOKEN to GITHUB_ENV"
6680
echo "GITHUB_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV
81+
echo "Wrote GITHUB_TOKEN to GITHUB_ENV"
6782
git config --global user.name '${{ steps.get-user-id.outputs.user-name }}'
6883
git config user.name '${{ steps.get-user-id.outputs.user-name }}'
69-
git config --global user.email '${{ steps.get-user-id.outputs.user-id }}+${{ steps.get-user-id.outputs.user-name }}@users.noreply.github.com'
70-
git config user.email '${{ steps.get-user-id.outputs.user-id }}+${{ steps.get-user-id.outputs.user-name }}@users.noreply.github.com'
84+
git config --global user.email '${{ steps.get-user-id.outputs.user-email }}'
85+
git config user.email '${{ steps.get-user-id.outputs.user-email }}'
86+
87+
- name: Output GitHub App authentication info
88+
shell: bash
89+
run: |
90+
echo "GitHub App Authentication Info:"
91+
echo "-------------------------------"
92+
echo "- User Name: ${{ steps.get-user-id.outputs.user-name }}"
93+
echo "- User ID: ${{ steps.get-user-id.outputs.user-id }}"
94+
echo "- User Email: ${{ steps.get-user-id.outputs.user-email }}"
95+
echo "- App Slug: ${{ steps.app-token.outputs.app-slug }}"
7196
7297
- name: Configure repo checkout token
98+
if: inputs.skip-checkout != 'true'
7399
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
74100
with:
75101
token: ${{ steps.app-token.outputs.token }}

0 commit comments

Comments
 (0)