Skip to content
Open
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
2 changes: 1 addition & 1 deletion lib/analyze-commits.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = function analyzeCommits (pluginConfig, context) {
const config = getConfig(pluginConfig, context)
debug('[Analyze commits] Effective config: %o', config)

const notes = ReleaseNotes.get(context, config.releaseNotes)
const notes = new ReleaseNotes(context, config.releaseNotes)

const releaseType = notes.getReleaseType(config.releaseRules)
if (releaseType) {
Expand Down
2 changes: 1 addition & 1 deletion lib/generate-notes.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = async function generateNotes (pluginConfig, context) {
const config = getConfig(pluginConfig, context)
debug('[Generate notes] Effective config: %o', config)

const notes = ReleaseNotes.get(context, config.releaseNotes)
const notes = new ReleaseNotes(context, config.releaseNotes)
await notes.updateContext(context)

logger.log('Release notes are generated.')
Expand Down
8 changes: 0 additions & 8 deletions lib/release-notes.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,4 @@ module.exports = class ReleaseNotes {
.replace(/\n{3,}/g, '\n\n') // allow a blank line
}
}

/**
* @return {ReleaseNotes}
*/
static get (context, releaseNotesOptions) {
ReleaseNotes._instance = ReleaseNotes._instance || new ReleaseNotes(context, releaseNotesOptions)
return ReleaseNotes._instance
}
}
12 changes: 0 additions & 12 deletions test/integration/analyze-commits.test.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
const test = require('ava')
const sinon = require('sinon')

const { analyzeCommits } = require('../..')
const ReleaseNotes = require('../../lib/release-notes')
const getContext = require('./fixtures/contexts')

const stub = sinon.stub(ReleaseNotes, 'get')
// to avoid singleton for tests
stub.callsFake(function (...args) {
return new ReleaseNotes(...args)
})

test.after(function () {
stub.restore()
})

const CASES = [
{
name: 'default config + common context w/o updates',
Expand Down
12 changes: 0 additions & 12 deletions test/integration/generate-notes.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
const test = require('ava')
const sinon = require('sinon')
const dateFormat = require('dateformat')

const { generateNotes } = require('../..')
const ReleaseNotes = require('../../lib/release-notes')
const getContext = require('./fixtures/contexts')

const { readFileSync } = require('fs')
Expand All @@ -18,16 +16,6 @@ function readNotesSync (name) {
.replace(/\{datetime\}/g, dateFormat(now, 'UTC:yyyy-mm-dd'))
}

const stub = sinon.stub(ReleaseNotes, 'get')
// to avoid singleton for tests
stub.callsFake(function (...args) {
return new ReleaseNotes(...args)
})

test.after(function () {
stub.restore()
})

const CASES = [
{
name: 'default config + common context w/ patch updates',
Expand Down
54 changes: 54 additions & 0 deletions test/integration/release-notes-singleton.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const test = require('ava')

const { analyzeCommits, generateNotes } = require('../..')
const getContext = require('./fixtures/contexts')

// Regression: semantic-release runs analyzeCommits / generateNotes twice
// within the same process when adding a channel to an existing tag (e.g.
// maintenance branch creation). State must not leak between passes.

test.serial(
'analyzeCommits: pass 2 must not inherit release type cached from pass 1',
async function (t) {
// GIVEN pass 1 yields a "minor" release (`:sparkles:` commit present)
const pass1 = getContext('common', { commits: { boring: 1, minor: 1 } })
pass1.logger.log = t.log
t.is(await analyzeCommits({}, pass1), 'minor')

// WHEN pass 2 runs with only commits that match no release rule
const pass2 = getContext('common', { commits: { boring: 2 } })
pass2.logger.log = t.log

// THEN pass 2 must yield no release (would inherit 'minor' under the
// previous singleton + `_rtype` cache).
t.is(await analyzeCommits({}, pass2), undefined)
}
)

test.serial(
'generateNotes: pass 2 must render only commits from its own context',
async function (t) {
// GIVEN pass 1 rendered notes for a minor release including `:sparkles:` commits
const pass1 = getContext('common', {
commits: { boring: 1, minor: 1 },
nextRelease: { version: '1.1.0', gitTag: 'v1.1.0' }
})
pass1.logger.log = t.log
await analyzeCommits({}, pass1)
const pass1Notes = await generateNotes({}, pass1)
t.true(pass1Notes.includes('Add a new feature'))

// WHEN pass 2 generates notes for a context with no `:sparkles:` commit
const pass2 = getContext('common', {
commits: { boring: 1 },
nextRelease: { version: '1.1.1', gitTag: 'v1.1.1' }
})
pass2.logger.log = t.log

// THEN pass 2 notes must not include the `:sparkles:` commit from pass 1
// (would leak under the previous singleton whose `_context.commits` was
// frozen at first construction).
const pass2Notes = await generateNotes({}, pass2)
t.false(pass2Notes.includes('Add a new feature'))
}
)