Add automatic naming of new draft releases

Closes #91
This commit is contained in:
Richard North
2018-12-03 09:06:59 +00:00
parent 88bf178f5b
commit b13722bf8d
7 changed files with 134 additions and 8 deletions

View File

@@ -1,6 +1,6 @@
const getConfig = require('probot-config')
const { isTriggerableBranch } = require('./lib/triggerable-branch')
const { findReleases, generateReleaseBody } = require('./lib/releases')
const { findReleases, generateReleaseInfo } = require('./lib/releases')
const { findCommits, findPullRequests } = require('./lib/commits')
const log = require('./lib/log')
@@ -30,20 +30,21 @@ module.exports = app => {
const { draftRelease, lastRelease } = await findReleases({ app, context })
const commits = await findCommits({ app, context, branch, lastRelease })
const mergedPullRequests = await findPullRequests({ app, context, commits })
const body = generateReleaseBody({ commits, config, lastRelease, mergedPullRequests })
const releaseInfo = generateReleaseInfo({ commits, config, lastRelease, mergedPullRequests })
if (!draftRelease) {
log({ app, context, message: 'Creating new draft release' })
await context.github.repos.createRelease(context.repo({
tag_name: '',
body: body,
name: releaseInfo.name,
tag_name: releaseInfo.tag,
body: releaseInfo.body,
draft: true
}))
} else {
log({ app, context, message: 'Updating existing draft release' })
await context.github.repos.editRelease(context.repo({
release_id: draftRelease.id,
body: body
body: releaseInfo.body
}))
}
})

View File

@@ -1,5 +1,6 @@
const compareVersions = require('compare-versions')
const { getVersionInfo } = require('./versions')
const log = require('./log')
const UNCATEGORIZED = 'UNCATEGORIZED'
@@ -92,7 +93,13 @@ const categorizePullRequests = (pullRequests, categories) => {
})
}
module.exports.generateReleaseBody = ({ commits, config, lastRelease, mergedPullRequests }) => {
const templateNextVersion = (template, nextVersions) => {
return template.replace('$NEXT_MAJOR_VERSION', nextVersions.incrementedMajor)
.replace('$NEXT_MINOR_VERSION', nextVersions.incrementedMinor)
.replace('$NEXT_PATCH_VERSION', nextVersions.incrementedPatch);
}
module.exports.generateReleaseInfo = ({ commits, config, lastRelease, mergedPullRequests }) => {
let body = config.template
const [categoriesConfig, orderedCategories] = getCategoriesConfig({ config })
@@ -130,5 +137,20 @@ module.exports.generateReleaseBody = ({ commits, config, lastRelease, mergedPull
body = body.replace('$CONTRIBUTORS', contributorsSentence({ commits, pullRequests: mergedPullRequests }))
return body
let name = config['default-release-name'] || '';
let tag = config['default-release-tag'] || '';
if (lastRelease) {
const versionInfo = getVersionInfo(lastRelease);
if (versionInfo) {
body = templateNextVersion(body, versionInfo);
name = templateNextVersion(name, versionInfo);
tag = templateNextVersion(tag, versionInfo);
}
}
return {
name,
tag,
body
}
}

29
lib/versions.js Normal file
View File

@@ -0,0 +1,29 @@
const semverRegex = /(\d+)\.(\d+)\.(\d+)/;
module.exports.getVersionInfo = (lastRelease) => {
const lastReleaseTag = lastRelease.tag_name;
const lastReleaseName = lastRelease.name;
let lastReleaseMatch;
lastReleaseMatch = lastReleaseTag.match(semverRegex);
if (! lastReleaseMatch) {
lastReleaseMatch = lastReleaseName.match(semverRegex);
}
if (! lastReleaseMatch) {
return undefined;
}
const major = (lastReleaseMatch[1] - 0);
const minor = (lastReleaseMatch[2] - 0);
const patch = (lastReleaseMatch[3] - 0);
return {
major,
minor,
patch,
incrementedMajor: `${major + 1}.0.0`,
incrementedMinor: `${major}.${minor + 1}.0`,
incrementedPatch: `${major}.${minor}.${patch + 1}`,
}
}

View File

@@ -38,7 +38,7 @@
]
},
"jest": {
"collectCoverage": true,
"collectCoverage": false,
"collectCoverageFrom": [
"index.js",
"lib/**"

View File

@@ -0,0 +1,3 @@
template: Placeholder with example. Automatically calculated values are next major=$NEXT_MAJOR_VERSION, minor=$NEXT_MINOR_VERSION, patch=$NEXT_PATCH_VERSION
default-release-name: "v$NEXT_PATCH_VERSION (Code name: Placeholder)"
default-release-tag: v$NEXT_PATCH_VERSION

View File

@@ -142,6 +142,32 @@ Previous tag: ''
)
})
it('makes next versions available as template placeholders', async () => {
github.repos.getContent = fn().mockReturnValueOnce(mockConfig('config-with-next-versioning.yml'))
github.repos.getReleases = fn().mockReturnValueOnce(Promise.resolve({ data:
[ require('./fixtures/release') ]
}))
github.repos.compareCommits = fn().mockReturnValueOnce(Promise.resolve({ data: {
commits: require('./fixtures/commits')
} }))
github.pullRequests.get = fn()
.mockReturnValueOnce(Promise.resolve(require('./fixtures/pull-request-1')))
.mockReturnValueOnce(Promise.resolve(require('./fixtures/pull-request-2')))
github.repos.createRelease = fn()
await app.receive({ name: 'push', payload: require('./fixtures/push') })
expect(github.repos.createRelease).toBeCalledWith(
expect.objectContaining({
body: `Placeholder with example. Automatically calculated values are next major=3.0.0, minor=2.1.0, patch=2.0.1`,
draft: true,
name: 'v2.0.1 (Code name: Placeholder)',
tag_name: 'v2.0.1'
})
)
})
describe('with custom changes-template config', () => {
it('creates a new draft using the template', async () => {
github.repos.getContent = fn().mockReturnValueOnce(mockConfig('config-with-changes-templates.yml'))

45
test/versions.test.js Normal file
View File

@@ -0,0 +1,45 @@
const { getVersionInfo } = require('../lib/versions')
describe('versions', () => {
it('extracts a version-like string from the last tag', () => {
const versionInfo = getVersionInfo({
tag_name: 'v10.0.3',
name: 'Some release'
});
expect(versionInfo.incrementedMajor).toEqual('11.0.0');
expect(versionInfo.incrementedMinor).toEqual('10.1.0');
expect(versionInfo.incrementedPatch).toEqual('10.0.4');
})
it('extracts a version-like string from the last release name', () => {
const versionInfo = getVersionInfo({
tag_name: 'notaproperversion',
name: '10.0.3'
});
expect(versionInfo.incrementedMajor).toEqual('11.0.0');
expect(versionInfo.incrementedMinor).toEqual('10.1.0');
expect(versionInfo.incrementedPatch).toEqual('10.0.4');
})
it('extracts a version-like string from the last tag instead of the release name, if conflicting', () => {
const versionInfo = getVersionInfo({
tag_name: '10.0.3',
name: '8.1.0'
});
expect(versionInfo.incrementedMajor).toEqual('11.0.0');
expect(versionInfo.incrementedMinor).toEqual('10.1.0');
expect(versionInfo.incrementedPatch).toEqual('10.0.4');
})
it('gives up if a semver version-like string cannot be found in either tag or release name', () => {
const versionInfo = getVersionInfo({
tag_name: '10.0',
name: 'not a proper version'
});
expect(versionInfo).toEqual(undefined);
})
})