Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a13b8e8f0b | |||
| 7890ff190e |
@@ -173,6 +173,12 @@ jobs:
|
||||
body: "Hello, World!"
|
||||
```
|
||||
|
||||
The `repositories` input accepts comma or newline-separated repository names. It also accepts full repository names, which is useful when passing `${{ github.repository }}`:
|
||||
|
||||
```yaml
|
||||
repositories: ${{ github.repository }},generic-submodule
|
||||
```
|
||||
|
||||
### Create a token for all repositories in another owner's installation
|
||||
|
||||
```yaml
|
||||
@@ -373,10 +379,12 @@ steps:
|
||||
|
||||
### `repositories`
|
||||
|
||||
**Optional:** Comma or newline-separated list of repositories to grant access to.
|
||||
**Optional:** Comma or newline-separated list of repositories to grant access to. Entries can be repository names, such as `repo1`, or full repository names, such as `owner/repo1`.
|
||||
|
||||
> [!NOTE]
|
||||
> If `owner` is set and `repositories` is empty, access will be scoped to all repositories in the provided repository owner's installation. If `owner` and `repositories` are empty, access will be scoped to only the current repository.
|
||||
>
|
||||
> The owner portion of any full repository name in `repositories` must match the `owner` input, or the current repository owner if `owner` is unset.
|
||||
|
||||
### `enterprise`
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ inputs:
|
||||
description: "The owner of the GitHub App installation (defaults to current repository owner)"
|
||||
required: false
|
||||
repositories:
|
||||
description: "Comma or newline-separated list of repositories to install the GitHub App on (defaults to current repository if owner is unset)"
|
||||
description: "Comma or newline-separated list of repository names or owner/repository names to install the GitHub App on (defaults to current repository if owner is unset)"
|
||||
required: false
|
||||
enterprise:
|
||||
description: "The slug of the enterprise account where the GitHub App is installed (cannot be used with 'owner' or 'repositories')"
|
||||
|
||||
+45
-7
@@ -86,29 +86,67 @@ function resolveInstallationTarget(enterprise, owner, repositories, core) {
|
||||
return { type: "owner", owner };
|
||||
}
|
||||
|
||||
const parsedOwner = owner || String(process.env.GITHUB_REPOSITORY_OWNER);
|
||||
const target = normalizeRepositoryTarget(owner, repositories);
|
||||
|
||||
if (!owner) {
|
||||
core.info(
|
||||
`No 'owner' input provided. Using default owner '${parsedOwner}' to create token for the following repositories:${repositories
|
||||
.map((repo) => `\n- ${parsedOwner}/${repo}`)
|
||||
`No 'owner' input provided. Using default owner '${target.owner}' to create token for the following repositories:${target.repositories
|
||||
.map((repo) => `\n- ${target.owner}/${repo}`)
|
||||
.join("")}`
|
||||
);
|
||||
} else {
|
||||
core.info(
|
||||
`Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:${repositories
|
||||
.map((repo) => `\n- ${parsedOwner}/${repo}`)
|
||||
`Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:${target.repositories
|
||||
.map((repo) => `\n- ${target.owner}/${repo}`)
|
||||
.join("")}`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
type: "repository",
|
||||
owner: parsedOwner,
|
||||
repositories,
|
||||
owner: target.owner,
|
||||
repositories: target.repositories,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeRepositoryTarget(owner, repositories) {
|
||||
const parsedOwner = owner || String(process.env.GITHUB_REPOSITORY_OWNER);
|
||||
const parsedRepositories = repositories.map(parseRepositoryInput);
|
||||
|
||||
const mismatchedRepository = parsedRepositories.find(
|
||||
(repository) =>
|
||||
repository.owner &&
|
||||
repository.owner.toLowerCase() !== parsedOwner.toLowerCase()
|
||||
);
|
||||
|
||||
if (mismatchedRepository) {
|
||||
throw new Error(
|
||||
`Repository '${mismatchedRepository.input}' includes owner '${mismatchedRepository.owner}', which does not match the resolved owner '${parsedOwner}'.`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
owner: parsedOwner,
|
||||
repositories: parsedRepositories.map((repository) => repository.name),
|
||||
};
|
||||
}
|
||||
|
||||
function parseRepositoryInput(input) {
|
||||
const parts = input.split("/");
|
||||
|
||||
if (parts.length === 1 && parts[0]) {
|
||||
return { input, owner: "", name: parts[0] };
|
||||
}
|
||||
|
||||
if (parts.length === 2 && parts[0] && parts[1]) {
|
||||
return { input, owner: parts[0], name: parts[1] };
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Invalid repository '${input}'. Expected 'repository' or 'owner/repository'.`
|
||||
);
|
||||
}
|
||||
|
||||
function getTokenRetryDescription(target) {
|
||||
switch (target.type) {
|
||||
case "enterprise":
|
||||
|
||||
@@ -296,6 +296,42 @@ POST /app/installations/123456/access_tokens
|
||||
{"repositories":["failed-repo"]}
|
||||
`;
|
||||
|
||||
exports[`main-token-get-owner-set-repo-full-name.test.js > stdout 1`] = `
|
||||
Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:
|
||||
- actions/create-github-app-token
|
||||
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a
|
||||
|
||||
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a
|
||||
|
||||
::set-output name=installation-id::123456
|
||||
|
||||
::set-output name=app-slug::github-actions
|
||||
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a
|
||||
::save-state name=expiresAt::2016-07-11T22:14:10Z
|
||||
--- REQUESTS ---
|
||||
GET /repos/actions/create-github-app-token/installation
|
||||
POST /app/installations/123456/access_tokens
|
||||
{"repositories":["create-github-app-token"]}
|
||||
`;
|
||||
|
||||
exports[`main-token-get-owner-set-repo-invalid-format.test.js > stderr 1`] = `
|
||||
Error: Invalid repository 'octocat/hello-world/extra'. Expected 'repository' or 'owner/repository'.
|
||||
at parseRepositoryInput (file://<cwd>/lib/main.js:<line>:<column>)
|
||||
at Array.map (<anonymous>)
|
||||
at normalizeRepositoryTarget (file://<cwd>/lib/main.js:<line>:<column>)
|
||||
at resolveInstallationTarget (file://<cwd>/lib/main.js:<line>:<column>)
|
||||
at main (file://<cwd>/lib/main.js:<line>:<column>)
|
||||
at run (file://<cwd>/main.js:<line>:<column>)
|
||||
at file://<cwd>/main.js:<line>:<column>
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:<line>:<column>)
|
||||
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:<line>:<column>)
|
||||
at async file://<cwd>/tests/main-token-get-owner-set-repo-invalid-format.test.js:<line>:<column>
|
||||
`;
|
||||
|
||||
exports[`main-token-get-owner-set-repo-invalid-format.test.js > stdout 1`] = `
|
||||
::error::Invalid repository 'octocat/hello-world/extra'. Expected 'repository' or 'owner/repository'.
|
||||
`;
|
||||
|
||||
exports[`main-token-get-owner-set-repo-network-error.test.js > stdout 1`] = `
|
||||
Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:
|
||||
- actions/network-repo
|
||||
@@ -316,6 +352,22 @@ POST /app/installations/123456/access_tokens
|
||||
{"repositories":["network-repo"]}
|
||||
`;
|
||||
|
||||
exports[`main-token-get-owner-set-repo-owner-mismatch.test.js > stderr 1`] = `
|
||||
Error: Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'.
|
||||
at normalizeRepositoryTarget (file://<cwd>/lib/main.js:<line>:<column>)
|
||||
at resolveInstallationTarget (file://<cwd>/lib/main.js:<line>:<column>)
|
||||
at main (file://<cwd>/lib/main.js:<line>:<column>)
|
||||
at run (file://<cwd>/main.js:<line>:<column>)
|
||||
at file://<cwd>/main.js:<line>:<column>
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:<line>:<column>)
|
||||
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:<line>:<column>)
|
||||
at async file://<cwd>/tests/main-token-get-owner-set-repo-owner-mismatch.test.js:<line>:<column>
|
||||
`;
|
||||
|
||||
exports[`main-token-get-owner-set-repo-owner-mismatch.test.js > stdout 1`] = `
|
||||
::error::Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'.
|
||||
`;
|
||||
|
||||
exports[`main-token-get-owner-set-repo-set-to-many-newline.test.js > stdout 1`] = `
|
||||
Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:
|
||||
- actions/create-github-app-token
|
||||
@@ -391,6 +443,41 @@ POST /app/installations/123456/access_tokens
|
||||
null
|
||||
`;
|
||||
|
||||
exports[`main-token-get-owner-unset-repo-full-name-and-bare.test.js > stdout 1`] = `
|
||||
No 'owner' input provided. Using default owner 'actions' to create token for the following repositories:
|
||||
- actions/create-github-app-token
|
||||
- actions/toolkit
|
||||
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a
|
||||
|
||||
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a
|
||||
|
||||
::set-output name=installation-id::123456
|
||||
|
||||
::set-output name=app-slug::github-actions
|
||||
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a
|
||||
::save-state name=expiresAt::2016-07-11T22:14:10Z
|
||||
--- REQUESTS ---
|
||||
GET /repos/actions/create-github-app-token/installation
|
||||
POST /app/installations/123456/access_tokens
|
||||
{"repositories":["create-github-app-token","toolkit"]}
|
||||
`;
|
||||
|
||||
exports[`main-token-get-owner-unset-repo-owner-mismatch.test.js > stderr 1`] = `
|
||||
Error: Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'.
|
||||
at normalizeRepositoryTarget (file://<cwd>/lib/main.js:<line>:<column>)
|
||||
at resolveInstallationTarget (file://<cwd>/lib/main.js:<line>:<column>)
|
||||
at main (file://<cwd>/lib/main.js:<line>:<column>)
|
||||
at run (file://<cwd>/main.js:<line>:<column>)
|
||||
at file://<cwd>/main.js:<line>:<column>
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:<line>:<column>)
|
||||
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:<line>:<column>)
|
||||
at async file://<cwd>/tests/main-token-get-owner-unset-repo-owner-mismatch.test.js:<line>:<column>
|
||||
`;
|
||||
|
||||
exports[`main-token-get-owner-unset-repo-owner-mismatch.test.js > stdout 1`] = `
|
||||
::error::Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'.
|
||||
`;
|
||||
|
||||
exports[`main-token-get-owner-unset-repo-set.test.js > stdout 1`] = `
|
||||
No 'owner' input provided. Using default owner 'actions' to create token for the following repositories:
|
||||
- actions/create-github-app-token
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { test } from "./main.js";
|
||||
|
||||
// Verify `main` successfully obtains a token when the `owner` and `repositories` inputs are set, and `repositories` contains a full repository name.
|
||||
await test(() => {
|
||||
process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER;
|
||||
process.env.INPUT_REPOSITORIES = process.env.GITHUB_REPOSITORY;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { DEFAULT_ENV } from "./main.js";
|
||||
|
||||
// Verify `main` exits with an error when a repository entry is neither a repository name nor an owner/repository name.
|
||||
for (const [key, value] of Object.entries(DEFAULT_ENV)) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
|
||||
process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER;
|
||||
process.env.INPUT_REPOSITORIES = "octocat/hello-world/extra";
|
||||
|
||||
const { default: promise } = await import("../main.js");
|
||||
await promise;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { DEFAULT_ENV } from "./main.js";
|
||||
|
||||
// Verify `main` exits with an error when a full repository name does not match the `owner` input.
|
||||
for (const [key, value] of Object.entries(DEFAULT_ENV)) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
|
||||
process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER;
|
||||
process.env.INPUT_REPOSITORIES = "octocat/hello-world";
|
||||
|
||||
const { default: promise } = await import("../main.js");
|
||||
await promise;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { test } from "./main.js";
|
||||
|
||||
// Verify `main` successfully obtains a token when `owner` is omitted and `repositories` mixes a full repository name with bare repository names.
|
||||
await test(() => {
|
||||
delete process.env.INPUT_OWNER;
|
||||
process.env.INPUT_REPOSITORIES = `${process.env.GITHUB_REPOSITORY},toolkit`;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { DEFAULT_ENV } from "./main.js";
|
||||
|
||||
// Verify `main` exits with an error when a full repository name does not match the default owner.
|
||||
for (const [key, value] of Object.entries(DEFAULT_ENV)) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
|
||||
delete process.env.INPUT_OWNER;
|
||||
process.env.INPUT_REPOSITORIES = "octocat/hello-world";
|
||||
|
||||
const { default: promise } = await import("../main.js");
|
||||
await promise;
|
||||
|
||||
Reference in New Issue
Block a user