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

Minimize semver logic + tests #331

Merged
merged 2 commits into from
May 13, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Test

on:
push:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- run: npm ci
- run: npm test
10 changes: 10 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,16 @@
],
"args": ["actions-yml"],
"program": "${workspaceFolder}/bin.js"
},
{
"type": "pwa-node",
"request": "launch",
"name": "test",
"skipFiles": [
"<node_internals>/**"
],
"args": [],
"program": "${workspaceFolder}/test/test.js"
}
]
}
10 changes: 10 additions & 0 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ The semver increment level defaults to `patch` but can be set to `major`, `minor

**pr-release** infers the current version by checking multiple sources (package.json, release PR header, git tag, prior release) and always takes the highest found version as the authoritative one. So if you want to override the generated version, just manually update the release PR title to be a normal non-semver prerelease and merge. From then on, versions will not be prerelease incremented.

### The auto generated versions looks weird...

By default pr-release tries to capture the full scope/risk of a release by including every patch/minor/major increment. This is especially useful for versioning applications and gauging the scope/risk of a release at a glance.

For libraries you may want to use the `--minimize-semver-changes` option which makes the minimum necessary change to the semver to still satisfy semver range comparisons.

For example, if the previous version was `2.0.4` and the release candidate has 6 patches, 3 minors and 0 majors. The next version would be calculated as `2.1.0` as there was at least 1 minor. 1 minor constitutes a minor version update and no other version information is required, that is why the patch section is zeroed out. Additionally a minor jump from `2.1.0` or `2.6.0` is still a minor update, so it is not necessary to include the amount of minor jumps.

With the default settings the version would be calculated as `2.6.7` as it is a simple addition of semver increment levels to the base version.

### How do I configure my Github actions to use `pr-release`?

Run `npx pr-release actions-yml`. It will generate all the yml files you need to use all the features of `pr-release`.
Expand Down
79 changes: 66 additions & 13 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,17 +207,33 @@ async function updateDocs(){
await fs.writeFile('README.md', newReadme, 'utf8')
}

function getNextVersion({ recentBranches, version }){
export function getNextVersion({
recentBranches, version, minimizeSemverChange=false
}){
let severityIdx = groupBy( x => prSeverity(x), recentBranches )

// todo-james
let noPrereleaseBase; {
const parsed = semver.parse(version)
parsed.prerelease = []
noPrereleaseBase = parsed.format()
}

let nextVersion; {
nextVersion = semver.clean(version)
nextVersion = semver.clean(noPrereleaseBase)

for(let level of ['major', 'minor', 'patch', 'prerelease']){

let levelOrder = ['major', 'minor', 'patch', 'prerelease']
if( minimizeSemverChange ) {
levelOrder = ['patch', 'minor', 'major', 'prerelease']
}
outer: for(let level of levelOrder){
let n = severityIdx[level] ? severityIdx[level].length : 0
for( let i = 0; i < n; i++ ) {
nextVersion = semver.inc(nextVersion, level)

if ( minimizeSemverChange ) {
continue outer;
}
}
}

Expand All @@ -237,7 +253,7 @@ function getNextVersion({ recentBranches, version }){
return nextVersion
}

async function inferVersionExternal(){
async function inferVersionExternal({ minimizeSemverChange=false }={}){
let [owner,repo] = process.env.GITHUB_REPOSITORY.split('/')

const lastRelease = await getLastRelease({ owner, repo })
Expand All @@ -248,7 +264,9 @@ async function inferVersionExternal(){

const version =
await getNextVersion({
recentBranches, version: currentVersion.version
recentBranches
, version: currentVersion.version
, minimizeSemverChange
})

console.log('v'+version)
Expand Down Expand Up @@ -372,7 +390,11 @@ async function extractChangelog(options){
// this version is the published version + branch inferred versions
// it ignores the version set in the PR description
let nextVersion =
await getNextVersion({ recentBranches, version })
await getNextVersion({
recentBranches
, version
, minimizeSemverChange: options.minimizeSemverChange
})

let contributors =
[...new Set(recentBranches.map( x => x.user.login))]
Expand Down Expand Up @@ -589,10 +611,10 @@ async function merge(options){
// There may not be one, and if there is, there may already be a tag for that release

const changelogOut = typeof options.changelog == 'string' ? { out: options.changelog } : {}

const { minimizeSemverChange } = options
let out = options.changelog
? await externalChangelog({ ...changelogOut })
: await extractChangelog({})
? await externalChangelog({ ...changelogOut, minimizeSemverChange })
: await extractChangelog({ minimizeSemverChange })

let { nextVersion } = out
let [owner,repo] = process.env.GITHUB_REPOSITORY.split('/')
Expand Down Expand Up @@ -1040,7 +1062,11 @@ async function pr(options){

let severityIdx = groupBy( x => prSeverity(x), recentBranches )

let nextVersion = getNextVersion({ recentBranches, version })
let nextVersion = getNextVersion({
recentBranches
, version
, minimizeSemverChange: options.minimizeSemverChange
})

let defaultTitle = `Release - v${nextVersion}`

Expand Down Expand Up @@ -1658,6 +1684,7 @@ async function inferPreReleaseExternal({
, 'package-path': packagePath='package.json'
, publish=false
, apply=publish
, minimizeSemverChange
}={}){

let [owner,repo] = process.env.GITHUB_REPOSITORY.split('/')
Expand Down Expand Up @@ -1693,9 +1720,13 @@ async function inferPreReleaseExternal({
await inferVersion({ owner, repo, lastRelease })

let nextVersion =
await getNextVersion({ recentBranches: openBranches, version })
await getNextVersion({
recentBranches: openBranches
, version
, minimizeSemverChange
})


// todo-james move into getNextVersion
if(!semver.prerelease(nextVersion)){
x = nextVersion+'-'+preid+'.0'
} else {
Expand Down Expand Up @@ -1761,6 +1792,11 @@ subcommands:

Do not thank contributors in changelog or release PR

${blue(`--minimize-semver-changes`)}

Make the minimum change to the semver instead of including an increment
per pr merged.

${magenta(`merge`)}

Commits updated changelog and creates new npm/github/etc release.
Expand All @@ -1784,6 +1820,11 @@ subcommands:

${magenta('filepath')} defaults to changelog.md

${blue(`--minimize-semver-changes`)}

Make the minimum change to the semver instead of including an increment
per pr merged.

${magenta(`actions-yml`)}

Scaffold Github actions yml files
Expand Down Expand Up @@ -1830,6 +1871,11 @@ subcommands:
This is the same function used to generate the versions in the title
header and body but as a standalone command.

${blue(`--minimize-semver-changes`)}

Make the minimum change to the semver instead of including an increment
per pr merged.

${red(`Advanced Commands`)}
${red(`-----------------`)}

Expand Down Expand Up @@ -1876,6 +1922,12 @@ ${magenta(`infer-prerelease`)}
${blue(`--publish`)} will publish to the same release channel as preid (defaults to next)

${blue(`--publish=alpha`)} will publish to the specified channel, in this case alpha


${blue(`--minimize-semver-changes`)}

Make the minimum change to the semver instead of including an increment
per pr merged.
`

let [subcommand] = argv._
Expand Down Expand Up @@ -1928,6 +1980,7 @@ export async function main(){
if( preflights[subcommand] ) await preflight(argv._, argv)

argv = { contributors: true, thanks: true, ...argv }
argv = { 'minimize-semver-change': argv.minimizeSemverChange, ...argv }

await f(argv, ...argv._)
} catch (e) {
Expand Down
Loading