Skip to content

Commit

Permalink
feat: Added rebase detection (#17)
Browse files Browse the repository at this point in the history
* feat: Added `rebase` detection

* chore: Rebased and rebuild to latest `main`

* chore: Update `rebase` mode

* fix: Updated tests

* chore: Added tests for `api.js`

* docs: Updated README

* style: Missing spaces
  • Loading branch information
samtrion authored Aug 26, 2024
1 parent 9fa1950 commit 370b839
Show file tree
Hide file tree
Showing 10 changed files with 782 additions and 140 deletions.
28 changes: 17 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,27 @@ jobs:
uses: dailydevops/dependamerge-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
command: squash
command: squash # Not required, default is squash
approve-only: false # Not required, default is false
handle-submodule: false # Not required, default is false
handle-dependency-group: true # Not required, default is true
target: patch # Not required, default is patch
skip-commit-verification: false # Not required, default is false
skip-verification: false # Not required, default is false
```
### Inputs
| Name | Description | Required | Default | Available Values |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: | ----------------------------- | -------------------------------- |
| `token` | GitHub token | ✔ | `${{ secrets.GITHUB_TOKEN }}` | --- |
| `command` | Merge Method with which the pull request is to be merged. | ❌ | `squash` | `squash`, `merge` |
| `approve-only` | If `true`, then the pull request is only approved, but not merged. | ❌ | `false` | `true`, `false` |
| `handle-submodule` | If `true`, Git submodules are also merged. | ❌ | `false` | `true`, `false` |
| `handle-dependency-group` | If `true`, all pull requests of a dependency group are merged. | ❌ | `true` | `true`, `false` |
| `target` | The maximum target of the version comparison to be merged. | ❌ | `patch` | `major`, `minor`, `patch`, `any` |
| `skip-commit-verification` | If `true`, then the action will not expect the commits to have a verification signature. It is required to set this to true in GitHub Enterprise Server. | ❌ | `false` | `true`, `false` |
| `skip-verification` | If `true`, the action will not validate the user or the commit verification status. | ❌ | `false` | `true`, `false` |
| Name | Description | Required | Default | Available Values |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: | ----------------------------- | -------------------------------- |
| `token` | GitHub token | ✔ | `${{ secrets.GITHUB_TOKEN }}` | --- |
| `command` | Merge Method with which the pull request is to be merged.<br/><br/>Command `squash` is the default command. All commits are squashed into one commit and merged into the target branch.<br />Command `merge` merges the pull request with the target branch, keeping the commit history.<br />Command `rebase` only checks whether the PR is behind the current compare branch, if so, the PR is rebased. | ❌ | `squash` | `squash`, `merge`, `rebase` |
| `approve-only` | If `true`, then the pull request is only approved, but not merged. | ❌ | `false` | `true`, `false` |
| `handle-submodule` | If `true`, Git submodules are also merged. | ❌ | `false` | `true`, `false` |
| `handle-dependency-group` | If `true`, all pull requests of a dependency group are merged. | ❌ | `true` | `true`, `false` |
| `target` | The maximum target of the version comparison to be merged. | ❌ | `patch` | `major`, `minor`, `patch`, `any` |
| `skip-commit-verification` | If `true`, then the action will not expect the commits to have a verification signature. It is required to set this to true in GitHub Enterprise Server. | ❌ | `false` | `true`, `false` |
| `skip-verification` | If `true`, the action will not validate the user or the commit verification status. | ❌ | `false` | `true`, `false` |

### Outputs

Expand Down
105 changes: 105 additions & 0 deletions __tests__/api.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
const {
addComment,
approvePullRequest,
comparePullRequest,
getPullRequest
} = require('../src/api')

// Mock for the GitHub API client
const github = {
rest: {
issues: {
createComment: jest.fn()
},
pulls: {
createReview: jest.fn()
},
repos: {
compare: jest.fn(),
get: jest.fn()
}
}
}

// Mock data for the repository and pull request
const repo = {
owner: {
login: 'test-owner'
},
name: 'test-repo'
}

const pullRequest = {
base: {
ref: 'base-branch'
},
number: 123,
head: {
ref: 'head-branch'
}
}

describe('Tests for `addComment` function', () => {
test('should add a comment to the pull request', async () => {
const body = 'This is a test comment.'

await addComment(github, repo, pullRequest, body)

expect(github.rest.issues.createComment).toHaveBeenCalledWith({
owner: repo.owner.login,
repo: repo.name,
issue_number: pullRequest.number,
body
})
})
test('should approve the pull request', async () => {
const body = 'This is a test review.'

await approvePullRequest(github, repo, pullRequest, body)

expect(github.rest.pulls.createReview).toHaveBeenCalledWith({
owner: repo.owner.login,
repo: repo.name,
pull_number: pullRequest.number,
event: 'APPROVE',
body
})
})
test('should compare a pull request in a GitHub repository', async () => {
const baseRef = 'base-branch'
const headRef = 'head-branch'

const comparisonResult = {
// Mock comparison result
}

github.rest.repos.compare = jest.fn().mockResolvedValue(comparisonResult)

const result = await comparePullRequest(github, repo, pullRequest)

expect(github.rest.repos.compare).toHaveBeenCalledWith({
owner: repo.owner.login,
repo: repo.name,
basehead: `${baseRef}...${headRef}`
})

expect(result).toBe(comparisonResult)
})
test('should retrieve a pull request from a GitHub repository', async () => {
const pullRequestData = {
// Mock pull request data
}

github.rest.pulls.get = jest.fn().mockResolvedValue(pullRequestData)

const result = await getPullRequest(github, repo, pullRequest)

expect(github.rest.pulls.get).toHaveBeenCalledWith({
owner: repo.owner.login,
repo: repo.name,
pull_number: pullRequest.number
})

expect(result).toBe(pullRequestData)
})
})
161 changes: 160 additions & 1 deletion __tests__/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -12,7 +35,10 @@ const github = {
},
pulls: {
createReview: jest.fn(),
get: jest.fn()
get: mockGetPullRequest
},
repos: {
compare: mockCompare
}
}
}
Expand All @@ -28,6 +54,7 @@ const repository = {
describe('Tests for `getInputs` function', () => {
test.each([
['merge', 'merge'],
['rebase', 'rebase'],
['squash', 'squash and merge'],
[undefined, 'squash and merge']
])('input command `%s` should return `%s`', (command, expected) => {
Expand Down Expand Up @@ -316,8 +343,136 @@ describe('Tests for `validatePullRequest` function', () => {
)
})

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,
command: 'rebase',
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 `false` when compare commits is not behind', async () => {
mockCompare.mockReturnValueOnce({
data: {
status: 'clean',
behind_by: 0
}
})

const pullRequest = {
...basePullRequest,
merged: false,
state: 'open',
draft: false,
user: {
login: 'dependabot[bot]'
}
}

const config = {
inputs: {
approveOnly: false,
command: 'rebase',
handleSubmodule: true,
handleDependencyGroup: true
},
metadata: {}
}

const result = await validatePullRequest(
github,
repository,
pullRequest,
config
)

expect(result.execute).toBe(false)
expect(result.validationState).toBe(state.skipped)
expect(result.validationMessage).toBe(
`The pull request is not behind the target branch.`
)
}, 15000)

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,
Expand Down Expand Up @@ -354,6 +509,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,
Expand Down Expand Up @@ -395,6 +551,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,
Expand Down Expand Up @@ -448,6 +605,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,
Expand Down Expand Up @@ -486,6 +644,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,
Expand Down
2 changes: 1 addition & 1 deletion badges/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 370b839

Please sign in to comment.