From 80e77fd377b039131927d4983859ec47fa23b806 Mon Sep 17 00:00:00 2001 From: Xan Johnson Date: Sat, 11 Dec 2021 06:02:57 -0700 Subject: [PATCH] :sparkles: Add fork workflow functionality (#135) Implements #133 Co-authored-by: Maximilian Schiller --- README.md | 16 ++++++++++++++++ action.yml | 5 +++++ dist/index.js | 45 +++++++++++++++++++++++++++++++++++++++------ src/config.js | 5 +++++ src/git.js | 35 ++++++++++++++++++++++++++++++++--- src/index.js | 7 ++++--- 6 files changed, 101 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9072f2ce..1a304be0 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,7 @@ Here are all the inputs [repo-file-sync-action](https://github.com/BetaHuhn/repo | `DRY_RUN` | Run everything except that nothing will be pushed | **No** | false | | `SKIP_CLEANUP` | Skips removing the temporary directory. Useful for debugging | **No** | false | | `SKIP_PR` | Skips creating a Pull Request and pushes directly to the default branch | **No** | false | +| `FORK` | A Github account username. Changes will be pushed to a fork of target repos on this account. | **No** | false | ### Outputs @@ -389,6 +390,21 @@ The above example would result in a commit message that looks something like thi Change-type: patch ``` +### Fork and pull request workflow + +If you do not wish to grant this action write access to target repositories, you can specify a bot/user Github acccount that you do have access to with the `FORK` parameter. + +A fork of each target repository will be created on this account, and all changes will be pushed to a branch on the fork, instead of upstream. Pull requests will be opened from the forks to target repositories. + +Note: while you can open pull requests to target repositories without write access, some features, like applying labels, are not possible. + +```yml +uses: BetaHuhn/repo-file-sync-action@v1 +with: + GH_PAT: ${{ secrets.GH_PAT }} + FORK: file-sync-bot +``` + ### Advanced sync config Here's how I keep common files in sync across my repositories. The main repository [`github-files`](https://github.com/BetaHuhn/github-files) contains all the files I want to sync and the [repo-file-sync-action](https://github.com/BetaHuhn/repo-file-sync-action) Action which runs on every push. diff --git a/action.yml b/action.yml index b553ea60..83110fe7 100644 --- a/action.yml +++ b/action.yml @@ -79,6 +79,11 @@ inputs: description: | Specify a different prefix for the new branch in the target repo. Defaults to repo-sync/SOURCE_REPO_NAME required: false + FORK: + description: | + Specify the user account that will be used in a fork and pull-request workflow. Defaults + false. + required: false outputs: pull_request_urls: diff --git a/dist/index.js b/dist/index.js index 343e7a45..a4e6217c 100644 --- a/dist/index.js +++ b/dist/index.js @@ -17261,6 +17261,9 @@ try { BRANCH_PREFIX: getInput({ key: 'BRANCH_PREFIX', default: 'repo-sync/SOURCE_REPO_NAME' + }), + FORK: getInput({ + key: 'FORK' }) } @@ -17416,7 +17419,8 @@ const { GITHUB_REPOSITORY, OVERWRITE_EXISTING_PR, PR_BODY, - BRANCH_PREFIX + BRANCH_PREFIX, + FORK } = __nccwpck_require__(4570) const { dedent, execCmd } = __nccwpck_require__(8505) @@ -17458,6 +17462,28 @@ class Git { await this.clone() await this.setIdentity() await this.getBaseBranch() + + if (FORK) { + const forkUrl = `https://${ GITHUB_TOKEN }@github.com/${ FORK }/${ this.repo.name }.git` + await this.createFork() + await this.createRemote(forkUrl) + + } + } + + async createFork() { + core.debug(`Creating fork with OWNER: ${ this.repo.user } and REPO: ${ this.repo.name }`) + await this.github.repos.createFork({ + owner: this.repo.user, + repo: this.repo.name + }) + } + + async createRemote(forkUrl) { + return execCmd( + `git remote add fork ${ forkUrl }`, + this.workingDir + ) } async clone() { @@ -17603,6 +17629,12 @@ class Git { } async push() { + if (FORK) { + return execCmd( + `git push -u fork ${ this.prBranch } --force`, + this.workingDir + ) + } return execCmd( `git push ${ this.gitUrl } --force`, this.workingDir @@ -17614,7 +17646,7 @@ class Git { owner: this.repo.user, repo: this.repo.name, state: 'open', - head: `${ this.repo.user }:${ this.prBranch }` + head: `${ FORK ? FORK : this.repo.user }:${ this.prBranch }` }) this.existingPr = data[0] @@ -17678,7 +17710,7 @@ class Git { repo: this.repo.name, title: title === undefined ? `${ COMMIT_PREFIX } Synced file(s) with ${ GITHUB_REPOSITORY }` : title, body: body, - head: this.prBranch, + head: `${ FORK ? FORK : this.repo.user }:${ this.prBranch }`, base: this.baseBranch }) @@ -18020,7 +18052,8 @@ const { OVERWRITE_EXISTING_PR, SKIP_PR, ORIGINAL_MESSAGE, - COMMIT_AS_PR_TITLE + COMMIT_AS_PR_TITLE, + FORK } = __nccwpck_require__(4570) const run = async () => { @@ -18175,12 +18208,12 @@ const run = async () => { core.notice(`Pull Request #${ pullRequest.number } created/updated: ${ pullRequest.html_url }`) prUrls.push(pullRequest.html_url) - if (PR_LABELS !== undefined && PR_LABELS.length > 0) { + if (PR_LABELS !== undefined && PR_LABELS.length > 0 && FORK === undefined) { core.info(`Adding label(s) "${ PR_LABELS.join(', ') }" to PR`) await git.addPrLabels(PR_LABELS) } - if (ASSIGNEES !== undefined && ASSIGNEES.length > 0) { + if (ASSIGNEES !== undefined && ASSIGNEES.length > 0 && FORK === undefined) { core.info(`Adding assignee(s) "${ ASSIGNEES.join(', ') }" to PR`) await git.addPrAssignees(ASSIGNEES) } diff --git a/src/config.js b/src/config.js index cfae99e5..631c9a23 100644 --- a/src/config.js +++ b/src/config.js @@ -108,6 +108,11 @@ try { BRANCH_PREFIX: getInput({ key: 'BRANCH_PREFIX', default: 'repo-sync/SOURCE_REPO_NAME' + }), + FORK: getInput({ + key: 'FORK', + default: false, + disableable: true }) } diff --git a/src/git.js b/src/git.js index 66d5fa96..44656b89 100644 --- a/src/git.js +++ b/src/git.js @@ -16,7 +16,8 @@ const { GITHUB_REPOSITORY, OVERWRITE_EXISTING_PR, PR_BODY, - BRANCH_PREFIX + BRANCH_PREFIX, + FORK } = require('./config') const { dedent, execCmd } = require('./helpers') @@ -58,6 +59,28 @@ class Git { await this.clone() await this.setIdentity() await this.getBaseBranch() + + if (FORK) { + const forkUrl = `https://${ GITHUB_TOKEN }@github.com/${ FORK }/${ this.repo.name }.git` + await this.createFork() + await this.createRemote(forkUrl) + + } + } + + async createFork() { + core.debug(`Creating fork with OWNER: ${ this.repo.user } and REPO: ${ this.repo.name }`) + await this.github.repos.createFork({ + owner: this.repo.user, + repo: this.repo.name + }) + } + + async createRemote(forkUrl) { + return execCmd( + `git remote add fork ${ forkUrl }`, + this.workingDir + ) } async clone() { @@ -203,6 +226,12 @@ class Git { } async push() { + if (FORK) { + return execCmd( + `git push -u fork ${ this.prBranch } --force`, + this.workingDir + ) + } return execCmd( `git push ${ this.gitUrl } --force`, this.workingDir @@ -214,7 +243,7 @@ class Git { owner: this.repo.user, repo: this.repo.name, state: 'open', - head: `${ this.repo.user }:${ this.prBranch }` + head: `${ FORK ? FORK : this.repo.user }:${ this.prBranch }` }) this.existingPr = data[0] @@ -278,7 +307,7 @@ class Git { repo: this.repo.name, title: title === undefined ? `${ COMMIT_PREFIX } Synced file(s) with ${ GITHUB_REPOSITORY }` : title, body: body, - head: this.prBranch, + head: `${ FORK ? FORK : this.repo.user }:${ this.prBranch }`, base: this.baseBranch }) diff --git a/src/index.js b/src/index.js index 2067a3a8..a4ad0973 100644 --- a/src/index.js +++ b/src/index.js @@ -16,7 +16,8 @@ const { OVERWRITE_EXISTING_PR, SKIP_PR, ORIGINAL_MESSAGE, - COMMIT_AS_PR_TITLE + COMMIT_AS_PR_TITLE, + FORK } = require('./config') const run = async () => { @@ -171,12 +172,12 @@ const run = async () => { core.notice(`Pull Request #${ pullRequest.number } created/updated: ${ pullRequest.html_url }`) prUrls.push(pullRequest.html_url) - if (PR_LABELS !== undefined && PR_LABELS.length > 0) { + if (PR_LABELS !== undefined && PR_LABELS.length > 0 && FORK === undefined) { core.info(`Adding label(s) "${ PR_LABELS.join(', ') }" to PR`) await git.addPrLabels(PR_LABELS) } - if (ASSIGNEES !== undefined && ASSIGNEES.length > 0) { + if (ASSIGNEES !== undefined && ASSIGNEES.length > 0 && FORK === undefined) { core.info(`Adding assignee(s) "${ ASSIGNEES.join(', ') }" to PR`) await git.addPrAssignees(ASSIGNEES) }