Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tag prefix #1092

Merged
merged 5 commits into from Mar 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -114,6 +114,7 @@ You can configure Release Drafter using the following key in your `.github/relea
| `category-template` | Optional | The template to use for each category. Use [category template variables](#category-template-variables) to insert values. Default: `"## $TITLE"`. |
| `name-template` | Optional | The template for the name of the draft release. For example: `"v$NEXT_PATCH_VERSION"`. |
| `tag-template` | Optional | The template for the tag of the draft release. For example: `"v$NEXT_PATCH_VERSION"`. |
| `tag-prefix` | Optional | A known prefix used to filter release tags. For matching tags, this prefix is stripped before attempting to parse the version. Default: `""` |
| `version-template` | Optional | The template to use when calculating the next version number for the release. Useful for projects that don't use semantic versioning. Default: `"$MAJOR.$MINOR.$PATCH"` |
| `change-template` | Optional | The template to use for each merged pull request. Use [change template variables](#change-template-variables) to insert values. Default: `"* $TITLE (#$NUMBER) @$AUTHOR"`. |
| `change-title-escapes` | Optional | Characters to escape in `$TITLE` when inserting into `change-template` so that they are not interpreted as Markdown format characters. Default: `""` |
Expand All @@ -131,6 +132,7 @@ You can configure Release Drafter using the following key in your `.github/relea
| `version-resolver` | Optional | Adjust the `$RESOLVED_VERSION` variable using labels. Refer to [Version Resolver](#version-resolver) to learn more about this |
| `commitish` | Optional | The release target, i.e. branch or commit it should point to. Default: the ref that release-drafter runs for, e.g. `refs/heads/master` if configured to run on pushes to `master`. |
| `filter-by-commitish` | Optional | Filter previous releases to consider only those with the target matching `commitish`. Default: `false`. |
| `include-paths` | Optional | Restrict pull requests included in the release notes to only the pull requests that modified any of the paths in this array. Supports files and directories. Default: `[]` |

Release Drafter also supports [Probot Config](https://github.com/probot/probot-config), if you want to store your configuration files in a central repository. This allows you to share configurations between projects, and create a organization-wide configuration file by creating a repository named `.github` with the file `.github/release-drafter.yml`.

Expand Down
38 changes: 29 additions & 9 deletions dist/index.js
Expand Up @@ -128605,12 +128605,16 @@ module.exports = (app, { getRouter }) => {
}

const targetCommitish = commitish || config['commitish'] || ref
const filterByCommitish = config['filter-by-commitish']
const {
'filter-by-commitish': filterByCommitish,
'tag-prefix': tagPrefix,
} = config

const { draftRelease, lastRelease } = await findReleases({
context,
targetCommitish,
filterByCommitish,
tagPrefix,
})

const { commits, pullRequests: mergedPullRequests } =
Expand Down Expand Up @@ -128997,6 +129001,7 @@ const { SORT_BY, SORT_DIRECTIONS } = __nccwpck_require__(11940)
const DEFAULT_CONFIG = Object.freeze({
'name-template': '',
'tag-template': '',
'tag-prefix': '',
'change-template': `* $TITLE (#$NUMBER) @$AUTHOR`,
'change-title-escapes': '',
'no-changes-template': `* No changes`,
Expand Down Expand Up @@ -129134,6 +129139,7 @@ const findReleases = async ({
context,
targetCommitish,
filterByCommitish,
tagPrefix,
}) => {
let releaseCount = 0
let releases = await context.octokit.paginate(
Expand All @@ -129156,12 +129162,15 @@ const findReleases = async ({
// `refs/heads/branch` and `branch` are the same thing in this context
const headRefRegex = /^refs\/heads\//
const targetCommitishName = targetCommitish.replace(headRefRegex, '')
const filteredReleases = filterByCommitish
const commitishFilteredReleases = filterByCommitish
? releases.filter(
(r) =>
targetCommitishName === r.target_commitish.replace(headRefRegex, '')
)
: releases
const filteredReleases = tagPrefix
? commitishFilteredReleases.filter((r) => r.tag_name.startsWith(tagPrefix))
: commitishFilteredReleases
const sortedPublishedReleases = sortReleases(
filteredReleases.filter((r) => !r.draft)
)
Expand Down Expand Up @@ -129428,7 +129437,8 @@ const generateReleaseInfo = ({
// Use the first override parameter to identify
// a version, from the most accurate to the least
version || tag || name,
resolveVersionKeyIncrement(mergedPullRequests, config)
resolveVersionKeyIncrement(mergedPullRequests, config),
config['tag-prefix']
)

if (versionInfo) {
Expand Down Expand Up @@ -129575,6 +129585,10 @@ const schema = (context) => {
.allow('')
.default(DEFAULT_CONFIG['name-template']),

'tag-prefix': Joi.string()
.allow('')
.default(DEFAULT_CONFIG['tag-prefix']),

'tag-template': Joi.string()
.allow('')
.default(DEFAULT_CONFIG['tag-template']),
Expand Down Expand Up @@ -130077,24 +130091,30 @@ const toSemver = (version) => {
return semver.coerce(version)
}

const coerceVersion = (input) => {
const coerceVersion = (input, tagPrefix) => {
if (!input) {
return
}

const stripTag = (input) =>
tagPrefix && input.startsWith(tagPrefix)
? input.slice(tagPrefix.length)
: input

return typeof input === 'object'
? toSemver(input.tag_name) || toSemver(input.name)
: toSemver(input)
? toSemver(stripTag(input.tag_name)) || toSemver(stripTag(input.name))
: toSemver(stripTag(input))
}

const getVersionInfo = (
release,
template,
inputVersion,
versionKeyIncrement
versionKeyIncrement,
tagPrefix
) => {
const version = coerceVersion(release)
inputVersion = coerceVersion(inputVersion)
const version = coerceVersion(release, tagPrefix)
inputVersion = coerceVersion(inputVersion, tagPrefix)

if (!version && !inputVersion) {
return defaultVersionInfo
Expand Down
6 changes: 5 additions & 1 deletion index.js
Expand Up @@ -159,12 +159,16 @@ module.exports = (app, { getRouter }) => {
}

const targetCommitish = commitish || config['commitish'] || ref
const filterByCommitish = config['filter-by-commitish']
const {
'filter-by-commitish': filterByCommitish,
'tag-prefix': tagPrefix,
} = config

const { draftRelease, lastRelease } = await findReleases({
context,
targetCommitish,
filterByCommitish,
tagPrefix,
})

const { commits, pullRequests: mergedPullRequests } =
Expand Down
1 change: 1 addition & 0 deletions lib/default-config.js
Expand Up @@ -3,6 +3,7 @@ const { SORT_BY, SORT_DIRECTIONS } = require('./sort-pull-requests')
const DEFAULT_CONFIG = Object.freeze({
'name-template': '',
'tag-template': '',
'tag-prefix': '',
'change-template': `* $TITLE (#$NUMBER) @$AUTHOR`,
'change-title-escapes': '',
'no-changes-template': `* No changes`,
Expand Down
9 changes: 7 additions & 2 deletions lib/releases.js
Expand Up @@ -24,6 +24,7 @@ const findReleases = async ({
context,
targetCommitish,
filterByCommitish,
tagPrefix,
}) => {
let releaseCount = 0
let releases = await context.octokit.paginate(
Expand All @@ -46,12 +47,15 @@ const findReleases = async ({
// `refs/heads/branch` and `branch` are the same thing in this context
const headRefRegex = /^refs\/heads\//
const targetCommitishName = targetCommitish.replace(headRefRegex, '')
const filteredReleases = filterByCommitish
const commitishFilteredReleases = filterByCommitish
? releases.filter(
(r) =>
targetCommitishName === r.target_commitish.replace(headRefRegex, '')
)
: releases
const filteredReleases = tagPrefix
? commitishFilteredReleases.filter((r) => r.tag_name.startsWith(tagPrefix))
: commitishFilteredReleases
const sortedPublishedReleases = sortReleases(
filteredReleases.filter((r) => !r.draft)
)
Expand Down Expand Up @@ -318,7 +322,8 @@ const generateReleaseInfo = ({
// Use the first override parameter to identify
// a version, from the most accurate to the least
version || tag || name,
resolveVersionKeyIncrement(mergedPullRequests, config)
resolveVersionKeyIncrement(mergedPullRequests, config),
config['tag-prefix']
)

if (versionInfo) {
Expand Down
4 changes: 4 additions & 0 deletions lib/schema.js
Expand Up @@ -39,6 +39,10 @@ const schema = (context) => {
.allow('')
.default(DEFAULT_CONFIG['name-template']),

'tag-prefix': Joi.string()
.allow('')
.default(DEFAULT_CONFIG['tag-prefix']),

'tag-template': Joi.string()
.allow('')
.default(DEFAULT_CONFIG['tag-template']),
Expand Down
18 changes: 12 additions & 6 deletions lib/versions.js
Expand Up @@ -136,24 +136,30 @@ const toSemver = (version) => {
return semver.coerce(version)
}

const coerceVersion = (input) => {
const coerceVersion = (input, tagPrefix) => {
if (!input) {
return
}

const stripTag = (input) =>
tagPrefix && input.startsWith(tagPrefix)
? input.slice(tagPrefix.length)
: input

return typeof input === 'object'
? toSemver(input.tag_name) || toSemver(input.name)
: toSemver(input)
? toSemver(stripTag(input.tag_name)) || toSemver(stripTag(input.name))
: toSemver(stripTag(input))
}

const getVersionInfo = (
release,
template,
inputVersion,
versionKeyIncrement
versionKeyIncrement,
tagPrefix
) => {
const version = coerceVersion(release)
inputVersion = coerceVersion(inputVersion)
const version = coerceVersion(release, tagPrefix)
inputVersion = coerceVersion(inputVersion, tagPrefix)

if (!version && !inputVersion) {
return defaultVersionInfo
Expand Down
12 changes: 12 additions & 0 deletions schema.json
Expand Up @@ -47,6 +47,18 @@
}
]
},
"tag-prefix": {
"anyOf": [
{
"type": "string",
"enum": [""]
},
{
"default": "",
"type": "string"
}
]
},
"tag-template": {
"anyOf": [
{
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/config/config-with-tag-prefix.yml
@@ -0,0 +1,7 @@
name-template: 'static-tag-prefix-v$RESOLVED_VERSION 🌈'
tag-template: 'static-tag-prefix-v$RESOLVED_VERSION'
tag-prefix: static-tag-prefix-v
template: |
## Previous release

$PREVIOUS_TAG
52 changes: 52 additions & 0 deletions test/index.test.js
Expand Up @@ -2831,6 +2831,58 @@ describe('release-drafter', () => {
})
})

describe('with tag-prefix', () => {
it('gets the version from the tag, stripping the prefix', async () => {
getConfigMock('config-with-tag-prefix.yml')
// Explicitly include a RC suffix in order to differentiate the
// behaviour of semver.parse vs semver.coerce in versions.js
//
// We expect the release to be 2.1.4, not 2.1.5
const alteredReleasePayload = {
...releasePayload,
tag_name: 'static-tag-prefix-v2.1.4-RC3',
}

nock('https://api.github.com')
.post('/graphql', (body) =>
body.query.includes('query findCommitsWithAssociatedPullRequests')
)
.reply(200, graphqlCommitsNoPRsPayload)

nock('https://api.github.com')
.get('/repos/toolmantim/release-drafter-test-project/releases')
.query(true)
.reply(200, [alteredReleasePayload])
.post(
'/repos/toolmantim/release-drafter-test-project/releases',
(body) => {
expect(body).toMatchInlineSnapshot(`
Object {
"body": "## Previous release

static-tag-prefix-v2.1.4-RC3
",
"draft": true,
"name": "static-tag-prefix-v2.1.4 🌈",
"prerelease": false,
"tag_name": "static-tag-prefix-v2.1.4",
"target_commitish": "refs/heads/master",
}
`)
return true
}
)
.reply(200, alteredReleasePayload)

await probot.receive({
name: 'push',
payload: pushPayload,
})

expect.assertions(1)
})
})

describe('with custom version resolver', () => {
it('uses correct default when no labels exist', async () => {
getConfigMock('config-with-custom-version-resolver-none.yml')
Expand Down