Skip to content

Commit

Permalink
feat: support hardcoded repositories (#10)
Browse files Browse the repository at this point in the history
This enables the action to skp the list repositoires for authenticated users API call which may fail for certain token types.

* build: include index.js
  • Loading branch information
jpoehnelt authored Apr 28, 2020
1 parent 4ca3ee1 commit 7004d56
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 21 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ A Github Action that can sync secrets from one repository to many others. This a

### `repositories`

**Required** New line deliminated regex expressions to select repositories. Repositires are limited to those in whcich the token user is an owner or collaborator.
**Required** New line deliminated regex expressions to select repositories. Repositires are limited to those in whcich the token user is an owner or collaborator. Set `repositories_list_regex` to `False` to use a hardcoded list of repositories.

### `repositories_list_regex`
If this value is `true` (default), the action will find all
repositories available to the token user and filter based upon the regex
provided. If it is false, it is expected that `repositories` will be an a
new line deliminated list in the form of org/name.

### `secrets`

Expand Down
3 changes: 3 additions & 0 deletions __tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ function clearInputs() {
describe("getConfig", () => {
const SECRETS = ["FOO.*", "^BAR$"];
const REPOSITORIES = ["google/baz.*", "^google/foo$"];
const REPOSITORIES_LIST_REGEX = true;
const GITHUB_TOKEN = "token";
const DRY_RUN = false;

const inputs = {
INPUT_GITHUB_TOKEN: GITHUB_TOKEN,
INPUT_SECRETS: SECRETS.join("\n"),
INPUT_REPOSITORIES: REPOSITORIES.join("\n"),
INPUT_REPOSITORIES_LIST_REGEX: String(REPOSITORIES_LIST_REGEX),
INPUT_DRY_RUN: String(DRY_RUN)
};

Expand All @@ -56,6 +58,7 @@ describe("getConfig", () => {
GITHUB_TOKEN,
SECRETS,
REPOSITORIES,
REPOSITORIES_LIST_REGEX,
DRY_RUN
});
});
Expand Down
32 changes: 32 additions & 0 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,40 @@ test("run should succeed with a repo and secret", async () => {
GITHUB_TOKEN: "token",
SECRETS: ["BAZ"],
REPOSITORIES: [".*"],
REPOSITORIES_LIST_REGEX: true,
DRY_RUN: false
});
await run();

expect(github.listAllMatchingRepos as jest.Mock).toBeCalledTimes(1);
expect((github.setSecretsForRepo as jest.Mock).mock.calls[0][2]).toEqual(
fixture[0].response
);

expect(process.exitCode).toBe(undefined);
});

test("run should succeed with a repo and secret with repository_list_regex as false", async () => {
(github.setSecretsForRepo as jest.Mock) = jest
.fn()
.mockImplementation(async () => null);

(secrets.getSecrets as jest.Mock) = jest.fn().mockReturnValue({
BAZ: "bar"
});

(config.getConfig as jest.Mock) = jest.fn().mockReturnValue({
GITHUB_TOKEN: "token",
SECRETS: ["BAZ"],
REPOSITORIES: [fixture[0].response.full_name],
REPOSITORIES_LIST_REGEX: false,
DRY_RUN: false
});
await run();

expect((github.setSecretsForRepo as jest.Mock).mock.calls[0][2]).toEqual({
full_name: fixture[0].response.full_name
});

expect(process.exitCode).toBe(undefined);
});
15 changes: 12 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,19 @@ inputs:
required: true
repositories:
description: |
New line deliminated regex expressions to select repositories.
Repositires are limited to those in whcich the token user is an owner
or collaborator.
New line deliminated regex expressions to select repositories. Repositires
are limited to those in which the token user is an owner or collaborator.
Set `REPOSITORIES_LIST_REGEX` to `False` to use a hardcoded list of
repositories.
required: true
repositories_list_regex:
default: "true"
description: |
If this value is `true`(default), the action will find all repositories
available to the token user and filter based upon the regex provided. If
it is false, it is expected that `REPOSITORIES` will be an a new line
deliminated list in the form of org/name.
required: false
secrets:
description: |
New line deliminated regex expressions to select values from `process.env`.
Expand Down
24 changes: 18 additions & 6 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2119,20 +2119,30 @@ function run() {
const octokit = github_1.DefaultOctokit({
auth: config.GITHUB_TOKEN
});
const repos = yield github_1.listAllMatchingRepos({
patterns: config.REPOSITORIES,
octokit
});
let repos;
if (config.REPOSITORIES_LIST_REGEX) {
repos = yield github_1.listAllMatchingRepos({
patterns: config.REPOSITORIES,
octokit
});
}
else {
repos = config.REPOSITORIES.map(s => {
return {
full_name: s
};
});
}
/* istanbul ignore next */
if (repos.length === 0) {
const repoPatternString = config.REPOSITORIES.join(", ");
core.setFailed(`Repos: No matches with "${repoPatternString}". Check your token and regex.`);
return;
}
// eslint-disable-next-line @typescript-eslint/promise-function-async
const repoNames = repos.map(r => r.full_name);
core.info(JSON.stringify({
REPOSITORIES: config.REPOSITORIES,
REPOSITORIES_LIST_REGEX: config.REPOSITORIES_LIST_REGEX,
SECRETS: config.SECRETS,
DRY_RUN: config.DRY_RUN,
FOUND_REPOS: repoNames,
Expand Down Expand Up @@ -5495,6 +5505,9 @@ function getConfig() {
GITHUB_TOKEN: core.getInput("GITHUB_TOKEN", { required: true }),
SECRETS: core.getInput("SECRETS", { required: true }).split("\n"),
REPOSITORIES: core.getInput("REPOSITORIES", { required: true }).split("\n"),
REPOSITORIES_LIST_REGEX: ["1", "true"].includes(core
.getInput("REPOSITORIES_LIST_REGEX", { required: false })
.toLowerCase()),
DRY_RUN: ["1", "true"].includes(core.getInput("DRY_RUN", { required: false }).toLowerCase())
};
if (config.DRY_RUN) {
Expand Down Expand Up @@ -7428,7 +7441,6 @@ const defaultOptions = {
onAbuseLimit
}
};
// eslint-disable-next-line @typescript-eslint/promise-function-async
function DefaultOctokit(_a) {
var options = __rest(_a, []);
return new RetryOctokit(Object.assign(Object.assign({}, defaultOptions), options));
Expand Down
6 changes: 6 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface Config {
GITHUB_TOKEN: string;
SECRETS: string[];
REPOSITORIES: string[];
REPOSITORIES_LIST_REGEX: boolean;
DRY_RUN: boolean;
}

Expand All @@ -28,6 +29,11 @@ export function getConfig(): Config {
GITHUB_TOKEN: core.getInput("GITHUB_TOKEN", { required: true }),
SECRETS: core.getInput("SECRETS", { required: true }).split("\n"),
REPOSITORIES: core.getInput("REPOSITORIES", { required: true }).split("\n"),
REPOSITORIES_LIST_REGEX: ["1", "true"].includes(
core
.getInput("REPOSITORIES_LIST_REGEX", { required: false })
.toLowerCase()
),
DRY_RUN: ["1", "true"].includes(
core.getInput("DRY_RUN", { required: false }).toLowerCase()
)
Expand Down
18 changes: 12 additions & 6 deletions src/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import { Octokit } from "@octokit/rest";
import { encrypt } from "./utils";
import { retry } from "@octokit/plugin-retry";

export interface Repository {
full_name: string;
}

const RetryOctokit = Octokit.plugin(retry);

/* istanbul ignore next */
Expand Down Expand Up @@ -47,7 +51,6 @@ const defaultOptions = {
}
};

// eslint-disable-next-line @typescript-eslint/promise-function-async
export function DefaultOctokit({ ...options }): any {
return new RetryOctokit({ ...defaultOptions, ...options });
}
Expand All @@ -62,7 +65,7 @@ export async function listAllMatchingRepos({
octokit: any;
affiliation?: string;
pageSize?: number;
}): Promise<any[]> {
}): Promise<Repository[]> {
const repos = await listAllReposForAuthenticatedUser({
octokit,
affiliation,
Expand All @@ -84,8 +87,8 @@ export async function listAllReposForAuthenticatedUser({
octokit: any;
affiliation: string;
pageSize: number;
}): Promise<any[]> {
const repos: any[] = [];
}): Promise<Repository[]> {
const repos: Repository[] = [];

for (let page = 1; ; page++) {
const response = await octokit.repos.listForAuthenticatedUser({
Expand All @@ -102,7 +105,10 @@ export async function listAllReposForAuthenticatedUser({
return repos;
}

export function filterReposByPatterns(repos: any[], patterns: string[]): any[] {
export function filterReposByPatterns(
repos: Repository[],
patterns: string[]
): Repository[] {
const regexPatterns = patterns.map(s => new RegExp(s));

return repos.filter(
Expand All @@ -113,7 +119,7 @@ export function filterReposByPatterns(repos: any[], patterns: string[]): any[] {
export async function setSecretsForRepo(
octokit: any,
secrets: { [key: string]: string },
repo: any,
repo: Repository,
dry_run: boolean
): Promise<void> {
const [owner, name] = repo.full_name.split("/");
Expand Down
20 changes: 15 additions & 5 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import * as core from "@actions/core";

import {
DefaultOctokit,
Repository,
listAllMatchingRepos,
setSecretsForRepo
} from "./github";
Expand All @@ -40,10 +41,19 @@ export async function run(): Promise<void> {
auth: config.GITHUB_TOKEN
});

const repos = await listAllMatchingRepos({
patterns: config.REPOSITORIES,
octokit
});
let repos: Repository[];
if (config.REPOSITORIES_LIST_REGEX) {
repos = await listAllMatchingRepos({
patterns: config.REPOSITORIES,
octokit
});
} else {
repos = config.REPOSITORIES.map(s => {
return {
full_name: s
};
});
}

/* istanbul ignore next */
if (repos.length === 0) {
Expand All @@ -54,13 +64,13 @@ export async function run(): Promise<void> {
return;
}

// eslint-disable-next-line @typescript-eslint/promise-function-async
const repoNames = repos.map(r => r.full_name);

core.info(
JSON.stringify(
{
REPOSITORIES: config.REPOSITORIES,
REPOSITORIES_LIST_REGEX: config.REPOSITORIES_LIST_REGEX,
SECRETS: config.SECRETS,
DRY_RUN: config.DRY_RUN,
FOUND_REPOS: repoNames,
Expand Down

0 comments on commit 7004d56

Please sign in to comment.