Skip to content

Commit 2d8e405

Browse files
Handle commit hash versions (#200)
* chore: Run only test files when testing Prevents a warning message about test/moduleChanges.js having no tests. * feat: Handle commit hash versions This change add support for commit hash versions on both PR diff and title. They will be merged independently of the target option since the hash doesn't have that information. * test: add tests cases without a target This will prevent one issue where the PR was not merged and failed silently when there wasn't a target defined * fix: improve semver version/SHA1 hash detection * test: fix isCommitHash test name Also add a new test case for a full SHA1 hash.
1 parent 70dee0a commit 2d8e405

9 files changed

+286
-43
lines changed

dist/index.js

+55-15
Original file line numberDiff line numberDiff line change
@@ -6311,7 +6311,7 @@ class SemVer {
63116311
if (identifier) {
63126312
// 1.2.0-beta.1 bumps to 1.2.0-beta.2,
63136313
// 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
6314-
if (compareIdentifiers(this.prerelease[0], identifier) === 0) {
6314+
if (this.prerelease[0] === identifier) {
63156315
if (isNaN(this.prerelease[1])) {
63166316
this.prerelease = [identifier, 0]
63176317
}
@@ -9299,7 +9299,7 @@ const toolkit = __nccwpck_require__(2183)
92999299
const packageInfo = __nccwpck_require__(4147)
93009300
const { githubClient } = __nccwpck_require__(3386)
93019301
const { logInfo, logWarning, logError } = __nccwpck_require__(653)
9302-
const { getInputs, getPackageName } = __nccwpck_require__(6254)
9302+
const { isValidSemver, isCommitHash, getInputs, getPackageName } = __nccwpck_require__(6254)
93039303
const { targetOptions } = __nccwpck_require__(5013)
93049304
const {
93059305
getModuleVersionChanges,
@@ -9384,6 +9384,10 @@ function isAMajorReleaseBump(change) {
93849384
const from = change.delete
93859385
const to = change.insert
93869386

9387+
if (isCommitHash(from) && isCommitHash(to)) {
9388+
return false
9389+
}
9390+
93879391
const diff = semverDiff(semverCoerce(from), semverCoerce(to))
93889392
return diff === targetOptions.major
93899393
}
@@ -9395,11 +9399,18 @@ function parsePrTitle(pullRequest) {
93959399
if (!match) {
93969400
throw new Error('Error while parsing PR title, expected: `bump <package> from <old-version> to <new-version>`')
93979401
}
9398-
const [, oldVersion, newVersion] = match
93999402

94009403
const packageName = getPackageName(pullRequest.head.ref)
94019404

9402-
return { [packageName]: { delete: semverCoerce(oldVersion).raw, insert: semverCoerce(newVersion).raw } }
9405+
const [, oldVersion, newVersion] = match.map(t => t.replace(/`/g, ''))
9406+
const isValid = isValidSemver(oldVersion) && isValidSemver(newVersion)
9407+
9408+
return {
9409+
[packageName]: {
9410+
delete: isValid ? semverCoerce(oldVersion)?.raw : oldVersion,
9411+
insert: isValid ? semverCoerce(newVersion)?.raw : newVersion
9412+
}
9413+
}
94039414
}
94049415

94059416

@@ -9539,19 +9550,13 @@ exports.logWarning = log(warning)
95399550

95409551
const semverDiff = __nccwpck_require__(4297)
95419552
const semverCoerce = __nccwpck_require__(3466)
9542-
const semverValid = __nccwpck_require__(9601)
95439553
const { parse } = __nccwpck_require__(153)
9554+
const { isCommitHash, isValidSemver } = __nccwpck_require__(6254)
95449555

95459556
const { semanticVersionOrder } = __nccwpck_require__(5013)
9546-
const { logWarning } = __nccwpck_require__(653)
95479557

95489558
const expression = /"([^\s]+)":\s*"([^\s]+)"/
95499559

9550-
function hasBadChars(version) {
9551-
// recognize submodules title likes 'Bump dotbot from `aa93350` to `acaaaac`'
9552-
return /^[^^~*-0-9+x]/.test(version)
9553-
}
9554-
95559560
const checkModuleVersionChanges = (moduleChanges, target) => {
95569561
for (const module in moduleChanges) {
95579562
const from = moduleChanges[module].delete
@@ -9561,9 +9566,12 @@ const checkModuleVersionChanges = (moduleChanges, target) => {
95619566
return false
95629567
}
95639568

9564-
if ((!semverValid(from) && hasBadChars(from)) || (!semverValid(to) && hasBadChars(to))) {
9565-
logWarning(`Module "${module}" contains invalid semver versions from: ${from} to: ${to}`)
9566-
return false
9569+
if (isCommitHash(from) && isCommitHash(to)) {
9570+
return true
9571+
}
9572+
9573+
if (!isValidSemver(from) || !isValidSemver(to)) {
9574+
throw new Error(`Module "${module}" contains invalid semver versions from: ${from} to: ${to}`)
95679575
}
95689576

95699577
const diff = semverDiff(semverCoerce(from), semverCoerce(to))
@@ -9625,6 +9633,8 @@ module.exports = {
96259633
"use strict";
96269634

96279635

9636+
const semverValid = __nccwpck_require__(9601)
9637+
const semverCoerce = __nccwpck_require__(3466)
96289638
const core = __nccwpck_require__(2186)
96299639

96309640
const { getTargetInput } = __nccwpck_require__(5013)
@@ -9667,6 +9677,8 @@ exports.getInputs = () => ({
96679677
* Get a package name from a branch name.
96689678
* Dependabot branch names are in format "dependabot/npm_and_yarn/pkg-0.0.1"
96699679
* or "dependabot/github_actions/fastify/github-action-merge-dependabot-2.6.0"
9680+
* @param {String} branchName
9681+
* @returns Package name extracted from branch
96709682
*/
96719683
exports.getPackageName = (branchName) => {
96729684
const nameWithVersion = branchName.split('/').pop().split('-')
@@ -9680,6 +9692,34 @@ exports.getPackageName = (branchName) => {
96809692
return packageName
96819693
}
96829694

9695+
/**
9696+
* Checks if the string is a SHA1 commit hash.
9697+
* Usually github commit hashes are 7 chars long, but in case this change someday
9698+
* it's checking for the maximum length of a SHA1 hash (40 hexadecimal chars)
9699+
* @param {String} version
9700+
* @returns Boolean indicating whether version
9701+
*/
9702+
exports.isCommitHash = function(version) {
9703+
return /^[a-f0-9]{5,40}$/.test(version)
9704+
}
9705+
9706+
/**
9707+
* Checks if a version is a valid semver version.
9708+
* Uses loose: true and replace `v`, `~`, `^` charactes to make function a bit
9709+
* less restrictive regarding the accepted inputs
9710+
* @param {String} version
9711+
* @returns Boolean indicating whether version is valid
9712+
*/
9713+
exports.isValidSemver = function (version) {
9714+
const isNumber = !isNaN(+version)
9715+
9716+
if (isNumber) {
9717+
return semverValid(semverCoerce(version))
9718+
}
9719+
9720+
return semverValid(version.replace(/[\^~v]/g, ''), { loose: true })
9721+
}
9722+
96839723

96849724
/***/ }),
96859725

@@ -9815,7 +9855,7 @@ module.exports = JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45,46],"valid"]
98159855
/***/ ((module) => {
98169856

98179857
"use strict";
9818-
module.exports = JSON.parse('{"name":"github-action-merge-dependabot","version":"3.1.4","description":"A GitHub action to automatically merge and approve Dependabot pull requests","main":"src/index.js","scripts":{"build":"ncc build src/index.js","lint":"eslint .","test":"tap","prepare":"husky install"},"author":{"name":"Salman Mitha","email":"SalmanMitha@gmail.com"},"contributors":["Simone Busoli <simone.busoli@nearform.com>"],"license":"MIT","repository":{"type":"git","url":"git+https://github.com/fastify/github-action-merge-dependabot.git"},"bugs":{"url":"https://github.com/fastify/github-action-merge-dependabot/issues"},"homepage":"https://github.com/fastify/github-action-merge-dependabot#readme","dependencies":{"@actions/core":"^1.6.0","@actions/github":"^5.0.1","actions-toolkit":"github:nearform/actions-toolkit","gitdiff-parser":"^0.2.2","semver":"^7.3.7"},"devDependencies":{"@vercel/ncc":"^0.33.4","eslint":"^8.14.0","husky":"^7.0.4","prettier":"^2.6.2","proxyquire":"^2.1.3","sinon":"^13.0.2","tap":"^16.1.0"}}');
9858+
module.exports = JSON.parse('{"name":"github-action-merge-dependabot","version":"3.1.4","description":"A GitHub action to automatically merge and approve Dependabot pull requests","main":"src/index.js","scripts":{"build":"ncc build src/index.js","lint":"eslint .","test":"tap test/**.test.js","prepare":"husky install"},"author":{"name":"Salman Mitha","email":"SalmanMitha@gmail.com"},"contributors":["Simone Busoli <simone.busoli@nearform.com>"],"license":"MIT","repository":{"type":"git","url":"git+https://github.com/fastify/github-action-merge-dependabot.git"},"bugs":{"url":"https://github.com/fastify/github-action-merge-dependabot/issues"},"homepage":"https://github.com/fastify/github-action-merge-dependabot#readme","dependencies":{"@actions/core":"^1.7.0","@actions/github":"^5.0.1","actions-toolkit":"github:nearform/actions-toolkit","gitdiff-parser":"^0.2.2","semver":"^7.3.7"},"devDependencies":{"@vercel/ncc":"^0.33.4","eslint":"^8.14.0","husky":"^7.0.4","prettier":"^2.6.2","proxyquire":"^2.1.3","sinon":"^13.0.2","tap":"^16.1.0"}}');
98199859

98209860
/***/ })
98219861

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"scripts": {
77
"build": "ncc build src/index.js",
88
"lint": "eslint .",
9-
"test": "tap",
9+
"test": "tap test/**.test.js",
1010
"prepare": "husky install"
1111
},
1212
"author": {

src/action.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const toolkit = require('actions-toolkit')
99
const packageInfo = require('../package.json')
1010
const { githubClient } = require('./github-client')
1111
const { logInfo, logWarning, logError } = require('./log')
12-
const { getInputs, getPackageName } = require('./util')
12+
const { isValidSemver, isCommitHash, getInputs, getPackageName } = require('./util')
1313
const { targetOptions } = require('./getTargetInput')
1414
const {
1515
getModuleVersionChanges,
@@ -94,6 +94,10 @@ function isAMajorReleaseBump(change) {
9494
const from = change.delete
9595
const to = change.insert
9696

97+
if (isCommitHash(from) && isCommitHash(to)) {
98+
return false
99+
}
100+
97101
const diff = semverDiff(semverCoerce(from), semverCoerce(to))
98102
return diff === targetOptions.major
99103
}
@@ -105,9 +109,16 @@ function parsePrTitle(pullRequest) {
105109
if (!match) {
106110
throw new Error('Error while parsing PR title, expected: `bump <package> from <old-version> to <new-version>`')
107111
}
108-
const [, oldVersion, newVersion] = match
109112

110113
const packageName = getPackageName(pullRequest.head.ref)
111114

112-
return { [packageName]: { delete: semverCoerce(oldVersion).raw, insert: semverCoerce(newVersion).raw } }
115+
const [, oldVersion, newVersion] = match.map(t => t.replace(/`/g, ''))
116+
const isValid = isValidSemver(oldVersion) && isValidSemver(newVersion)
117+
118+
return {
119+
[packageName]: {
120+
delete: isValid ? semverCoerce(oldVersion)?.raw : oldVersion,
121+
insert: isValid ? semverCoerce(newVersion)?.raw : newVersion
122+
}
123+
}
113124
}

src/moduleVersionChanges.js

+7-10
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,13 @@
22

33
const semverDiff = require('semver/functions/diff')
44
const semverCoerce = require('semver/functions/coerce')
5-
const semverValid = require('semver/functions/valid')
65
const { parse } = require('gitdiff-parser')
6+
const { isCommitHash, isValidSemver } = require('./util')
77

88
const { semanticVersionOrder } = require('./getTargetInput')
9-
const { logWarning } = require('./log')
109

1110
const expression = /"([^\s]+)":\s*"([^\s]+)"/
1211

13-
function hasBadChars(version) {
14-
// recognize submodules title likes 'Bump dotbot from `aa93350` to `acaaaac`'
15-
return /^[^^~*-0-9+x]/.test(version)
16-
}
17-
1812
const checkModuleVersionChanges = (moduleChanges, target) => {
1913
for (const module in moduleChanges) {
2014
const from = moduleChanges[module].delete
@@ -24,9 +18,12 @@ const checkModuleVersionChanges = (moduleChanges, target) => {
2418
return false
2519
}
2620

27-
if ((!semverValid(from) && hasBadChars(from)) || (!semverValid(to) && hasBadChars(to))) {
28-
logWarning(`Module "${module}" contains invalid semver versions from: ${from} to: ${to}`)
29-
return false
21+
if (isCommitHash(from) && isCommitHash(to)) {
22+
return true
23+
}
24+
25+
if (!isValidSemver(from) || !isValidSemver(to)) {
26+
throw new Error(`Module "${module}" contains invalid semver versions from: ${from} to: ${to}`)
3027
}
3128

3229
const diff = semverDiff(semverCoerce(from), semverCoerce(to))

src/util.js

+32
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict'
22

3+
const semverValid = require('semver/functions/valid')
4+
const semverCoerce = require('semver/functions/coerce')
35
const core = require('@actions/core')
46

57
const { getTargetInput } = require('./getTargetInput')
@@ -42,6 +44,8 @@ exports.getInputs = () => ({
4244
* Get a package name from a branch name.
4345
* Dependabot branch names are in format "dependabot/npm_and_yarn/pkg-0.0.1"
4446
* or "dependabot/github_actions/fastify/github-action-merge-dependabot-2.6.0"
47+
* @param {String} branchName
48+
* @returns Package name extracted from branch
4549
*/
4650
exports.getPackageName = (branchName) => {
4751
const nameWithVersion = branchName.split('/').pop().split('-')
@@ -54,3 +58,31 @@ exports.getPackageName = (branchName) => {
5458

5559
return packageName
5660
}
61+
62+
/**
63+
* Checks if the string is a SHA1 commit hash.
64+
* Usually github commit hashes are 7 chars long, but in case this change someday
65+
* it's checking for the maximum length of a SHA1 hash (40 hexadecimal chars)
66+
* @param {String} version
67+
* @returns Boolean indicating whether version
68+
*/
69+
exports.isCommitHash = function(version) {
70+
return /^[a-f0-9]{5,40}$/.test(version)
71+
}
72+
73+
/**
74+
* Checks if a version is a valid semver version.
75+
* Uses loose: true and replace `v`, `~`, `^` charactes to make function a bit
76+
* less restrictive regarding the accepted inputs
77+
* @param {String} version
78+
* @returns Boolean indicating whether version is valid
79+
*/
80+
exports.isValidSemver = function (version) {
81+
const isNumber = !isNaN(+version)
82+
83+
if (isNumber) {
84+
return semverValid(semverCoerce(version))
85+
}
86+
87+
return semverValid(version.replace(/[\^~v]/g, ''), { loose: true })
88+
}

0 commit comments

Comments
 (0)