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

feat: use upstream release-please #334

Merged
merged 2 commits into from
Nov 28, 2023
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
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,23 @@ trivial to swap out this content directory for a different one as it is only
referenced in a single place in `lib/config.js`. However, it's not currently
possible to change this value at runtime, but that might become possible in
future versions of this package.

### Testing

The files `test/release/release-manager.js` and `test/release/release-please.js`
use recorded `nock` fixtures to generate snapshots. To update these fixtures run:

```sh
GITHUB_TOKEN=<YOUR_PAT> npm run test:record --- test/release/release-{please,manager}.js
```

If you only need to update fixtures for one, it's best to only run that single
test file.

#### `test/release/release-please.js`

This test file uses the repo `npm/npm-cli-release-please` to record its
fixtures. It expects `https://github.com/npm/npm-cli-release-please` to be
checked out in a sibling directory to this repo. It also needs the current
branch set to `template-oss-mock-testing-branch-do-not-delete` before the tests
are run.
2 changes: 0 additions & 2 deletions bin/release-manager.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env node

const { join } = require('path')
const core = require('@actions/core')
const { parseArgs } = require('util')
const ReleaseManager = require('../lib/release/release-manager')
Expand All @@ -10,7 +9,6 @@ ReleaseManager.run({
token: process.env.GITHUB_TOKEN,
repo: process.env.GITHUB_REPOSITORY,
cwd: process.cwd(),
lukekarrys marked this conversation as resolved.
Show resolved Hide resolved
pkg: require(join(process.cwd(), 'package.json')),
...parseArgs({
options: {
pr: { type: 'string' },
Expand Down
16 changes: 13 additions & 3 deletions lib/content/release-please-config-json.hbs
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
{
"separate-pull-requests": {{{ del }}},
"plugins": {{#if isMonoPublic }}["node-workspace"]{{ else }}{{{ del }}}{{/if}},
"exclude-packages-from-root": true,
{{#if isMonoPublic }}
"plugins": [
"node-workspace",
"node-workspace-format"
],
{{/if}}
"exclude-packages-from-root": {{{ del }}},
"group-pull-request-title-pattern": "chore: release ${version}",
"pull-request-title-pattern": "chore: release${component} ${version}",
"changelog-sections": {{{ json changelogTypes }}},
"prerelease-type": "pre",
"packages": {
"{{ pkgPath }}": {
{{#if isRoot}}"package-name": ""{{/if}}
{{#if isRoot}}
"package-name": ""{{#if workspacePaths}},
"exclude-paths": {{{ json workspacePaths }}}
{{/if}}
{{/if}}
}
}
}
6 changes: 3 additions & 3 deletions lib/release/changelog.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { link, code, specRe, list, dateFmt, makeGitHubUrl } = require('./util')
const { link, code, wrapSpecs, list, formatDate, makeGitHubUrl } = require('./util')

class Changelog {
static BREAKING = 'breaking'
Expand All @@ -11,7 +11,7 @@ class Changelog {
}

constructor ({ version, url, sections }) {
this.#title = `## ${url ? link(version, url) : version} (${dateFmt()})`
this.#title = `## ${url ? link(version, url) : version} (${formatDate()})`
for (const section of sections) {
this.#types.add(section.type)
this.#titles[section.type] = section.section
Expand Down Expand Up @@ -136,7 +136,7 @@ class ChangelogNotes {

// The title of the commit, with the optional scope as a prefix
const scope = commit.scope && `${commit.scope}:`
const subject = commit.bareMessage.replace(specRe, code('$1'))
const subject = wrapSpecs(commit.bareMessage)
entry.push([scope, subject].filter(Boolean).join(' '))

// A list og the authors github handles or names
Expand Down
107 changes: 107 additions & 0 deletions lib/release/node-workspace-format.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
const localeCompare = require('@isaacs/string-locale-compare')('en')
const { ManifestPlugin } = require('release-please/build/src/plugin.js')
const { addPath } = require('release-please/build/src/plugins/workspace.js')
const { TagName } = require('release-please/build/src/util/tag-name.js')
const { ROOT_PROJECT_PATH } = require('release-please/build/src/manifest.js')
const { DEPS, link, wrapSpecs } = require('./util.js')

const WORKSPACE_MESSAGE = (name, version) => `${DEPS}(workspace): ${name}@${version}`
const WORKSPACE_SCOPE = /(?<scope>workspace): `?(?<name>\S+?)[@\s](?<version>\S+?)`?$/gm

module.exports = class extends ManifestPlugin {
static WORKSPACE_MESSAGE = WORKSPACE_MESSAGE

#releasesByPackage = new Map()
#pathsByComponent = new Map()

async preconfigure (strategiesByPath) {
// First build a list of all releases that will happen based on
// the conventional commits
for (const path in strategiesByPath) {
const component = await strategiesByPath[path].getComponent()
const packageName = await await strategiesByPath[path].getDefaultPackageName()
this.#pathsByComponent.set(component, path)
this.#releasesByPackage.set(packageName, { path, component })
}

return strategiesByPath
}

run (candidates) {
this.#rewriteWorkspaceChangelogItems(candidates)
this.#sortReleases(candidates)
return candidates
}

// I don't like how release-please formats workspace changelog entries
// so this rewrites them to look like the rest of our changelog. This can't
// be part of the changelog plugin since they are written after that by the
// node-workspace plugin. A possible PR to release-please could add an option
// to customize these or run them through the changelog notes generator.
#rewriteWorkspaceChangelogItems (candidates) {
for (const candidate of candidates) {
for (const release of candidate.pullRequest.body.releaseData) {
// Update notes with a link to each workspaces release notes
// now that we have all of the releases in a single pull request
release.notes =
release.notes.replace(WORKSPACE_SCOPE, (...args) => {
const { scope, name, version } = args.pop()
const { path, component } = this.#releasesByPackage.get(name)
const { tagSeparator, includeVInTag } = this.repositoryConfig[path]
const { repository: { owner, repo } } = this.github
const tag = new TagName(version, component, tagSeparator, includeVInTag).toString()
const url = `https://github.com/${owner}/${repo}/releases/tag/${tag}`
return `${link(scope, url)}: ${wrapSpecs(`${name}@${version}`)}`
})

// remove the other release please dependencies list which always starts with
// the following line and then each line is indented. so we search for the line
// and remove and indented lines until the next non indented line.
let foundRemoveStart = false
let foundRemoveEnd = false
release.notes = release.notes
.split('\n')
.filter((line) => {
if (line === '* The following workspace dependencies were updated') {
foundRemoveStart = true
} else if (foundRemoveStart && !foundRemoveEnd) {
// TODO: test when inserted dependencies is not the last thing in the changelog
/* istanbul ignore next */
if (!line || !line.startsWith(' ')) {
foundRemoveEnd = true
}
}
// If we found the start, remove all lines until we've found the end
return foundRemoveStart ? foundRemoveEnd : true
})
.join('\n')

// Find the associated changelog and update that too
const path = this.#pathsByComponent.get(release.component)
for (const update of candidate.pullRequest.updates) {
if (update.path === addPath(path, 'CHANGELOG.md')) {
update.updater.changelogEntry = release.notes
}
}
}
}
}

// Sort root release to the top of the pull request
// release please pre sorts based on graph order so
#sortReleases (candidates) {
for (const candidate of candidates) {
candidate.pullRequest.body.releaseData.sort((a, b) => {
const aPath = this.#pathsByComponent.get(a.component)
const bPath = this.#pathsByComponent.get(b.component)
if (aPath === ROOT_PROJECT_PATH) {
return -1
}
if (bPath === ROOT_PROJECT_PATH) {
return 1
}
return localeCompare(aPath, bPath)
})
}
}
}
Loading