Skip to content

Commit 837e275

Browse files
gr2mparkerbxyz
andauthoredJan 26, 2024
feat: github-api-url (actions#88)
closes actions#77 --------- Co-authored-by: Parker Brown <17183625+parkerbxyz@users.noreply.github.com>
1 parent c4fa18d commit 837e275

15 files changed

+107
-55
lines changed
 

Diff for: ‎README.md

+18-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ In order to use this action, you need to:
1515
### Create a token for the current repository
1616

1717
```yaml
18-
on: [issues]
18+
name: Run tests on staging
19+
on:
20+
push:
21+
branches:
22+
- main
1923

2024
jobs:
2125
hello-world:
@@ -26,11 +30,10 @@ jobs:
2630
with:
2731
app-id: ${{ vars.APP_ID }}
2832
private-key: ${{ secrets.PRIVATE_KEY }}
29-
- uses: peter-evans/create-or-update-comment@v3
33+
github-api-url: "https://github.acme-inc.com/api/v3"
34+
- uses: ./actions/staging-tests
3035
with:
3136
token: ${{ steps.app-token.outputs.token }}
32-
issue-number: ${{ github.event.issue.number }}
33-
body: "Hello, World!"
3437
```
3538
3639
### Use app token with `actions/checkout`
@@ -146,7 +149,7 @@ jobs:
146149
run: echo 'matrix=[{"owner":"owner1"},{"owner":"owner2","repos":["repo1"]}]' >>"$GITHUB_OUTPUT"
147150
148151
use-matrix:
149-
name: '@${{ matrix.owners-and-repos.owner }} installation'
152+
name: "@${{ matrix.owners-and-repos.owner }} installation"
150153
needs: [set-matrix]
151154
runs-on: ubuntu-latest
152155
strategy:
@@ -172,6 +175,12 @@ jobs:
172175
MULTILINE_JSON_STRING: ${{ steps.get-installation-repositories.outputs.data }}
173176
```
174177

178+
### Run the workflow in a github.com repository against an organization in GitHub Enterprise Server
179+
180+
```yaml
181+
on: [push]
182+
```
183+
175184
## Inputs
176185

177186
### `app-id`
@@ -197,6 +206,10 @@ jobs:
197206

198207
**Optional:** If truthy, the token will not be revoked when the current job is complete.
199208

209+
### `github-api-url`
210+
211+
**Optional:** The URL of the GitHub REST API. Defaults to the URL of the GitHub Rest API where the workflow is run from.
212+
200213
## Outputs
201214

202215
### `token`

Diff for: ‎action.yml

+5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ inputs:
3232
description: "If truthy, the token will not be revoked when the current job is complete"
3333
required: false
3434
deprecationMessage: "'skip_token_revoke' is deprecated and will be removed in a future version. Use 'skip-token-revoke' instead."
35+
# Make GitHub API configurable to support non-GitHub Cloud use cases
36+
# see https://github.com/actions/create-github-app-token/issues/77
37+
github-api-url:
38+
description: The URL of the GitHub REST API.
39+
default: ${{ github.api_url }}
3540
outputs:
3641
token:
3742
description: "GitHub installation access token"

Diff for: ‎dist/main.cjs

+6-8
Original file line numberDiff line numberDiff line change
@@ -3023,7 +3023,7 @@ var require_dist_node6 = __commonJS({
30233023
module2.exports = __toCommonJS2(dist_src_exports);
30243024
function oauthAuthorizationUrl(options) {
30253025
const clientType = options.clientType || "oauth-app";
3026-
const baseUrl = options.baseUrl || "https://github.com";
3026+
const baseUrl2 = options.baseUrl || "https://github.com";
30273027
const result = {
30283028
clientType,
30293029
allowSignup: options.allowSignup === false ? false : true,
@@ -3037,7 +3037,7 @@ var require_dist_node6 = __commonJS({
30373037
const scopes = "scopes" in options ? options.scopes : [];
30383038
result.scopes = typeof scopes === "string" ? scopes.split(/[,\s]+/).filter(Boolean) : scopes;
30393039
}
3040-
result.url = urlBuilderAuthorize(`${baseUrl}/login/oauth/authorize`, result);
3040+
result.url = urlBuilderAuthorize(`${baseUrl2}/login/oauth/authorize`, result);
30413041
return result;
30423042
}
30433043
function urlBuilderAuthorize(base, options) {
@@ -3149,10 +3149,10 @@ var require_dist_node7 = __commonJS({
31493149
request: request2 = import_request3.request,
31503150
...options
31513151
}) {
3152-
const baseUrl = requestToOAuthBaseUrl(request2);
3152+
const baseUrl2 = requestToOAuthBaseUrl(request2);
31533153
return (0, import_oauth_authorization_url.oauthAuthorizationUrl)({
31543154
...options,
3155-
baseUrl
3155+
baseUrl: baseUrl2
31563156
});
31573157
}
31583158
var import_request22 = require_dist_node5();
@@ -10464,7 +10464,6 @@ async function getTokenFromRepository(request2, auth, parsedOwner, parsedReposit
1046410464
// lib/request.js
1046510465
var import_request = __toESM(require_dist_node5(), 1);
1046610466
var request_default = import_request.request.defaults({
10467-
baseUrl: process.env["GITHUB_API_URL"],
1046810467
headers: {
1046910468
"user-agent": "actions/create-github-app-token"
1047010469
}
@@ -10490,16 +10489,15 @@ var repositories = import_core.default.getInput("repositories");
1049010489
var skipTokenRevoke = Boolean(
1049110490
import_core.default.getInput("skip-token-revoke") || import_core.default.getInput("skip_token_revoke")
1049210491
);
10492+
var baseUrl = import_core.default.getInput("github-api-url").replace(/\/$/, "");
1049310493
main(
1049410494
appId,
1049510495
privateKey,
1049610496
owner,
1049710497
repositories,
1049810498
import_core.default,
1049910499
import_auth_app.createAppAuth,
10500-
request_default.defaults({
10501-
baseUrl: process.env["GITHUB_API_URL"]
10502-
}),
10500+
request_default.defaults({ baseUrl }),
1050310501
skipTokenRevoke
1050410502
).catch((error) => {
1050510503
console.error(error);

Diff for: ‎dist/post.cjs

+2-7
Original file line numberDiff line numberDiff line change
@@ -3030,19 +3030,14 @@ function tokenExpiresIn(expiresAt) {
30303030
// lib/request.js
30313031
var import_request = __toESM(require_dist_node5(), 1);
30323032
var request_default = import_request.request.defaults({
3033-
baseUrl: process.env["GITHUB_API_URL"],
30343033
headers: {
30353034
"user-agent": "actions/create-github-app-token"
30363035
}
30373036
});
30383037

30393038
// post.js
3040-
post(
3041-
import_core.default,
3042-
request_default.defaults({
3043-
baseUrl: process.env["GITHUB_API_URL"]
3044-
})
3045-
).catch((error) => {
3039+
var baseUrl = import_core.default.getInput("github-api-url").replace(/\/$/, "");
3040+
post(import_core.default, request_default.defaults({ baseUrl })).catch((error) => {
30463041
console.error(error);
30473042
import_core.default.setFailed(error.message);
30483043
});

Diff for: ‎lib/request.js

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { request } from "@octokit/request";
22

33
export default request.defaults({
4-
baseUrl: process.env["GITHUB_API_URL"],
54
headers: {
65
"user-agent": "actions/create-github-app-token",
76
},

Diff for: ‎main.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,16 @@ const skipTokenRevoke = Boolean(
3131
core.getInput("skip-token-revoke") || core.getInput("skip_token_revoke")
3232
);
3333

34+
const baseUrl = core.getInput("github-api-url").replace(/\/$/, "");
35+
3436
main(
3537
appId,
3638
privateKey,
3739
owner,
3840
repositories,
3941
core,
4042
createAppAuth,
41-
request.defaults({
42-
baseUrl: process.env["GITHUB_API_URL"],
43-
}),
43+
request.defaults({ baseUrl }),
4444
skipTokenRevoke
4545
).catch((error) => {
4646
/* c8 ignore next 3 */

Diff for: ‎post.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,9 @@ import core from "@actions/core";
55
import { post } from "./lib/post.js";
66
import request from "./lib/request.js";
77

8-
post(
9-
core,
10-
request.defaults({
11-
baseUrl: process.env["GITHUB_API_URL"],
12-
})
13-
).catch((error) => {
8+
const baseUrl = core.getInput("github-api-url").replace(/\/$/, "");
9+
10+
post(core, request.defaults({ baseUrl })).catch((error) => {
1411
/* c8 ignore next 3 */
1512
console.error(error);
1613
core.setFailed(error.message);

Diff for: ‎tests/main-custom-github-api-url.test.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { test, DEFAULT_ENV } from "./main.js";
2+
3+
// Verify that main works with a custom GitHub API URL passed as `github-api-url` input
4+
await test(
5+
() => {
6+
process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER;
7+
process.env.INPUT_REPOSITORIES = process.env.GITHUB_REPOSITORY;
8+
},
9+
{
10+
...DEFAULT_ENV,
11+
"INPUT_GITHUB-API-URL": "https://github.acme-inc.com/api/v3",
12+
}
13+
);

Diff for: ‎tests/main-token-get-owner-set-repo-fail-response.test.js

+7-8
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { test } from "./main.js";
22

33
// Verify `main` retry when the GitHub API returns a 500 error.
44
await test((mockPool) => {
5-
process.env.INPUT_OWNER = 'actions'
6-
process.env.INPUT_REPOSITORIES = 'failed-repo';
7-
const owner = process.env.INPUT_OWNER
8-
const repo = process.env.INPUT_REPOSITORIES
5+
process.env.INPUT_OWNER = "actions";
6+
process.env.INPUT_REPOSITORIES = "failed-repo";
7+
const owner = process.env.INPUT_OWNER;
8+
const repo = process.env.INPUT_REPOSITORIES;
99
const mockInstallationId = "123456";
1010

1111
mockPool
@@ -18,9 +18,9 @@ await test((mockPool) => {
1818
// Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
1919
},
2020
})
21-
.reply(500, 'GitHub API not available')
22-
23-
mockPool
21+
.reply(500, "GitHub API not available");
22+
23+
mockPool
2424
.intercept({
2525
path: `/repos/${owner}/${repo}/installation`,
2626
method: "GET",
@@ -35,5 +35,4 @@ await test((mockPool) => {
3535
{ id: mockInstallationId },
3636
{ headers: { "content-type": "application/json" } }
3737
);
38-
3938
});

Diff for: ‎tests/main-token-get-owner-set-to-user-fail-response.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ await test((mockPool) => {
1717
// Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
1818
},
1919
})
20-
.reply(500, 'GitHub API not available')
21-
mockPool
20+
.reply(500, "GitHub API not available");
21+
mockPool
2222
.intercept({
2323
path: `/orgs/${process.env.INPUT_OWNER}/installation`,
2424
method: "GET",

Diff for: ‎tests/main.js

+21-14
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
// @ts-check
33
import { MockAgent, setGlobalDispatcher } from "undici";
44

5-
export async function test(cb = (_mockPool) => {}) {
6-
// Set required environment variables and inputs
7-
process.env.GITHUB_REPOSITORY_OWNER = "actions";
8-
process.env.GITHUB_REPOSITORY = "actions/create-github-app-token";
5+
export const DEFAULT_ENV = {
6+
GITHUB_REPOSITORY_OWNER: "actions",
7+
GITHUB_REPOSITORY: "actions/create-github-app-token",
98
// inputs are set as environment variables with the prefix INPUT_
109
// https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs
11-
process.env["INPUT_APP-ID"] = "123456";
12-
process.env["INPUT_PRIVATE-KEY"] = `-----BEGIN RSA PRIVATE KEY-----
10+
"INPUT_GITHUB-API-URL": "https://api.github.com",
11+
"INPUT_APP-ID": "123456",
12+
// This key is invalidated. It’s from https://github.com/octokit/auth-app.js/issues/465#issuecomment-1564998327.
13+
"INPUT_PRIVATE-KEY": `-----BEGIN RSA PRIVATE KEY-----
1314
MIIEowIBAAKCAQEA280nfuUM9w00Ib9E2rvZJ6Qu3Ua3IqR34ZlK53vn/Iobn2EL
1415
Z9puc5Q/nFBU15NKwHyQNb+OG2hTCkjd1Xi9XPzEOH1r42YQmTGq8YCkUSkk6KZA
1516
5dnhLwN9pFquT9fQgrf4r1D5GJj3rqvj8JDr1sBmunArqY5u4gziSrIohcjLIZV0
@@ -35,27 +36,33 @@ r4J2gqb0xTDfq7gLMNrIXc2QQM4gKbnJp60JQM3p9NmH8huavBZGvSvNzTwXyGG3
3536
so0tiQKBgGQXZaxaXhYUcxYHuCkQ3V4Vsj3ezlM92xXlP32SGFm3KgFhYy9kATxw
3637
Cax1ytZzvlrKLQyQFVK1COs2rHt7W4cJ7op7C8zXfsigXCiejnS664oAuX8sQZID
3738
x3WQZRiXlWejSMUAHuMwXrhGlltF3lw83+xAjnqsVp75kGS6OH61
38-
-----END RSA PRIVATE KEY-----`; // This key is invalidated. It’s from https://github.com/octokit/auth-app.js/issues/465#issuecomment-1564998327.
39+
-----END RSA PRIVATE KEY-----`,
40+
};
41+
42+
export async function test(cb = (_mockPool) => {}, env = DEFAULT_ENV) {
43+
for (const [key, value] of Object.entries(env)) {
44+
process.env[key] = value;
45+
}
3946

4047
// Set up mocking
48+
const baseUrl = new URL(env["INPUT_GITHUB-API-URL"]);
49+
const basePath = baseUrl.pathname === '/' ? '' : baseUrl.pathname;
4150
const mockAgent = new MockAgent();
4251
mockAgent.disableNetConnect();
4352
setGlobalDispatcher(mockAgent);
44-
const mockPool = mockAgent.get("https://api.github.com");
53+
const mockPool = mockAgent.get(baseUrl.origin);
4554

4655
// Calling `auth({ type: "app" })` to obtain a JWT doesn’t make network requests, so no need to intercept.
4756

4857
// Mock installation id request
4958
const mockInstallationId = "123456";
50-
const owner = process.env.INPUT_OWNER ?? process.env.GITHUB_REPOSITORY_OWNER;
59+
const owner = env.INPUT_OWNER ?? env.GITHUB_REPOSITORY_OWNER;
5160
const repo = encodeURIComponent(
52-
(process.env.INPUT_REPOSITORIES ?? process.env.GITHUB_REPOSITORY).split(
53-
","
54-
)[0]
61+
(env.INPUT_REPOSITORIES ?? env.GITHUB_REPOSITORY).split(",")[0]
5562
);
5663
mockPool
5764
.intercept({
58-
path: `/repos/${owner}/${repo}/installation`,
65+
path: `${basePath}/repos/${owner}/${repo}/installation`,
5966
method: "GET",
6067
headers: {
6168
accept: "application/vnd.github.v3+json",
@@ -75,7 +82,7 @@ x3WQZRiXlWejSMUAHuMwXrhGlltF3lw83+xAjnqsVp75kGS6OH61
7582
const mockExpiresAt = "2016-07-11T22:14:10Z";
7683
mockPool
7784
.intercept({
78-
path: `/app/installations/${mockInstallationId}/access_tokens`,
85+
path: `${basePath}/app/installations/${mockInstallationId}/access_tokens`,
7986
method: "POST",
8087
headers: {
8188
accept: "application/vnd.github.v3+json",

Diff for: ‎tests/post-revoke-token-fail-response.test.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@ import { MockAgent, setGlobalDispatcher } from "undici";
44
// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions
55
process.env.STATE_token = "secret123";
66

7+
// inputs are set as environment variables with the prefix INPUT_
8+
// https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs
9+
process.env["INPUT_GITHUB-API-URL"] = "https://api.github.com";
10+
711
// 1 hour in the future, not expired
8-
process.env.STATE_expiresAt = new Date(Date.now() + 1000 * 60 * 60).toISOString();
12+
process.env.STATE_expiresAt = new Date(
13+
Date.now() + 1000 * 60 * 60
14+
).toISOString();
915

1016
const mockAgent = new MockAgent();
1117

Diff for: ‎tests/post-token-set.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import { MockAgent, setGlobalDispatcher } from "undici";
44
// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions
55
process.env.STATE_token = "secret123";
66

7+
// inputs are set as environment variables with the prefix INPUT_
8+
// https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs
9+
process.env["INPUT_GITHUB-API-URL"] = "https://api.github.com";
10+
711
// 1 hour in the future, not expired
812
process.env.STATE_expiresAt = new Date(Date.now() + 1000 * 60 * 60).toISOString();
913

Diff for: ‎tests/snapshots/index.js.md

+16
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,22 @@ Generated by [AVA](https://avajs.dev).
1616
private_key — 'private_key' is deprecated and will be removed in a future version. Use 'private-key' instead.␊
1717
skip_token_revoke — 'skip_token_revoke' is deprecated and will be removed in a future version. Use 'skip-token-revoke' instead.`
1818

19+
## main-custom-github-api-url.test.js
20+
21+
> stderr
22+
23+
''
24+
25+
> stdout
26+
27+
`owner and repositories set, creating token for repositories "actions/create-github-app-token" owned by "actions"␊
28+
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
29+
30+
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
31+
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
32+
33+
::set-output name=expiresAt::2016-07-11T22:14:10Z`
34+
1935
## main-missing-app-id.test.js
2036

2137
> stderr

Diff for: ‎tests/snapshots/index.js.snap

21 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)
Please sign in to comment.