diff --git a/__tests__/utils.test.js b/__tests__/utils.test.js
index 8d42426..f727438 100644
--- a/__tests__/utils.test.js
+++ b/__tests__/utils.test.js
@@ -4,6 +4,29 @@ const { getInputs, state, validatePullRequest } = require('../src/utils')
// Mock for dependencies (in this case, for the GitHub "core" module)
jest.mock('@actions/core')
+const basePullRequest = {
+ base: {
+ ref: ''
+ },
+ head:{
+ ref: ''
+ }
+}
+
+const mockCompare = jest.fn()
+mockCompare.mockReturnValue({
+ data: {
+ status: 'before',
+ 'behind_by': 0
+ }
+})
+
+const mockGetPullRequest = jest.fn()
+mockGetPullRequest.mockReturnValue({
+ data: {
+ mergeable: true,
+ }
+})
// Mock for the object `github` that is passed to the action
const github = {
rest: {
@@ -12,7 +35,10 @@ const github = {
},
pulls: {
createReview: jest.fn(),
- get: jest.fn()
+ get: mockGetPullRequest
+ },
+ repos: {
+ compare: mockCompare
}
}
}
@@ -315,9 +341,94 @@ describe('Tests for `validatePullRequest` function', () => {
'The pull-request is associated with a dependency group but the action is not configured to handle dependency groups.'
)
})
+
+ test('should return `true` after compare commits', async () => {
+ mockCompare.mockReturnValueOnce({
+ data: {
+ status: 'behind',
+ 'behind_by': 2
+ }
+ })
+
+ const pullRequest = {
+ ...basePullRequest,
+ merged: false,
+ state: 'open',
+ draft: false,
+ user: {
+ login: 'dependabot[bot]'
+ },
+ mergeable: true,
+ mergeable_state: 'behind'
+ }
+
+ const config = {
+ inputs: {
+ approveOnly: false,
+ handleSubmodule: true,
+ handleDependencyGroup: true
+ },
+ metadata: {}
+ }
+
+ const result = await validatePullRequest(
+ github,
+ repository,
+ pullRequest,
+ config
+ )
+
+ expect(result.execute).toBe(true)
+ expect(result.body).toBe('@dependabot rebase')
+ expect(result.validationState).toBe(state.rebased)
+ expect(result.validationMessage).toBe('The pull request will be rebased.')
+ })
+
+ test('should return `true` when pull request has a mergeable state of `null`', async () => {
+ mockGetPullRequest.mockReturnValueOnce({
+ data: {
+ mergeable: null,
+ mergeable_state: 'behind'
+ }
+ })
+
+ const pullRequest = {
+ ...basePullRequest,
+ merged: false,
+ state: 'open',
+ draft: false,
+ user: {
+ login: 'dependabot[bot]'
+ },
+ mergeable: null,
+ mergeable_state: 'behind'
+ }
+
+ const config = {
+ inputs: {
+ approveOnly: false,
+ handleSubmodule: true,
+ handleDependencyGroup: true
+ },
+ metadata: {}
+ }
+
+ const result = await validatePullRequest(
+ github,
+ repository,
+ pullRequest,
+ config
+ )
+
+ expect(result.execute).toBe(true)
+ expect(result.body).toBe('@dependabot rebase')
+ expect(result.validationState).toBe(state.rebased)
+ expect(result.validationMessage).toBe('The pull request will be rebased.')
+ }, 15000)
test('should return `true` when pull request has a mergeable state of `behind`', async () => {
const pullRequest = {
+ ...basePullRequest,
merged: false,
state: 'open',
draft: false,
@@ -354,6 +465,7 @@ describe('Tests for `validatePullRequest` function', () => {
'should return `false` when pull request has a mergeable state of `%s`',
async mergeableState => {
const pullRequest = {
+ ...basePullRequest,
merged: false,
state: 'open',
draft: false,
@@ -395,6 +507,7 @@ describe('Tests for `validatePullRequest` function', () => {
'should return `false` when pull request has a target `%s` and update type `%s`',
async (target, updateType) => {
const pullRequest = {
+ ...basePullRequest,
merged: false,
state: 'open',
draft: false,
@@ -448,6 +561,7 @@ describe('Tests for `validatePullRequest` function', () => {
'should return `true` when pull request has a target `%s` and update type `%s` and command `%s`',
async (target, updateType, cmd) => {
const pullRequest = {
+ ...basePullRequest,
merged: false,
state: 'open',
draft: false,
@@ -486,6 +600,7 @@ describe('Tests for `validatePullRequest` function', () => {
test('should return `true` when pull request has approve-only enabled', async () => {
const pullRequest = {
+ ...basePullRequest,
merged: false,
state: 'open',
draft: false,
diff --git a/badges/coverage.svg b/badges/coverage.svg
index f0a3125..c37dda1 100644
--- a/badges/coverage.svg
+++ b/badges/coverage.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/dist/index.js b/dist/index.js
index db3bdf0..29add10 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -24727,6 +24727,15 @@ async function approvePullRequest(github, repo, pull_request, body) {
})
}
+async function comparePullRequestToBase(github, repo, pull_request) {
+ return await github.rest.repos.compareCommits({
+ owner: repo.owner.login,
+ repo: repo.name,
+ base: pull_request.base.ref,
+ head: pull_request.head.ref
+ })
+}
+
async function getPullRequest(github, repo, pull_request) {
return await github.rest.pulls.get({
owner: repo.owner.login,
@@ -24801,10 +24810,12 @@ module.exports = async function run({ github, context, inputs, metadata }) {
return core.setFailed(msg)
}
+ core.startGroup('Input Values')
core.debug(`GitHub: ${JSON.stringify(github, null, 2)}`)
core.debug(`Context: ${JSON.stringify(context, null, 2)}`)
core.debug(`Inputs: ${JSON.stringify(inputs, null, 2)}`)
core.debug(`Metadata: ${JSON.stringify(metadata, null, 2)}`)
+ core.endGroup()
const config = {
inputs: getInputs(inputs),
@@ -24923,152 +24934,180 @@ function getMetadata(metadata) {
}
async function validatePullRequest(github, repository, pull_request, config) {
- if (pull_request.state !== 'open' || pull_request.merged) {
- return {
- execute: false,
- validationState: state.skipped,
- validationMessage: 'Pull request is not open or already merged.'
+ core.startGroup('Validate Pull Request')
+ try {
+ if (pull_request.state !== 'open' || pull_request.merged) {
+ return {
+ execute: false,
+ validationState: state.skipped,
+ validationMessage: 'Pull request is not open or already merged.'
+ }
}
- }
- if (pull_request.draft) {
- return {
- execute: false,
- validationState: state.skipped,
- validationMessage: 'Pull request is a draft.'
+ if (pull_request.draft) {
+ return {
+ execute: false,
+ validationState: state.skipped,
+ validationMessage: 'Pull request is a draft.'
+ }
}
- }
- if (
- !config.inputs.skipVerification &&
- pull_request.user.login !== dependabotUser
- ) {
- return {
- execute: false,
- validationState: state.skipped,
- validationMessage: `The Commit/PullRequest was not created by ${dependabotUser}.`
+ if (
+ !config.inputs.skipVerification &&
+ pull_request.user.login !== dependabotUser
+ ) {
+ return {
+ execute: false,
+ validationState: state.skipped,
+ validationMessage: `The Commit/PullRequest was not created by ${dependabotUser}.`
+ }
}
- }
- let targetUpdateType = config.inputs.target
- if (config.metadata.ecosystem === 'gitsubmodule') {
- if (!config.inputs.handleSubmodule) {
+ let targetUpdateType = config.inputs.target
+ if (config.metadata.ecosystem === 'gitsubmodule') {
+ if (!config.inputs.handleSubmodule) {
+ return {
+ execute: false,
+ validationState: state.skipped,
+ validationMessage:
+ 'The pull-request is associated with a submodule but the action is not configured to handle submodules.'
+ }
+ } else {
+ targetUpdateType = updateTypes.any
+ }
+ }
+
+ if (
+ !config.inputs.handleDependencyGroup &&
+ config.metadata.dependecyGroup !== ''
+ ) {
return {
execute: false,
validationState: state.skipped,
validationMessage:
- 'The pull-request is associated with a submodule but the action is not configured to handle submodules.'
+ 'The pull-request is associated with a dependency group but the action is not configured to handle dependency groups.'
}
- } else {
- targetUpdateType = updateTypes.any
}
- }
- if (
- !config.inputs.handleDependencyGroup &&
- config.metadata.dependecyGroup !== ''
- ) {
- return {
- execute: false,
- validationState: state.skipped,
- validationMessage:
- 'The pull-request is associated with a dependency group but the action is not configured to handle dependency groups.'
+ const { data: compareData } = await cmd.comparePullRequestToBase(
+ github,
+ repository,
+ pull_request
+ )
+ if (compareData.status === 'behind' && compareData.behind_by > 0) {
+ return {
+ execute: true,
+ body: `@dependabot ${commandText.rebase}`,
+ cmd: cmd.addComment,
+ validationState: state.rebased,
+ validationMessage: 'The pull request will be rebased.'
+ }
}
- }
-
- let retryCount = 0
- let mergeabilityResolved = pull_request.mergeable !== null
-
- while (!mergeabilityResolved && retryCount < 5) {
- try {
- core.info(
- `Pull request mergeability is not resolved. Retry count: ${retryCount}`
- )
- const { data } = await cmd.getPullRequest(
- github,
- repository,
- pull_request
- )
+ let retryCount = 0
+ let mergeabilityResolved = pull_request.mergeable !== null
- if (data.mergeable === null || data.mergeable === undefined) {
+ while (!mergeabilityResolved && retryCount < 5) {
+ try {
core.info(
- `Pull request mergeability is not yet resolved... retrying in 5 seconds.`
+ `Pull request mergeability is not resolved. Retry count: ${retryCount}`
)
- retryCount++
- await new Promise(resolve => setTimeout(resolve, 5000))
- } else {
- mergeabilityResolved = true
+
+ const { data: prData } = await cmd.getPullRequest(
+ github,
+ repository,
+ pull_request
+ )
+
+ if (prData.mergeable === null || prData.mergeable === undefined) {
+ core.info(
+ `Pull request mergeability is not yet resolved... retrying in 5 seconds.`
+ )
+ retryCount++
+ await new Promise(resolve => setTimeout(resolve, 5000))
+ } else {
+ mergeabilityResolved = true
+ }
+ } catch (apiError) {
+ return {
+ execute: false,
+ validationState: state.skipped,
+ validationMessage: `An error occurred fetching the PR from Github: ${JSON.stringify(
+ apiError
+ )}`
+ }
}
- } catch (apiError) {
+ }
+
+ if (pull_request.mergeable_state === 'behind') {
+ return {
+ execute: true,
+ body: `@dependabot ${commandText.rebase}`,
+ cmd: cmd.addComment,
+ validationState: state.rebased,
+ validationMessage: 'The pull request will be rebased.'
+ }
+ }
+
+ if (
+ pull_request.mergeable_state === 'blocked' ||
+ pull_request.mergeable_state === 'dirty'
+ ) {
+ core.info(
+ `Pull request merge is blocked by conflicts. State: ${pull_request.mergeable_state}`
+ )
return {
execute: false,
validationState: state.skipped,
- validationMessage: `An error occurred fetching the PR from Github: ${JSON.stringify(
- apiError
- )}`
+ validationMessage:
+ 'Pull request merge is blocked by conflicts, please resolve them manually.'
}
}
- }
- if (pull_request.mergeable_state === 'behind') {
- return {
- execute: true,
- body: `@dependabot ${commandText.rebase}`,
- cmd: cmd.addComment,
- validationState: state.rebased,
- validationMessage: 'The pull request will be rebased.'
- }
- }
+ const treatVersion =
+ targetUpdateType === updateTypes.any ||
+ updateTypesPriority.indexOf(config.metadata.updateType) <=
+ updateTypesPriority.indexOf(targetUpdateType)
- if (
- pull_request.mergeable_state === 'blocked' ||
- pull_request.mergeable_state === 'dirty'
- ) {
core.info(
- `Pull request merge is blocked by conflicts. State: ${pull_request.mergeable_state}`
+ `Check package '${config.metadata.dependecyNames}' - Old: '${config.metadata.previousVersion}' New: '${config.metadata.newVersion}'`
)
- return {
- execute: false,
- validationState: state.skipped,
- validationMessage:
- 'Pull request merge is blocked by conflicts, please resolve them manually.'
+ core.info(`Is the package version treated? - ${treatVersion}`)
+ if (!treatVersion) {
+ return {
+ execute: false,
+ validationState: state.skipped,
+ validationMessage: `The package version is not treated by the action.`
+ }
}
- }
-
- const treatVersion =
- targetUpdateType === updateTypes.any ||
- updateTypesPriority.indexOf(config.metadata.updateType) <=
- updateTypesPriority.indexOf(targetUpdateType)
- core.info(
- `Check package '${config.metadata.dependecyNames}' - Old: '${config.metadata.previousVersion}' New: '${config.metadata.newVersion}'`
- )
- core.info(`Is the package version treated? - ${treatVersion}`)
- if (!treatVersion) {
- return {
- execute: false,
- validationState: state.skipped,
- validationMessage: `The package version is not treated by the action.`
+ if (config.inputs.approveOnly) {
+ return {
+ execute: true,
+ body: 'Approved by DependaMerge.',
+ cmd: cmd.approvePullRequest,
+ validationState: state.approved,
+ validationMessage: 'The pull request will be approved.'
+ }
}
- }
- if (config.inputs.approveOnly) {
return {
execute: true,
- body: 'Approved by DependaMerge.',
+ body: `@dependabot ${config.inputs.commandMethod}`,
cmd: cmd.approvePullRequest,
- validationState: state.approved,
- validationMessage: 'The pull request will be approved.'
+ validationState: state.merged,
+ validationMessage: 'The pull request will be merged.'
}
- }
-
- return {
- execute: true,
- body: `@dependabot ${config.inputs.commandMethod}`,
- cmd: cmd.approvePullRequest,
- validationState: state.merged,
- validationMessage: 'The pull request will be merged.'
+ } catch (validationError) {
+ return {
+ execute: false,
+ validationState: state.failed,
+ validationMessage: `An error occurred validating the PR: ${JSON.stringify(
+ validationError
+ )}`
+ }
+ } finally {
+ core.endGroup()
}
}
diff --git a/package-lock.json b/package-lock.json
index 0e1269b..e7fb6e4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "dependamerge-action",
- "version": "1.0.3",
+ "version": "1.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "dependamerge-action",
- "version": "1.0.3",
+ "version": "1.1.1",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.1"
diff --git a/package.json b/package.json
index 4600df5..e92bf57 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "dependamerge-action",
"description": "GitHub action that automatically validates, approves and merges pull requests for branches created by dependabot[bot].",
- "version": "1.0.3",
+ "version": "1.1.1",
"author": "dailydevops",
"private": true,
"homepage": "https://github.com/dailydevops/dependamerge-action#readme",
diff --git a/src/api.js b/src/api.js
index 2a3821e..ef1a216 100644
--- a/src/api.js
+++ b/src/api.js
@@ -19,6 +19,14 @@ async function approvePullRequest(github, repo, pull_request, body) {
})
}
+async function comparePullRequest(github, repo, pull_request) {
+ return await github.rest.repos.compare({
+ owner: repo.owner.login,
+ repo: repo.name,
+ basehead: `${pull_request.base.ref}...${pull_request.head.ref}`
+ })
+}
+
async function getPullRequest(github, repo, pull_request) {
return await github.rest.pulls.get({
owner: repo.owner.login,
@@ -30,5 +38,6 @@ async function getPullRequest(github, repo, pull_request) {
module.exports = {
addComment,
approvePullRequest,
+ comparePullRequest,
getPullRequest
}
diff --git a/src/index.js b/src/index.js
index 0c2d546..59ba0ce 100644
--- a/src/index.js
+++ b/src/index.js
@@ -51,10 +51,12 @@ module.exports = async function run({ github, context, inputs, metadata }) {
return core.setFailed(msg)
}
+ core.startGroup('Input Values')
core.debug(`GitHub: ${JSON.stringify(github, null, 2)}`)
core.debug(`Context: ${JSON.stringify(context, null, 2)}`)
core.debug(`Inputs: ${JSON.stringify(inputs, null, 2)}`)
core.debug(`Metadata: ${JSON.stringify(metadata, null, 2)}`)
+ core.endGroup()
const config = {
inputs: getInputs(inputs),
diff --git a/src/utils.js b/src/utils.js
index 0b0cd1e..f8f26b6 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,7 +1,12 @@
'use strict'
const core = require('@actions/core')
-const cmd = require('./api')
+const {
+ addComment,
+ approvePullRequest,
+ comparePullRequest,
+ getPullRequest
+} = require('./api')
const dependabotUser = 'dependabot[bot]'
// const dependabotCommitter = 'GitHub'
@@ -135,6 +140,17 @@ async function validatePullRequest(github, repository, pull_request, config) {
}
}
+ const { data: compareData } = await comparePullRequest(github, repository, pull_request)
+ if (compareData && compareData.status === 'behind' && compareData.behind_by > 0) {
+ return {
+ execute: true,
+ body: `@dependabot ${commandText.rebase}`,
+ cmd: addComment,
+ validationState: state.rebased,
+ validationMessage: 'The pull request will be rebased.'
+ }
+ }
+
let retryCount = 0
let mergeabilityResolved = pull_request.mergeable !== null
@@ -144,13 +160,13 @@ async function validatePullRequest(github, repository, pull_request, config) {
`Pull request mergeability is not resolved. Retry count: ${retryCount}`
)
- const { data } = await cmd.getPullRequest(
+ const { data: prData } = await getPullRequest(
github,
repository,
pull_request
)
- if (data.mergeable === null || data.mergeable === undefined) {
+ if (prData.mergeable === null || prData.mergeable === undefined) {
core.info(
`Pull request mergeability is not yet resolved... retrying in 5 seconds.`
)
@@ -174,7 +190,7 @@ async function validatePullRequest(github, repository, pull_request, config) {
return {
execute: true,
body: `@dependabot ${commandText.rebase}`,
- cmd: cmd.addComment,
+ cmd: addComment,
validationState: state.rebased,
validationMessage: 'The pull request will be rebased.'
}
@@ -216,7 +232,7 @@ async function validatePullRequest(github, repository, pull_request, config) {
return {
execute: true,
body: 'Approved by DependaMerge.',
- cmd: cmd.approvePullRequest,
+ cmd: approvePullRequest,
validationState: state.approved,
validationMessage: 'The pull request will be approved.'
}
@@ -225,7 +241,7 @@ async function validatePullRequest(github, repository, pull_request, config) {
return {
execute: true,
body: `@dependabot ${config.inputs.commandMethod}`,
- cmd: cmd.approvePullRequest,
+ cmd: approvePullRequest,
validationState: state.merged,
validationMessage: 'The pull request will be merged.'
}