Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve handling of repositories input #169

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,9 @@ jobs:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: "repo1,repo2"
repositories: |
repo1
repo2
- uses: peter-evans/create-or-update-comment@v3
with:
token: ${{ steps.app-token.outputs.token }}
Expand Down Expand Up @@ -302,7 +304,7 @@ steps:

### `repositories`

**Optional:** Comma-separated list of repositories to grant access to.
**Optional:** Comma or newline-separated list of repositories to grant access to.

> [!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.
Expand Down
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ inputs:
description: "The owner of the GitHub App installation (defaults to current repository owner)"
required: false
repositories:
description: "Repositories to install the GitHub App on (defaults to current repository if owner is unset)"
description: "Comma or newline-separated list of repositories to install the GitHub App on (defaults to current repository if owner is unset)"
required: false
skip-token-revoke:
description: "If truthy, the token will not be revoked when the current job is complete"
Expand Down
30 changes: 16 additions & 14 deletions dist/main.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -39700,33 +39700,35 @@ async function pRetry(input, options) {
// lib/main.js
async function main(appId2, privateKey2, owner2, repositories2, core3, createAppAuth2, request2, skipTokenRevoke2) {
let parsedOwner = "";
let parsedRepositoryNames = "";
if (!owner2 && !repositories2) {
[parsedOwner, parsedRepositoryNames] = String(
let parsedRepositoryNames = [];
if (!owner2 && repositories2.length === 0) {
const [owner3, repo] = String(
process.env.GITHUB_REPOSITORY
).split("/");
parsedOwner = owner3;
parsedRepositoryNames = [repo];
core3.info(
`owner and repositories not set, creating token for the current repository ("${parsedRepositoryNames}")`
`owner and repositories not set, creating token for the current repository ("${repo}")`
);
}
if (owner2 && !repositories2) {
if (owner2 && repositories2.length === 0) {
parsedOwner = owner2;
core3.info(
`repositories not set, creating token for all repositories for given owner "${owner2}"`
);
}
if (!owner2 && repositories2) {
if (!owner2 && repositories2.length > 0) {
parsedOwner = String(process.env.GITHUB_REPOSITORY_OWNER);
parsedRepositoryNames = repositories2;
core3.info(
`owner not set, creating owner for given repositories "${repositories2}" in current owner ("${parsedOwner}")`
`owner not set, creating owner for given repositories "${repositories2.join(",")}" in current owner ("${parsedOwner}")`
);
}
if (owner2 && repositories2) {
if (owner2 && repositories2.length > 0) {
parsedOwner = owner2;
parsedRepositoryNames = repositories2;
core3.info(
`owner and repositories set, creating token for repositories "${repositories2}" owned by "${owner2}"`
`owner and repositories set, creating token for repositories "${repositories2.join(",")}" owned by "${owner2}"`
);
}
const auth5 = createAppAuth2({
Expand All @@ -39735,11 +39737,11 @@ async function main(appId2, privateKey2, owner2, repositories2, core3, createApp
request: request2
});
let authentication, installationId, appSlug;
if (parsedRepositoryNames) {
if (parsedRepositoryNames.length > 0) {
({ authentication, installationId, appSlug } = await pRetry(() => getTokenFromRepository(request2, auth5, parsedOwner, parsedRepositoryNames), {
onFailedAttempt: (error) => {
core3.info(
`Failed to create token for "${parsedRepositoryNames}" (attempt ${error.attemptNumber}): ${error.message}`
`Failed to create token for "${parsedRepositoryNames.join(",")}" (attempt ${error.attemptNumber}): ${error.message}`
);
},
retries: 3
Expand Down Expand Up @@ -39789,15 +39791,15 @@ async function getTokenFromOwner(request2, auth5, parsedOwner) {
async function getTokenFromRepository(request2, auth5, parsedOwner, parsedRepositoryNames) {
const response = await request2("GET /repos/{owner}/{repo}/installation", {
owner: parsedOwner,
repo: parsedRepositoryNames.split(",")[0],
repo: parsedRepositoryNames[0],
request: {
hook: auth5.hook
}
});
const authentication = await auth5({
type: "installation",
installationId: response.data.id,
repositoryNames: parsedRepositoryNames.split(",")
repositoryNames: parsedRepositoryNames
});
const installationId = response.data.id;
const appSlug = response.data["app_slug"];
Expand Down Expand Up @@ -39847,7 +39849,7 @@ if (!privateKey) {
throw new Error("Input required and not supplied: private-key");
}
var owner = import_core2.default.getInput("owner");
var repositories = import_core2.default.getInput("repositories");
var repositories = import_core2.default.getInput("repositories").split(/[\n,]+/).map((s) => s.trim()).filter((x) => x !== "");
var skipTokenRevoke = Boolean(
import_core2.default.getInput("skip-token-revoke") || import_core2.default.getInput("skip_token_revoke")
);
Expand Down
32 changes: 17 additions & 15 deletions lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import pRetry from "p-retry";
* @param {string} appId
* @param {string} privateKey
* @param {string} owner
* @param {string} repositories
* @param {string[]} repositories
* @param {import("@actions/core")} core
* @param {import("@octokit/auth-app").createAppAuth} createAppAuth
* @param {import("@octokit/request").request} request
Expand All @@ -22,21 +22,23 @@ export async function main(
skipTokenRevoke
) {
let parsedOwner = "";
let parsedRepositoryNames = "";
let parsedRepositoryNames = [];

// If neither owner nor repositories are set, default to current repository
if (!owner && !repositories) {
[parsedOwner, parsedRepositoryNames] = String(
if (!owner && repositories.length === 0) {
const [owner, repo] = String(
process.env.GITHUB_REPOSITORY
).split("/");
parsedOwner = owner;
parsedRepositoryNames = [repo];

core.info(
`owner and repositories not set, creating token for the current repository ("${parsedRepositoryNames}")`
`owner and repositories not set, creating token for the current repository ("${repo}")`
);
}

// If only an owner is set, default to all repositories from that owner
if (owner && !repositories) {
if (owner && repositories.length === 0) {
parsedOwner = owner;

core.info(
Expand All @@ -45,22 +47,22 @@ export async function main(
}

// If repositories are set, but no owner, default to `GITHUB_REPOSITORY_OWNER`
if (!owner && repositories) {
if (!owner && repositories.length > 0) {
parsedOwner = String(process.env.GITHUB_REPOSITORY_OWNER);
parsedRepositoryNames = repositories;

core.info(
`owner not set, creating owner for given repositories "${repositories}" in current owner ("${parsedOwner}")`
`owner not set, creating owner for given repositories "${repositories.join(',')}" in current owner ("${parsedOwner}")`
);
}

// If both owner and repositories are set, use those values
if (owner && repositories) {
if (owner && repositories.length > 0) {
parsedOwner = owner;
parsedRepositoryNames = repositories;

core.info(
`owner and repositories set, creating token for repositories "${repositories}" owned by "${owner}"`
`owner and repositories set, creating token for repositories "${repositories.join(',')}" owned by "${owner}"`
);
}

Expand All @@ -73,11 +75,11 @@ export async function main(
let authentication, installationId, appSlug;
// If at least one repository is set, get installation ID from that repository

if (parsedRepositoryNames) {
if (parsedRepositoryNames.length > 0) {
({ authentication, installationId, appSlug } = await pRetry(() => getTokenFromRepository(request, auth, parsedOwner, parsedRepositoryNames), {
onFailedAttempt: (error) => {
core.info(
`Failed to create token for "${parsedRepositoryNames}" (attempt ${error.attemptNumber}): ${error.message}`
`Failed to create token for "${parsedRepositoryNames.join(',')}" (attempt ${error.attemptNumber}): ${error.message}`
);
},
retries: 3,
Expand Down Expand Up @@ -144,7 +146,7 @@ async function getTokenFromRepository(request, auth, parsedOwner, parsedReposito
// https://docs.github.com/rest/apps/apps?apiVersion=2022-11-28#get-a-repository-installation-for-the-authenticated-app
const response = await request("GET /repos/{owner}/{repo}/installation", {
owner: parsedOwner,
repo: parsedRepositoryNames.split(",")[0],
repo: parsedRepositoryNames[0],
request: {
hook: auth.hook,
},
Expand All @@ -154,11 +156,11 @@ async function getTokenFromRepository(request, auth, parsedOwner, parsedReposito
const authentication = await auth({
type: "installation",
installationId: response.data.id,
repositoryNames: parsedRepositoryNames.split(","),
repositoryNames: parsedRepositoryNames,
});

const installationId = response.data.id;
const appSlug = response.data['app_slug'];

return { authentication, installationId, appSlug };
}
}
5 changes: 4 additions & 1 deletion main.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ if (!privateKey) {
throw new Error("Input required and not supplied: private-key");
}
const owner = core.getInput("owner");
const repositories = core.getInput("repositories");
const repositories = core.getInput("repositories")
.split(/[\n,]+/)
.map(s => s.trim())
.filter(x => x !== '');

const skipTokenRevoke = Boolean(
core.getInput("skip-token-revoke") || core.getInput("skip_token_revoke")
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { test } from "./main.js";

// Verify `main` successfully obtains a token when the `owner` and `repositories` inputs are set (and the latter is a list of repos).
await test(() => {
process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER;
const currentRepoName = process.env.GITHUB_REPOSITORY.split("/")[1];
// Intentional unnecessary whitespace to test parsing to array
process.env.INPUT_REPOSITORIES = `\n ${currentRepoName}\ntoolkit \n\n checkout \n`;
});
3 changes: 2 additions & 1 deletion tests/main-token-get-owner-set-repo-set-to-many.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ import { test } from "./main.js";
await test(() => {
process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER;
const currentRepoName = process.env.GITHUB_REPOSITORY.split("/")[1];
process.env.INPUT_REPOSITORIES = `${currentRepoName},toolkit`;
// Intentional unnecessary whitespace to test parsing to array
process.env.INPUT_REPOSITORIES = ` ${currentRepoName}, toolkit ,checkout`;
});
21 changes: 20 additions & 1 deletion tests/snapshots/index.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,25 @@ Generated by [AVA](https://avajs.dev).
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::save-state name=expiresAt::2016-07-11T22:14:10Z`

## main-token-get-owner-set-repo-set-to-many-newline.test.js

> stderr

''

> stdout

`owner and repositories set, creating token for repositories "create-github-app-token,toolkit,checkout" owned by "actions"␊
::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`

## main-token-get-owner-set-repo-set-to-many.test.js

> stderr
Expand All @@ -142,7 +161,7 @@ Generated by [AVA](https://avajs.dev).

> stdout

`owner and repositories set, creating token for repositories "create-github-app-token,toolkit" owned by "actions"␊
`owner and repositories set, creating token for repositories "create-github-app-token,toolkit,checkout" owned by "actions"␊
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
Expand Down
Binary file modified tests/snapshots/index.js.snap
Binary file not shown.