diff --git a/.github/workflows/feature-pr.yml b/.github/workflows/feature-pr.yml new file mode 100644 index 0000000..19fc951 --- /dev/null +++ b/.github/workflows/feature-pr.yml @@ -0,0 +1,27 @@ +name: feature + +on: + push: + workflow_dispatch: + +jobs: + feature: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [16.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npm ci + - run: npm run build --if-present + - run: node bin.js feature-pr --verbose --target main --source next + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index ac67872..3a1bc8c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -54,6 +54,16 @@ "args": ["merge", "--commit", "--target", "main", "--source", "next", "--verbose", "--refresh-clean"], "program": "${workspaceFolder}/bin.js" }, + { + "type": "pwa-node", + "request": "launch", + "name": "featurePR", + "skipFiles": [ + "/**" + ], + "args": ["feature-pr"], + "program": "${workspaceFolder}/bin.js" + }, { "type": "pwa-node", "request": "launch", diff --git a/README.md b/README.md index ab3e8cf..c341100 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ If `GITHUB_REPOSITORY` is not provided, pr-release will exit. Even if you are r If `GITHUB_SHA` is not specified, `pr-release` will make an API call to identify the relevant sha for the given command. If the relevant sha is not inferrable, `pr-release` will exit with a non zero code. +`GITHUB_REF` is used to identify if there is already a pull request for the current branch. This is especially useful for automatically generating feature branches on push. + ### How do I do concurrent release channels? Have a target branch for each channel e.g. `v1` and a release candidate branch like `v1-next`: diff --git a/lib/index.js b/lib/index.js index 6daebbd..eddde65 100644 --- a/lib/index.js +++ b/lib/index.js @@ -139,6 +139,13 @@ async function preflight(){ } else { if( !process.env.GITHUB_REPOSITORY ) throw new Error('GITHUB_REPOSITORY is required') if( !process.env.GITHUB_TOKEN ) throw new Error('GITHUB_TOKEN is required') + if( !process.env.GITHUB_REF ) { + try { + process.env.GITHUB_REF = (await $`git branch --show-current`).stdout.trim() + } catch (e) { + throw new Error('GITHUB_REF is required') + } + } octokit = new Octokit({ auth: process.env.GITHUB_TOKEN ,throttle: throttleOptions @@ -922,6 +929,79 @@ async function changelog(options){ } } +async function featurePR(){ + // Ensure there is not a PR for the current branch + // Ensure the current branch is targeting $source + // If so, create a PR automatically + // If drafts are available, use them + + + let [owner,repo] = process.env.GITHUB_REPOSITORY.split('/') + // let owner = 'harth-systems', repo = 'odin'; + + if( [source, target].includes(process.env.GITHUB_REF) ){ + return; + } + + let useDraft; { + + let repo2 = await octokit.rest.repos.get({ + owner, repo + }) + repo2 = repo2.data + + let user = await octokit.rest.users.getByUsername({ + username: owner + }) + user = user.data + + let org, plan; { + if(user.type == 'Organization'){ + org = await octokit.rest.orgs.get({ + org: owner + }) + org = org.data + plan = org.plan + } + } + + useDraft = + !repo2.private || plan.name == 'team' + } + + let [existing] = + await octokit.paginate(octokit.rest.search.issuesAndPullRequests, { + q: `head:${process.env.GITHUB_REF} base:${source} is:pr is:open repo:${owner}/${repo}` + ,sort: 'updated' + ,order: 'desc' + ,per_page: 1 + ,page: 1 + }) + useDraft; + + let commitSubject; { + try { + commitSubject = (await $`git show -s --format=%s HEAD`) + .stdout.trim() + } catch (e) { + commitSubject = process.env.GITHUB_REF + } + } + + if(!existing) { + await octokit.rest.pulls.create({ + owner + ,repo + ,title: commitSubject + ,head: process.env.GITHUB_REF + ,base: source + ,draft: useDraft + }) + } + + return; +} + let help= chalk`{green pr-release} @@ -953,6 +1033,13 @@ subcommands: {magenta actions-yml} Scaffold Github actions yml files + + {magenta feature-pr} + + Generate a feature-pr for the current branch that targets + the source branch if the push event is not for the target + or source branch. + ` let [subcommand] = argv._ @@ -963,6 +1050,7 @@ let subcommands = { , 'actions-yml': actionsYML , 'extract-changelog': extractChangelog , changelog + , 'feature-pr': featurePR } let preflights = { @@ -970,6 +1058,7 @@ let preflights = { , merge , 'extract-changelog': extractChangelog , changelog + , 'feature-pr': featurePR } diff --git a/templates/feature-pr.yml b/templates/feature-pr.yml new file mode 100644 index 0000000..b99e069 --- /dev/null +++ b/templates/feature-pr.yml @@ -0,0 +1,27 @@ +name: feature + +on: + push: + workflow_dispatch: + +jobs: + feature: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [16.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npm ci + - run: npm run build --if-present + - run: node bin.js feature-branch --verbose --target $target --source $source + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} \ No newline at end of file