Compare commits

...

15 Commits

Author SHA1 Message Date
github-actions[bot]
671dc9c9e0 build: update distribution (#1260)
Co-authored-by: peter-evans <peter-evans@users.noreply.github.com>
2022-09-28 12:39:00 +09:00
campersau
ddab646771 fix: only strip optional '.git' suffix from https server remote name and not 'Xgit' (#1257) 2022-09-28 12:35:31 +09:00
Peter Evans
3f9dbd5a76 fix: replace use of any type (#1251) 2022-09-21 15:42:50 +09:00
Peter Evans
171dd555b9 fix: improve logging when checking fork (#1246) 2022-09-21 10:40:38 +09:00
Peter Evans
6e59b075e0 test: update the test execution env (#1235) 2022-08-26 11:07:49 +09:00
Peter Evans
9c5916f06d docs: add funding 2022-08-26 10:32:19 +09:00
github-actions[bot]
33434f1c62 build: update distribution (#1229)
Co-authored-by: peter-evans <peter-evans@users.noreply.github.com>
2022-08-19 11:21:51 +09:00
dependabot[bot]
9ca978d38e build(deps): bump @actions/core from 1.6.0 to 1.9.1 (#1219)
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.6.0 to 1.9.1.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

---
updated-dependencies:
- dependency-name: "@actions/core"
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-19 11:17:02 +09:00
Peter Evans
8e154b2a92 ci: add workflow permissions (#1220) 2022-08-19 11:00:29 +09:00
github-actions[bot]
18f90432be build: update distribution (#1216)
Co-authored-by: peter-evans <peter-evans@users.noreply.github.com>
2022-08-18 17:29:42 +09:00
Peter Evans
2721abb4d0 fix: handle nothing to commit when autocrlf is set (#1211) 2022-08-18 17:20:00 +09:00
github-actions[bot]
20dac2ed48 build: update distribution (#1208)
Co-authored-by: peter-evans <peter-evans@users.noreply.github.com>
2022-08-17 12:37:21 +09:00
tillganster
8557470a68 feat: support no_proxy environment variable (#1205)
Co-authored-by: TGANSTE <till.ganster@mercedes-benz.com>
2022-08-17 12:25:36 +09:00
Peter Evans
10db75894f docs: add info about workflow permissions 2022-06-08 17:57:28 +09:00
Peter Evans
5a6b15373e docs: clearer description of update behaviour 2022-06-08 17:30:26 +09:00
16 changed files with 877 additions and 309 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
github: peter-evans

View File

@@ -10,6 +10,11 @@ on:
paths-ignore: paths-ignore:
- 'README.md' - 'README.md'
- 'docs/**' - 'docs/**'
permissions:
pull-requests: write
contents: write
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -36,6 +36,13 @@ Create Pull Request action will:
You can also pin to a [specific release](https://github.com/peter-evans/create-pull-request/releases) version in the format `@v4.x.x` You can also pin to a [specific release](https://github.com/peter-evans/create-pull-request/releases) version in the format `@v4.x.x`
### Workflow permissions
For this action to work you must explicitly allow GitHub Actions to create pull requests.
This setting can be found in a repository's settings under Actions > General > Workflow permissions.
For repositories belonging to an organization, this setting can be managed by admins in organization settings under Actions > General > Workflow permissions.
### Action inputs ### Action inputs
All inputs are **optional**. If not set, sensible defaults will be used. All inputs are **optional**. If not set, sensible defaults will be used.
@@ -106,7 +113,7 @@ How the action behaves:
- If there are changes (i.e. a diff exists with the checked-out base branch), the changes will be pushed to a new `branch` and a pull request created. - If there are changes (i.e. a diff exists with the checked-out base branch), the changes will be pushed to a new `branch` and a pull request created.
- If there are no changes (i.e. no diff exists with the checked-out base branch), no pull request will be created and the action exits silently. - If there are no changes (i.e. no diff exists with the checked-out base branch), no pull request will be created and the action exits silently.
- If a pull request already exists and there are no further changes (i.e. no diff with the current pull request branch) then the action exits silently. - If a pull request already exists it will be updated if necessary. Local changes in the Actions workspace, or changes on the base branch, can cause an update. If no update is required the action exits silently.
- If a pull request exists and new changes on the base branch make the pull request unnecessary (i.e. there is no longer a diff between the pull request branch and the base), the pull request is automatically closed. Additionally, if `delete-branch` is set to `true` the `branch` will be deleted. - If a pull request exists and new changes on the base branch make the pull request unnecessary (i.e. there is no longer a diff between the pull request branch and the base), the pull request is automatically closed. Additionally, if `delete-branch` is set to `true` the `branch` will be deleted.
For further details about how the action works and usage guidelines, see [Concepts, guidelines and advanced usage](docs/concepts-guidelines.md). For further details about how the action works and usage guidelines, see [Concepts, guidelines and advanced usage](docs/concepts-guidelines.md).

View File

@@ -8,7 +8,7 @@ if [[ "$(docker images -q $IMAGE 2> /dev/null)" == "" || $ARG1 == "build" ]]; th
echo "Building Docker image $IMAGE ..." echo "Building Docker image $IMAGE ..."
cat > Dockerfile << EOF cat > Dockerfile << EOF
FROM node:12-alpine FROM node:16-alpine
RUN apk --no-cache add git git-daemon RUN apk --no-cache add git git-daemon
RUN npm install jest jest-environment-jsdom --global RUN npm install jest jest-environment-jsdom --global
WORKDIR /cpr WORKDIR /cpr

View File

@@ -56,6 +56,24 @@ describe('utils tests', () => {
) )
expect(remote4.protocol).toEqual('HTTPS') expect(remote4.protocol).toEqual('HTTPS')
expect(remote4.repository).toEqual('peter-evans/create-pull-request') expect(remote4.repository).toEqual('peter-evans/create-pull-request')
const remote5 = utils.getRemoteDetail(
'https://github.com/peter-evans/ungit'
)
expect(remote5.protocol).toEqual('HTTPS')
expect(remote5.repository).toEqual('peter-evans/ungit')
const remote6 = utils.getRemoteDetail(
'https://github.com/peter-evans/ungit.git'
)
expect(remote6.protocol).toEqual('HTTPS')
expect(remote6.repository).toEqual('peter-evans/ungit')
const remote7 = utils.getRemoteDetail(
'git@github.com:peter-evans/ungit.git'
)
expect(remote7.protocol).toEqual('SSH')
expect(remote7.repository).toEqual('peter-evans/ungit')
}) })
test('getRemoteDetail fails to parse a remote URL', async () => { test('getRemoteDetail fails to parse a remote URL', async () => {

1036
dist/index.js vendored

File diff suppressed because it is too large Load Diff

36
package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "4.0.0", "version": "4.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.6.0", "@actions/core": "^1.9.1",
"@actions/exec": "^1.1.0", "@actions/exec": "^1.1.0",
"@octokit/core": "^3.5.1", "@octokit/core": "^3.5.1",
"@octokit/plugin-paginate-rest": "^2.17.0", "@octokit/plugin-paginate-rest": "^2.17.0",
@@ -37,11 +37,12 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.6.0", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"dependencies": { "dependencies": {
"@actions/http-client": "^1.0.11" "@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
} }
}, },
"node_modules/@actions/exec": { "node_modules/@actions/exec": {
@@ -53,11 +54,11 @@
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
"version": "1.0.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": { "dependencies": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"node_modules/@actions/io": { "node_modules/@actions/io": {
@@ -7550,11 +7551,12 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.6.0", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"requires": { "requires": {
"@actions/http-client": "^1.0.11" "@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
} }
}, },
"@actions/exec": { "@actions/exec": {
@@ -7566,11 +7568,11 @@
} }
}, },
"@actions/http-client": { "@actions/http-client": {
"version": "1.0.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": { "requires": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"@actions/io": { "@actions/io": {

View File

@@ -29,7 +29,7 @@
}, },
"homepage": "https://github.com/peter-evans/create-pull-request", "homepage": "https://github.com/peter-evans/create-pull-request",
"dependencies": { "dependencies": {
"@actions/core": "^1.6.0", "@actions/core": "^1.9.1",
"@actions/exec": "^1.1.0", "@actions/exec": "^1.1.0",
"@octokit/core": "^3.5.1", "@octokit/core": "^3.5.1",
"@octokit/plugin-paginate-rest": "^2.17.0", "@octokit/plugin-paginate-rest": "^2.17.0",

View File

@@ -4,6 +4,7 @@ import {v4 as uuidv4} from 'uuid'
const CHERRYPICK_EMPTY = const CHERRYPICK_EMPTY =
'The previous cherry-pick is now empty, possibly due to conflict resolution.' 'The previous cherry-pick is now empty, possibly due to conflict resolution.'
const NOTHING_TO_COMMIT = 'nothing to commit, working tree clean'
export enum WorkingBaseType { export enum WorkingBaseType {
Branch = 'branch', Branch = 'branch',
@@ -134,7 +135,14 @@ export async function createOrUpdateBranch(
if (signoff) { if (signoff) {
popts.push('--signoff') popts.push('--signoff')
} }
await git.commit(popts) const commitResult = await git.commit(popts, true)
// 'nothing to commit' can occur when core.autocrlf is set to true
if (
commitResult.exitCode != 0 &&
!commitResult.stdout.includes(NOTHING_TO_COMMIT)
) {
throw new Error(`Unexpected error: ${commitResult.stderr}`)
}
} }
// Remove uncommitted tracked and untracked changes // Remove uncommitted tracked and untracked changes

View File

@@ -60,6 +60,9 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
: baseRemote.repository : baseRemote.repository
if (inputs.pushToFork) { if (inputs.pushToFork) {
// Check if the supplied fork is really a fork of the base // Check if the supplied fork is really a fork of the base
core.info(
`Checking if '${branchRepository}' is a fork of '${baseRemote.repository}'`
)
const parentRepository = await githubHelper.getRepositoryParent( const parentRepository = await githubHelper.getRepositoryParent(
branchRepository branchRepository
) )
@@ -240,8 +243,8 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
} }
} }
} }
} catch (error: any) { } catch (error) {
core.setFailed(error.message) core.setFailed(utils.getErrorMessage(error))
} finally { } finally {
// Remove auth and restore persisted auth config if it existed // Remove auth and restore persisted auth config if it existed
core.startGroup('Restore persisted git credentials') core.startGroup('Restore persisted git credentials')

View File

@@ -3,6 +3,7 @@ import * as fs from 'fs'
import {GitCommandManager} from './git-command-manager' import {GitCommandManager} from './git-command-manager'
import * as path from 'path' import * as path from 'path'
import {URL} from 'url' import {URL} from 'url'
import * as utils from './utils'
export class GitAuthHelper { export class GitAuthHelper {
private git: GitCommandManager private git: GitCommandManager
@@ -33,8 +34,8 @@ export class GitAuthHelper {
try { try {
await this.setExtraheaderConfig(this.persistedExtraheaderConfigValue) await this.setExtraheaderConfig(this.persistedExtraheaderConfigValue)
core.info('Persisted git credentials restored') core.info('Persisted git credentials restored')
} catch (e: any) { } catch (e) {
core.warning(e) core.warning(utils.getErrorMessage(e))
} }
} }
} }

View File

@@ -53,7 +53,10 @@ export class GitCommandManager {
return await this.exec(args, allowAllExitCodes) return await this.exec(args, allowAllExitCodes)
} }
async commit(options?: string[]): Promise<void> { async commit(
options?: string[],
allowAllExitCodes = false
): Promise<GitOutput> {
const args = ['commit'] const args = ['commit']
if (this.identityGitOptions) { if (this.identityGitOptions) {
args.unshift(...this.identityGitOptions) args.unshift(...this.identityGitOptions)
@@ -63,7 +66,7 @@ export class GitCommandManager {
args.push(...options) args.push(...options)
} }
await this.exec(args) return await this.exec(args, allowAllExitCodes)
} }
async config( async config(

View File

@@ -1,6 +1,7 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import {Inputs} from './create-pull-request' import {Inputs} from './create-pull-request'
import {Octokit, OctokitOptions} from './octokit-client' import {Octokit, OctokitOptions} from './octokit-client'
import * as utils from './utils'
const ERROR_PR_REVIEW_FROM_AUTHOR = const ERROR_PR_REVIEW_FROM_AUTHOR =
'Review cannot be requested from pull request author' 'Review cannot be requested from pull request author'
@@ -64,10 +65,9 @@ export class GitHubHelper {
html_url: pull.html_url, html_url: pull.html_url,
created: true created: true
} }
} catch (e: any) { } catch (e) {
if ( if (
e.message && utils.getErrorMessage(e).includes(`A pull request already exists for`)
e.message.includes(`A pull request already exists for`)
) { ) {
core.info(`A pull request already exists for ${headBranch}`) core.info(`A pull request already exists for ${headBranch}`)
} else { } else {
@@ -169,8 +169,8 @@ export class GitHubHelper {
pull_number: pull.number, pull_number: pull.number,
...requestReviewersParams ...requestReviewersParams
}) })
} catch (e: any) { } catch (e) {
if (e.message && e.message.includes(ERROR_PR_REVIEW_FROM_AUTHOR)) { if (utils.getErrorMessage(e).includes(ERROR_PR_REVIEW_FROM_AUTHOR)) {
core.warning(ERROR_PR_REVIEW_FROM_AUTHOR) core.warning(ERROR_PR_REVIEW_FROM_AUTHOR)
} else { } else {
throw e throw e

View File

@@ -30,8 +30,8 @@ async function run(): Promise<void> {
core.debug(`Inputs: ${inspect(inputs)}`) core.debug(`Inputs: ${inspect(inputs)}`)
await createPullRequest(inputs) await createPullRequest(inputs)
} catch (error: any) { } catch (error) {
core.setFailed(error.message) core.setFailed(utils.getErrorMessage(error))
} }
} }

View File

@@ -11,13 +11,23 @@ export const Octokit = Core.plugin(
autoProxyAgent autoProxyAgent
) )
// Octokit plugin to support the https_proxy environment variable // Octokit plugin to support the https_proxy and no_proxy environment variable
function autoProxyAgent(octokit: Core) { function autoProxyAgent(octokit: Core) {
const proxy = process.env.https_proxy || process.env.HTTPS_PROXY const proxy = process.env.https_proxy || process.env.HTTPS_PROXY
const noProxy = process.env.no_proxy || process.env.NO_PROXY
let noProxyArray: string[] = []
if (noProxy) {
noProxyArray = noProxy.split(',')
}
if (!proxy) return if (!proxy) return
const agent = new HttpsProxyAgent(proxy) const agent = new HttpsProxyAgent(proxy)
octokit.hook.before('request', options => { octokit.hook.before('request', options => {
if (noProxyArray.includes(options.request.hostname)) {
return
}
options.request.agent = agent options.request.agent = agent
}) })
} }

View File

@@ -47,11 +47,11 @@ export function getRemoteDetail(remoteUrl: string): RemoteDetail {
} }
const httpsUrlPattern = new RegExp( const httpsUrlPattern = new RegExp(
'^https?://.*@?' + githubServerMatch[1] + '/(.+/.+?)(.git)?$', '^https?://.*@?' + githubServerMatch[1] + '/(.+/.+?)(\\.git)?$',
'i' 'i'
) )
const sshUrlPattern = new RegExp( const sshUrlPattern = new RegExp(
'^git@' + githubServerMatch[1] + ':(.+/.+).git$', '^git@' + githubServerMatch[1] + ':(.+/.+)\\.git$',
'i' 'i'
) )
@@ -134,13 +134,15 @@ export function fileExistsSync(path: string): boolean {
let stats: fs.Stats let stats: fs.Stats
try { try {
stats = fs.statSync(path) stats = fs.statSync(path)
} catch (error: any) { } catch (error) {
if (error.code === 'ENOENT') { if (hasErrorCode(error) && error.code === 'ENOENT') {
return false return false
} }
throw new Error( throw new Error(
`Encountered an error when checking whether path '${path}' exists: ${error.message}` `Encountered an error when checking whether path '${path}' exists: ${getErrorMessage(
error
)}`
) )
} }
@@ -150,3 +152,13 @@ export function fileExistsSync(path: string): boolean {
return false return false
} }
/* eslint-disable @typescript-eslint/no-explicit-any */
function hasErrorCode(error: any): error is {code: string} {
return typeof (error && error.code) === 'string'
}
export function getErrorMessage(error: unknown) {
if (error instanceof Error) return error.message
return String(error)
}