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
25 changes: 23 additions & 2 deletions lib/commands/publish.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const assert = require('node:assert').strict
const { isDeepStrictEqual } = require('node:util')
const pino = require('pino')
const { validate } = require('../validation')
const draft = require('./draft')
Expand Down Expand Up @@ -86,7 +86,28 @@ module.exports = async function (args) {
delete compare.current // the current branch could be named in a different way
CLEAN_REPO.tracking = `${args.remote}/${args.branch}` // your local branch must track where you will push
logger.debug('Complete repo status %s', inlineNotEmpty(status))
assert.deepStrictEqual(buildGitStatus(compare), CLEAN_REPO, 'The git repo must be clean (committed and pushed) before releasing!')

if (!compare.tracking) {
throw new Error(`Your local branch doesn't track any remote branch, but releasify expects "${CLEAN_REPO.tracking}".
Push it and set its upstream (for example: git push -u ${args.remote} ${args.branch}), or switch to the branch you want to release.`)
}

if (compare.tracking !== CLEAN_REPO.tracking) {
throw new Error(`Your local branch tracks "${compare.tracking}", but releasify expects "${CLEAN_REPO.tracking}".
Either switch to the branch you want to release, or tell releasify which one to use:
- for this run only: add --branch <name> (and --remote <name> if needed)
- as your new default: run "releasify config --arg branch"`)
}

const gitStatus = buildGitStatus(compare)
const notClean = Object.keys(CLEAN_REPO)
.filter(key => !isDeepStrictEqual(gitStatus[key], CLEAN_REPO[key]))
.map(key => `- ${key}: ${JSON.stringify(gitStatus[key])}`)
if (notClean.length > 0) {
throw new Error(`The git repo must be clean (committed and pushed) before releasing!
${notClean.join('\n')}
Check "git status", then commit, push or pull before trying again.`)
}

logger.debug('Building draft release..')
const releasing = await draft(args)
Expand Down
42 changes: 41 additions & 1 deletion test/command-publish.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ test('mandatory options', (t) => {
})

test('try to publish a repo not sync', async (t) => {
t.plan(1)
t.plan(2)
const cmd = h.buildProxyCommand('../lib/commands/publish', {
git: { status: { dirty: true } }
})
Expand All @@ -81,6 +81,46 @@ test('try to publish a repo not sync', async (t) => {
'The git repo must be clean (committed and pushed) before releasing!'
)
)
t.assert.match(error.message, /- modified: \["dirty-status\.js"\]/)
}
})

test('try to publish a repo tracked not to main branch', async (t) => {
t.plan(3)
const cmd = h.buildProxyCommand('../lib/commands/publish', {
git: { status: { tracking: 'origin/develop' } }
})
const opts = buildOptions()
opts.semver = 'patch'
opts.ghToken = '0000000000000000000000000000000000000000'
delete opts.tag

try {
await cmd(opts)
t.assert.fail('should not succeed')
} catch (error) {
t.assert.match(error.message, /origin\/main/)
t.assert.match(error.message, /origin\/develop/)
t.assert.match(error.message, /--branch/)
}
})

test('try to publish a branch that does not track any remote branch', async (t) => {
t.plan(2)
const cmd = h.buildProxyCommand('../lib/commands/publish', {
git: { status: { tracking: null } }
})
const opts = buildOptions()
opts.semver = 'patch'
opts.ghToken = '0000000000000000000000000000000000000000'
delete opts.tag

try {
await cmd(opts)
t.assert.fail('should not succeed')
} catch (error) {
t.assert.match(error.message, /doesn't track any remote branch/)
t.assert.match(error.message, /git push -u origin main/)
}
})

Expand Down
4 changes: 2 additions & 2 deletions test/proxy/simple-git-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function shouldThrows (cmd = {}, params) {
* {
* tag: {inputChecker: func, throwError: true, history: number of tag commit list}
* log: {inputChecker: func, throwError: true, messages: [array of messages to use]}
* status: {throwError: true, dirty: true, tracking: 'origin/main'}
* status: {throwError: true, dirty: true, tracking: 'origin/main' (null = no upstream branch)}
* add: {inputChecker: func, throwError: true}
* commit: {inputChecker: func, throwError: true, branch: 'main'}
* push: {inputChecker: func, throwError: true}
Expand Down Expand Up @@ -71,7 +71,7 @@ module.exports = function factory (opts = {}) {
modified.push('dirty-status.js')
}

const tracking = (opts.status && opts.status.tracking) ? opts.status.tracking : 'origin/main'
const tracking = (opts.status && opts.status.tracking !== undefined) ? opts.status.tracking : 'origin/main'

cb(null, {
not_added: [],
Expand Down
Loading