Skip to content

Commit

Permalink
feat: setup PR workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
btkostner committed May 9, 2023
1 parent cad4cc2 commit f18f7d2
Show file tree
Hide file tree
Showing 12 changed files with 324 additions and 24 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: CI

on:
merge_group:
pull_request:
types:
- opened
- reopened
- synchronize
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'main'}}

jobs:
Test:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16
cache: npm

- id: cache
name: Cache node_modules
uses: actions/cache@v2
with:
path: node_modules
key: ${{ runner.os }}-node-16-nodemodules-${{ hashFiles('package-lock.json') }}

- if: steps.cache.outputs.cache-hit != 'true'
name: Install Dependencies
run: npm ci

- name: Test
run: npm run test
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dist
node_modules
test/fixtures
20 changes: 10 additions & 10 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,24 @@ inputs:
required: false
type: string
default: github-actions[bot]
dry-run:
description: Run everything but do not push changes
required: false
type: boolean
default: false
path:
description: Relative path under $GITHUB_WORKSPACE where the repository to be synced is located
required: false
type: string
pr-assignee:
description: User to assign to the newly created pull request
required: false
type: string
pr-body:
description: The body of the pull request to create
required: false
type: string
pr-enabled:
description: Whether to create a pull request on changes
required: false
type: boolean
default: true
pr-labels:
description: The labels to apply to the newly created pull request
required: false
type: string
pr-reviewers:
pr-review-users:
description: Users to assign to review the newly created pull request
required: false
type: string
Expand All @@ -57,6 +53,10 @@ inputs:
required: false
type: string
default: "chore: sync files"
pr-token:
description: GitHub token used for creating the pull request
required: false
type: string
sync-token:
description: HTTP auth url string for cloning the sync repository
required: false
Expand Down
59 changes: 59 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@actions/github": "^5.1.1",
"@actions/glob": "^0.4.0",
"@actions/io": "^1.1.3",
"handlebars": "^4.7.7",
"uuid": "^9.0.0"
},
"devDependencies": {
Expand Down
15 changes: 8 additions & 7 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ export type Config = {
commitMessage: string;
commitUserEmail: string;
commitUserName: string;
dryRun: boolean;
fullPath: string;
path: string;
prAssignee: string;
prAssignee?: string;
prBody: string;
prEnabled: boolean;
prLabels: string[];
prReviewers: string[];
prReviewUsers: string[];
prTitle: string;
syncAuth: string;
prToken?: string;
syncAuth?: string;
syncBranch: string;
syncPath: string;
syncRepository: string;
Expand All @@ -34,14 +35,14 @@ export function getConfig(): Config {
commitMessage: core.getInput("commitMessage", { required: true }),
commitUserEmail: core.getInput("commitUserEmail", { required: true }),
commitUserName: core.getInput("commitUserName", { required: true }),
dryRun: core.getBooleanInput("dryRun", { required: true }),
fullPath: join(workspace, path),
path: path,
prAssignee: core.getInput("prAssignee", { required: false }),
prBody: core.getInput("prBody", { required: false }),
prEnabled: core.getBooleanInput("prEnabled", { required: true }),
prLabels: core.getMultilineInput("prLabels", { required: false }),
prReviewers: core.getMultilineInput("prReviewers", { required: false }),
prReviewUsers: core.getMultilineInput("prReviewUsers", { required: false }),
prTitle: core.getInput("prTitle", { required: true }),
prToken: core.getInput("prToken", { required: false }),
syncAuth: core.getInput("syncAuth", { required: false }),
syncBranch: core.getInput("syncBranch", { required: true }),
syncPath: createTempPath(),
Expand Down
18 changes: 17 additions & 1 deletion src/entrypoint.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
import core from "@actions/core";

import { run } from "./index";

run();
(async () => {
try {
await run();
} catch (error) {
if (error instanceof Error) {
core.setFailed(error.message);
} else if (typeof error === "string") {
core.setFailed(error);
} else {
core.setFailed("Unknown error occurred");
}

process.exit(1);
}
})();
79 changes: 79 additions & 0 deletions src/git.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { ok } from "assert";
import core from "@actions/core";
import { exec } from "@actions/exec";
import github from "@actions/github";
import { mkdirP } from "@actions/io";

import { Config } from "./config";
Expand All @@ -11,3 +14,79 @@ export async function cloneRepository(config: Config): Promise<void> {
`git clone https://${syncAuth}@${syncRepository} --branch ${syncBranch} ${syncPath}`
);
}

export async function commitChanges(config: Config): Promise<boolean> {
await exec("git", ["config", "user.email", config.commitUserEmail], {
cwd: config.fullPath,
silent: true,
});

await exec("git", ["config", "user.name", config.commitUserName], {
cwd: config.fullPath,
silent: true,
});

await exec("git", ["checkout", "-f", "-b", config.commitBranch], {
cwd: config.fullPath,
silent: true,
});

const exitCode = await exec("git", ["commit", "-m", config.commitMessage], {
cwd: config.fullPath,
failOnStdErr: false,
ignoreReturnCode: true,
silent: true,
});

return exitCode === 0;
}

export async function createPr(config: Config): Promise<void> {
await exec("git", ["push", "-f", "-u", "origin", config.commitBranch], {
cwd: config.fullPath,
silent: true,
});

ok(process.env.GITHUB_REPOSITORY, "Expected GITHUB_REPOSITORY to be defined");
ok(config.prToken, "Expected PR_TOKEN to be defined");

const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/");
const octokit = github.getOctokit(config.prToken);

const { data: repository } = await octokit.rest.repos.get({ owner, repo });

for (const name of config.prLabels) {
core.debug(`Creating issue label ${name}`);
await octokit.rest.issues.createLabel({ owner, repo, name });
}

const res = await octokit.rest.pulls.create({
owner,
repo,
base: repository.default_branch,
body: config.prBody,
head: config.commitBranch,
maintainer_can_modify: true,
title: config.prTitle,
});

if (res.status !== 201) {
throw new Error(`Failed to create PR: ${res.status}`);
}

await octokit.rest.issues.addLabels({
owner,
repo,
issue_number: res.data.number,
labels: config.prLabels,
});

await octokit.rest.pulls.requestReviewers({
owner,
repo,
pull_number: res.data.number,
reviewers: config.prReviewUsers,
});

core.setOutput("pr-url", res.data.html_url);
}
15 changes: 12 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import core from "@actions/core";
import github from "@actions/github";

import { cloneRepository } from "./git";
import { cloneRepository, commitChanges, createPr } from "./git";
import { getConfig } from "./config";
import { templateFiles } from "./templates";
import { runScripts } from "./scripts";
Expand All @@ -13,7 +13,16 @@ export async function run() {
await runScripts(config);
await templateFiles(config);

// Commit and push changes to sync repository
if (config.prEnabled) {
const hasChanges = await commitChanges(config);

// Create PR
if (hasChanges === false) {
core.info("No changes to commit.");
return;
}

core.info("Creating PR");
await createPr(config);
core.info("Created PR");
}
}
Loading

0 comments on commit f18f7d2

Please sign in to comment.