Skip to content

Commit

Permalink
feat: provide tagFormat configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
antongolub committed Sep 19, 2023
1 parent 02e7409 commit c405454
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 37 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,19 @@ Note, [npm-package-name charset](https://www.npmjs.com/package/validate-npm-pack
'2022.6.13-examplecom.v1.0.0.ZXhhbXBsZS5jb20-f1'
// date name ver b64 format
```
Anyway, it's still possible to override the default config by `tagFormat` option:
| tagFormat | Example |
|-----------|------------------------------------------------------|
| f0 | 2022.6.22-qiwi.pijma-native.v1.0.0-beta.0+foo.bar-f0 |
| f1 | 2022.6.13-examplecom.v1.0.0.ZXhhbXBsZS5jb20-f1 |
| lerna | @qiwi/[email protected] |
| pure | 1.2.3-my.package |
### Meta
Each release stores its result into the `meta` branch.
Each release pushes its result to the `meta` branch.
`2022-6-26-semrel-extra-zxbr-test-c-1-3-1-f0.json`
```json
{
Expand Down
10 changes: 8 additions & 2 deletions src/main/js/analyze.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ export const analyze = async (pkg) => {
)
pkg.preversion = pre && pkg.version
pkg.manifest.version = pkg.version
pkg.tag = releaseType ? formatTag({name: pkg.name, version: pkg.version}) : null
pkg.tag = releaseType ? formatTag({name: pkg.name, version: pkg.version, format: pkg.config.tagFormat}) : null

log({pkg})('semantic changes', changes, 'nextVersion', pkg.version, 'latestVersion', latestVersion)
log({pkg})(
'semantic changes', changes,
'releaseType', releaseType,
'prevVersion', latestVersion,
'nextVersion', pkg.version,
'nextTag', pkg.tag
)
}

export const releaseSeverityOrder = ['major', 'minor', 'patch']
Expand Down
3 changes: 1 addition & 2 deletions src/main/js/changelog.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ export const pushChangelog = queuefy(async (pkg) => {
})

export const formatReleaseNotes = async (pkg) => {
const {name, version, absPath: cwd, config: {ghBasicAuth: basicAuth}} = pkg
const {name, version, tag = formatTag({name, version}), absPath: cwd, config: {ghBasicAuth: basicAuth}} = pkg
const {repoPublicUrl} = await getRepo(cwd, {basicAuth})
const tag = formatTag({name, version})
const releaseDiffRef = `## [${name}@${version}](${repoPublicUrl}/compare/${pkg.latest.tag?.ref}...${tag}) (${new Date().toISOString().slice(0, 10)})`
const releaseDetails = Object.values(pkg.changes
.reduce((acc, {group, subj, short, hash}) => {
Expand Down
3 changes: 1 addition & 2 deletions src/main/js/gh.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ export const ghRelease = async (pkg) => {
log({pkg})('create gh release')

const now = Date.now()
const {name, version, absPath: cwd} = pkg
const {name, version, absPath: cwd, tag = formatTag({name, version})} = pkg
const {repoName} = await getRepo(cwd, {basicAuth})
const tag = formatTag({name, version})
const releaseNotes = await formatReleaseNotes(pkg)
const releaseData = JSON.stringify({
name: tag,
Expand Down
89 changes: 64 additions & 25 deletions src/main/js/meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import {fetchRepo, pushCommit, getTags as getGitTags, pushTag} from './git.js'
import {fetchManifest} from './npm.js'

export const pushReleaseTag = async (pkg) => {
const {name, version, config: {gitCommitterEmail, gitCommitterName}} = pkg
const tag = formatTag({name, version})
const {name, version, tag = formatTag({name, version}),config: {gitCommitterEmail, gitCommitterName}} = pkg
const cwd = pkg.context.git.root

pkg.context.git.tag = tag
Expand All @@ -21,8 +20,7 @@ export const pushReleaseTag = async (pkg) => {
export const pushMeta = queuefy(async (pkg) => {
log({pkg})('push artifact to branch \'meta\'')

const {name, version, absPath: cwd, config: {gitCommitterEmail, gitCommitterName, ghBasicAuth: basicAuth}} = pkg
const tag = formatTag({name, version})
const {name, version, tag = formatTag({name, version}), absPath: cwd, config: {gitCommitterEmail, gitCommitterName, ghBasicAuth: basicAuth}} = pkg
const to = '.'
const branch = 'meta'
const msg = `chore: release meta ${name} ${version}`
Expand Down Expand Up @@ -53,7 +51,10 @@ export const getLatest = async (pkg) => {
}
}

const isSafeName = n => /^(@?[a-z0-9-]+\/)?[a-z0-9-]+$/.test(n)

const f0 = {
name: 'f0',
parse(tag) {
if (!tag.endsWith('-f0')) return null

Expand All @@ -66,10 +67,10 @@ const f0 = {
const date = parseDateTag(_date)
const name = _name.includes('.') ? `@${_name.replace('.', '/')}` : _name

return {date, name, version, format: 'f0', ref: tag}
return {date, name, version, format: this.name, ref: tag}
},
format({name, date = new Date(), version}) {
if (!/^(@?[a-z0-9-]+\/)?[a-z0-9-]+$/.test(name) || !semver.valid(version)) return null
if (!isSafeName(name) || !semver.valid(version)) return null

const d = formatDateTag(date)
const n = name.replace('@', '').replace('/', '.')
Expand All @@ -79,6 +80,7 @@ const f0 = {
}

const f1 = {
name: 'f1',
parse(tag) {
if (!tag.endsWith('-f1')) return null

Expand All @@ -91,7 +93,7 @@ const f1 = {
const date = parseDateTag(_date)
const name = Buffer.from(b64, 'base64url').toString('utf8')

return {date, name, version, format: 'f1', ref: tag}
return {date, name, version, format: this.name, ref: tag}
},
format({name, date = new Date(), version}) {
if (!semver.valid(version)) return null
Expand All @@ -105,35 +107,72 @@ const f1 = {
}

const lerna = {
name: 'lerna',
parse(tag) {
const pattern = /^(@?[a-z0-9-]+(?:\/[a-z0-9-]+)?)@(v?\d+\.\d+\.\d+.*)/
const [, name, version] = pattern.exec(tag) || []

if (!semver.valid(version)) return null

return {name, version, format: 'lerna', ref: tag}
return {name, version, format: this.name, ref: tag}
},
// format({name, version}) {
// if (!semver.valid(version)) return null
//
// return `${name}@${version}`
// }
format({name, version}) {
if (!semver.valid(version)) return null

return `${name}@${version}`
}
}

// TODO
// const variants = [f0, f1]
// export const parseTag = (tag) => {
// for (const variant of variants) {
// const parsed = variant.parse(tag)
// if (parsed) return parsed
// }
//
// return null
// }
const pure = {
name: 'pure',
parse(tag) {
if (tag.endsWith('-f0') || tag.endsWith('-f1')) {
return null
}
const parsed = semver.parse(tag) || {}
const {prerelease} = parsed
if (!prerelease?.length) {
return null
}

const [n, o = ''] = prerelease.reverse()
const name = o === 'x' ? n : `@${o}/${n}`
const version = tag.slice(0, -1 - n.length - (o ? o.length + 1 : 0))

return {format: this.name, ref: tag, name, version}
},
format({name, version}) {
const parsed = semver.parse(version)
if (!parsed || !isSafeName(name)) {
return null
}
const {prerelease} = parsed
const [n, o] = name.slice(name[0] === '@' ? 1 : 0).split('/').reverse()
const extra = prerelease.length
? '.' + [o || 'x', n].join('.')
: '-' + [o, n].filter(Boolean).join('.')
return version + extra
}
}

const getFormatter = (tagFormat) => {
if (!tagFormat) {
return {
parse() {},
format() {}
}
}
const formatter = [f0, f1, pure, lerna].find(f => f.name === tagFormat)
if (!formatter) {
throw new Error(`Unsupported tag format: ${tagFormat}`)
}

return formatter
}

export const parseTag = (tag) => f0.parse(tag) || f1.parse(tag) || lerna.parse(tag) || null
export const parseTag = (tag) => f0.parse(tag) || f1.parse(tag) || lerna.parse(tag) || pure.parse(tag) || null

export const formatTag = (tag) => f0.format(tag) || f1.format(tag) || null
export const formatTag = (tag, tagFormat = tag.format) => getFormatter(tagFormat).format(tag) || f0.format(tag) || f1.format(tag) || null

export const getTags = async (cwd, ref = '') =>
(await getGitTags(cwd, ref))
Expand Down
17 changes: 12 additions & 5 deletions src/test/js/meta.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,18 +160,25 @@ test('formatTag() / parseTag()', () => {
version: '1.1.12',
format: 'lerna',
ref: '@qiwi/[email protected]'
},
true
}
],
[
'1.2.3-my.package',
{
name: '@my/package',
version: '1.2.3',
format: 'pure',
ref: '1.2.3-my.package'
}
]
]

cases.forEach(([tag, meta, parseonly]) => {
cases.forEach(([tag, meta]) => {
const parsed = parseTag(tag)
assert.equal(parsed, meta)

if (meta !== null && !parseonly) {
if (meta !== null) {
assert.is(formatTag(meta), tag)
assert.ok(semver.valid(tag))
}
})
})
Expand Down

0 comments on commit c405454

Please sign in to comment.