@cmflow/cli 0.65.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +106 -0
  2. package/bin/checkfeatures.sh +5 -0
  3. package/bin/cm-changelog.js +17 -0
  4. package/bin/cm-clean.js +10 -0
  5. package/bin/cm-config.js +14 -0
  6. package/bin/cm-deploy.js +11 -0
  7. package/bin/cm-fetch.js +11 -0
  8. package/bin/cm-finish.js +13 -0
  9. package/bin/cm-publish-pages.js +11 -0
  10. package/bin/cm-publish.js +14 -0
  11. package/bin/cm-push.js +14 -0
  12. package/bin/cm-rebase.js +14 -0
  13. package/bin/cm-republish.js +11 -0
  14. package/bin/cm-start.js +20 -0
  15. package/bin/cm.js +20 -0
  16. package/bin/cmexpedit.sh +9 -0
  17. package/bin/cmpull.sh +7 -0
  18. package/bin/cmrelease.js +3 -0
  19. package/package.json +88 -0
  20. package/release.config.js +19 -0
  21. package/semantic.js +1 -0
  22. package/src/commands/changelog.js +47 -0
  23. package/src/commands/clean.js +30 -0
  24. package/src/commands/config.js +23 -0
  25. package/src/commands/deploy.js +39 -0
  26. package/src/commands/fetch.js +21 -0
  27. package/src/commands/finish.js +44 -0
  28. package/src/commands/index.js +10 -0
  29. package/src/commands/prompts/branches.js +38 -0
  30. package/src/commands/publish-pages.js +29 -0
  31. package/src/commands/push.js +26 -0
  32. package/src/commands/rebase.js +38 -0
  33. package/src/commands/release.js +36 -0
  34. package/src/commands/republish.js +24 -0
  35. package/src/commands/start.js +82 -0
  36. package/src/commands/tasks/push-branch.js +16 -0
  37. package/src/commands/tasks/rebase-all-branches.js +34 -0
  38. package/src/commands/tasks/refresh-repository.js +33 -0
  39. package/src/commands/tasks/run-test.js +23 -0
  40. package/src/commands/tasks/update-branch.js +40 -0
  41. package/src/commands/tasks/update-dependencies.js +37 -0
  42. package/src/commands/utils/check-install.js +31 -0
  43. package/src/common/cli/cli.js +107 -0
  44. package/src/common/cli/docker.js +63 -0
  45. package/src/common/cli/docker.test.js +128 -0
  46. package/src/common/cli/git.js +130 -0
  47. package/src/common/cli/git.test.js +205 -0
  48. package/src/common/cli/heroku.js +21 -0
  49. package/src/common/cli/heroku.test.js +56 -0
  50. package/src/common/cli/lerna.js +25 -0
  51. package/src/common/cli/lerna.test.js +48 -0
  52. package/src/common/cli/npm.js +33 -0
  53. package/src/common/cli/npm.test.js +47 -0
  54. package/src/common/cli/yarn.js +33 -0
  55. package/src/common/cli/yarn.test.js +48 -0
  56. package/src/common/configure-git-workspace.js +27 -0
  57. package/src/common/get-config.js +135 -0
  58. package/src/common/get-package-json.js +7 -0
  59. package/src/common/get-release-config.js +7 -0
  60. package/src/common/index.js +10 -0
  61. package/src/common/run-command.js +61 -0
  62. package/src/common/run-command.test.js +63 -0
  63. package/src/index.js +1 -0
  64. package/src/main.js +10 -0
  65. package/src/semantic-release/actions/analyze-commits.js +9 -0
  66. package/src/semantic-release/actions/fail.js +16 -0
  67. package/src/semantic-release/actions/generate-notes.js +11 -0
  68. package/src/semantic-release/actions/index.js +8 -0
  69. package/src/semantic-release/actions/prepare.js +101 -0
  70. package/src/semantic-release/actions/publish.js +17 -0
  71. package/src/semantic-release/actions/success.js +30 -0
  72. package/src/semantic-release/actions/verify-conditions.js +30 -0
  73. package/src/semantic-release/actions/verify-release.js +7 -0
  74. package/src/semantic-release/get-semantic-config.js +115 -0
  75. package/src/semantic-release/utils/calculate-snapshot-version.js +9 -0
  76. package/src/semantic-release/utils/calculate-snapshot-version.test.js +57 -0
  77. package/src/semantic-release/utils/display-package-info.js +11 -0
  78. package/src/semantic-release/utils/display-release-info.js +12 -0
  79. package/src/semantic-release/utils/docker-clean-tags.js +45 -0
  80. package/src/semantic-release/utils/docker-clean-tags.test.js +54 -0
  81. package/src/semantic-release/utils/docker-publish.js +36 -0
  82. package/src/semantic-release/utils/docker-publish.test.js +43 -0
  83. package/src/semantic-release/utils/ghpages-publish.js +16 -0
  84. package/src/semantic-release/utils/log-section.js +5 -0
  85. package/src/workflow/index.js +37 -0
@@ -0,0 +1,115 @@
1
+ import { getConfig } from '../common/get-config'
2
+ import { WORKFLOW_CONFIGURATION } from '../workflow'
3
+
4
+ const releaseRules = WORKFLOW_CONFIGURATION.map(({ label, ...props }) => props)
5
+ const commitTypeMapping = WORKFLOW_CONFIGURATION.reduce((obj, { type, label }) => {
6
+ return {
7
+ ...obj,
8
+ [type]: label
9
+ }
10
+ }, {})
11
+
12
+ const transformCommitType = commit => {
13
+ if (commitTypeMapping[commit.type]) {
14
+ return commitTypeMapping[commit.type]
15
+ }
16
+
17
+ return commitTypeMapping.default
18
+ }
19
+
20
+ const transform = (commit, context) => {
21
+ const issues = []
22
+
23
+ commit.notes.forEach(note => {
24
+ note.title = 'BREAKING CHANGES'
25
+ })
26
+
27
+ commit.type = transformCommitType(commit)
28
+
29
+ if (commit.message && commit.message.match(/^[\w-]+$/i)) {
30
+ return
31
+ }
32
+
33
+ if (commit.subject) {
34
+ commit.subject = commit.subject.replace('[MEP]', '')
35
+ }
36
+
37
+ if (commit.scope === '*') {
38
+ commit.scope = ''
39
+ }
40
+
41
+ if (typeof commit.hash === 'string') {
42
+ commit.shortHash = commit.hash.substring(0, 7)
43
+ }
44
+
45
+ if (typeof commit.subject === 'string') {
46
+ let url = context.repository
47
+ ? `${context.host}/${context.owner}/${context.repository}`
48
+ : context.repoUrl
49
+ if (url) {
50
+ url = `${url}/issues/`
51
+ // Issue URLs.
52
+ commit.subject = commit.subject.replace(/#([0-9]+)/g, (_, issue) => {
53
+ issues.push(issue)
54
+ return `[#${issue}](${url}${issue})`
55
+ })
56
+ }
57
+ if (context.host) {
58
+ // User URLs.
59
+ commit.subject = commit.subject.replace(
60
+ /\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g,
61
+ (_, username) => {
62
+ if (username.includes('/')) {
63
+ return `@${username}`
64
+ }
65
+
66
+ return `[@${username}](${context.host}/${username})`
67
+ }
68
+ )
69
+ }
70
+ }
71
+
72
+ // remove references that already appear in the subject
73
+ commit.references = commit.references.filter(reference => {
74
+ if (issues.indexOf(reference.issue) === -1) {
75
+ return true
76
+ }
77
+
78
+ return false
79
+ })
80
+
81
+ return commit
82
+ }
83
+
84
+ export function getSemanticConfig () {
85
+ const config = getConfig()
86
+
87
+ return {
88
+ noCi: config.PRODUCTION_BRANCH !== config.BRANCH_NAME,
89
+ branches: [
90
+ {
91
+ name: config.PRODUCTION_BRANCH,
92
+ channel: 'release'
93
+ },
94
+ // Use this hack to always run semantic-release (as prerelease for feature/fix branch)
95
+ {
96
+ name: config.BRANCH_NAME,
97
+ channel: 'prerelease',
98
+ prerelease: true
99
+ }
100
+ ],
101
+ verifyConditions: ['@cmflow/cli/semantic'],
102
+ analyzeCommits: ['@cmflow/cli/semantic'],
103
+ verifyRelease: ['@cmflow/cli/semantic'],
104
+ generateNotes: ['@cmflow/cli/semantic'],
105
+ prepare: ['@cmflow/cli/semantic'],
106
+ publish: ['@cmflow/cli/semantic'],
107
+ success: ['@cmflow/cli/semantic'],
108
+ fail: ['@cmflow/cli/semantic'],
109
+ releaseRules,
110
+ parserOpts: {
111
+ noteKeywords: ['BREAKING CHANGE', 'BREAKING CHANGES']
112
+ },
113
+ writerOpts: { transform }
114
+ }
115
+ }
@@ -0,0 +1,9 @@
1
+ import semver from 'semver'
2
+ import { git } from '../../common'
3
+
4
+ export function calculateSnapshotVersion (context) {
5
+ const { nextRelease: { type }, lastRelease, config: { REF_COMMIT } } = context
6
+ const { major, minor, patch } = semver.parse(lastRelease.version)
7
+
8
+ return `${semver.inc(`${major}.${minor}.${patch}`, type)}-beta${git.getCommitTag(REF_COMMIT)}`
9
+ }
@@ -0,0 +1,57 @@
1
+ import { git } from '../../common'
2
+ import { calculateSnapshotVersion } from './calculate-snapshot-version'
3
+
4
+ jest.mock('../../common')
5
+
6
+ describe('calculateSnapshotVersion', () => {
7
+ beforeEach(() => {
8
+ git.getCommitTag.mockReturnValue('13246u')
9
+ })
10
+ it('should return the snapshot version', () => {
11
+ const context = {
12
+ nextRelease: { type: 'patch' },
13
+ lastRelease: {
14
+ version: '1.0.0'
15
+ },
16
+ config: {
17
+ REF_COMMIT: 'REF_COMMIT'
18
+ }
19
+ }
20
+
21
+ const version = calculateSnapshotVersion(context)
22
+ expect(git.getCommitTag).toHaveBeenCalledWith(context.config.REF_COMMIT)
23
+ expect(version).toEqual('1.0.1-beta13246u')
24
+ })
25
+
26
+ it('should return the snapshot version', () => {
27
+ const context = {
28
+ nextRelease: { type: 'minor' },
29
+ lastRelease: {
30
+ version: '1.0.0'
31
+ },
32
+ config: {
33
+ REF_COMMIT: 'REF_COMMIT'
34
+ }
35
+ }
36
+
37
+ const version = calculateSnapshotVersion(context)
38
+ expect(git.getCommitTag).toHaveBeenCalledWith(context.config.REF_COMMIT)
39
+ expect(version).toEqual('1.1.0-beta13246u')
40
+ })
41
+
42
+ it('should return the snapshot version', () => {
43
+ const context = {
44
+ nextRelease: { type: 'major' },
45
+ lastRelease: {
46
+ version: '1.0.0'
47
+ },
48
+ config: {
49
+ REF_COMMIT: 'REF_COMMIT'
50
+ }
51
+ }
52
+
53
+ const version = calculateSnapshotVersion(context)
54
+ expect(git.getCommitTag).toHaveBeenCalledWith(context.config.REF_COMMIT)
55
+ expect(version).toEqual('2.0.0-beta13246u')
56
+ })
57
+ })
@@ -0,0 +1,11 @@
1
+ import { logSection } from './log-section'
2
+
3
+ export function displayPackageInfo (context) {
4
+ logSection('Package Info', context)
5
+ context.logger.info('Name : ' + context.config.PROJECT_NAME)
6
+ context.logger.info('Version : ' + context.lastRelease.version)
7
+ context.logger.info('Repository : ' + context.config.REPOSITORY_URL)
8
+ context.logger.info('Branch : ' + context.branch.name)
9
+ context.logger.info('Tag : ' + context.lastRelease.gitTag)
10
+ context.logger.info('GitHead : ' + context.lastRelease.gitHead)
11
+ }
@@ -0,0 +1,12 @@
1
+ import { logSection } from './log-section'
2
+
3
+ export function displayReleaseInfo (context) {
4
+ logSection('Release Info', context)
5
+ context.logger.info('Branch : ' + context.branch.name)
6
+ context.logger.info('Build N° : ' + context.config.BUILD_NUMBER)
7
+ context.logger.info('Version : ' + context.nextRelease.version)
8
+ context.logger.info('Tag : ' + context.nextRelease.gitTag)
9
+ context.logger.info('GitHead : ' + context.nextRelease.gitHead)
10
+ context.logger.info('Type : ' + context.nextRelease.type)
11
+ context.logger.info('Channel : ' + context.nextRelease.channel)
12
+ }
@@ -0,0 +1,45 @@
1
+ import { docker } from '../../common'
2
+
3
+ function mapTags (tags) {
4
+ tags = tags
5
+ .map(tag => {
6
+ return {
7
+ name: tag.name,
8
+ date: new Date(tag.last_updated).getTime()
9
+ }
10
+ }).sort((a, b) => b.date - a.date)
11
+
12
+ let tagFound = false
13
+
14
+ return tags.reduce((result, tag) => {
15
+ if (tag.name.match(/\d+\.\d+\.\d+/)) {
16
+ tagFound = true
17
+ } else if (tagFound) {
18
+ result.push(tag)
19
+ }
20
+ return result
21
+ }, [])
22
+ }
23
+
24
+ export async function dockerCleanTags (context) {
25
+ const { logger, config: { DOCKER_HUB_ID, DOCKER_HUB_PWD, DOCKER_REPOSITORY } } = context
26
+
27
+ if (DOCKER_HUB_ID && DOCKER_HUB_PWD) {
28
+ logger.info('Start clean Docker Hub...')
29
+
30
+ const token = await docker.getToken(DOCKER_HUB_ID, DOCKER_HUB_PWD)
31
+ const options = {
32
+ token,
33
+ repository: DOCKER_REPOSITORY
34
+ }
35
+
36
+ const tags = mapTags(await docker.getTags(options))
37
+
38
+ await Promise.all(tags.map(async (tag) => {
39
+ await docker.deleteTag(tag.name, options)
40
+ logger.info(`TAG : ${tag.name} deleted`)
41
+ }))
42
+
43
+ logger.info('Docker Hub Clean !')
44
+ }
45
+ }
@@ -0,0 +1,54 @@
1
+ import { docker } from '../../common'
2
+ import { dockerCleanTags } from './docker-clean-tags'
3
+
4
+ jest.mock('../../common')
5
+
6
+ describe('dockerCleanTags', () => {
7
+ beforeEach(() => {
8
+ docker.getToken.mockReturnValue('token')
9
+ docker.getTags.mockReturnValue([
10
+ {
11
+ name: 'branch-1',
12
+ last_updated: new Date('2020-06-01')
13
+ },
14
+ {
15
+ name: '1.1.0',
16
+ last_updated: new Date('2020-05-20')
17
+ },
18
+ {
19
+ name: 'branch-2',
20
+ last_updated: new Date('2020-05-01')
21
+ },
22
+ {
23
+ name: '1.0.0',
24
+ last_updated: new Date('2020-04-01')
25
+ }
26
+ ])
27
+ })
28
+ it('should clean obsolete tags', async () => {
29
+ const context = {
30
+ logger: {
31
+ info: jest.fn(),
32
+ warn: jest.fn()
33
+ },
34
+ config: {
35
+ DOCKER_HUB_ID: 'DOCKER_HUB_ID',
36
+ DOCKER_HUB_PWD: 'DOCKER_HUB_PWD',
37
+ DOCKER_REPOSITORY: 'DOCKER_REPOSITORY'
38
+ }
39
+ }
40
+
41
+ await dockerCleanTags(context)
42
+
43
+ expect(docker.getToken).toHaveBeenCalledWith('DOCKER_HUB_ID', 'DOCKER_HUB_PWD')
44
+ expect(docker.getTags).toHaveBeenCalledWith({
45
+ token: 'token',
46
+ repository: 'DOCKER_REPOSITORY'
47
+ })
48
+ expect(docker.deleteTag).toHaveBeenCalledWith('branch-2', {
49
+ token: 'token',
50
+ repository: 'DOCKER_REPOSITORY'
51
+ })
52
+ expect(docker.deleteTag).toHaveBeenCalledTimes(1)
53
+ })
54
+ })
@@ -0,0 +1,36 @@
1
+ import { docker } from '../../common'
2
+ import { heroku } from '../../common/cli/heroku'
3
+
4
+ export async function dockerPublish (context) {
5
+ const { config: { DEPLOY_ON_DOCKER, DEPLOY_ON_HEROKU, SKIP_DEPLOY } } = context
6
+
7
+ if (!SKIP_DEPLOY) {
8
+ if (DEPLOY_ON_DOCKER) {
9
+ await deployOnDockerHub(context)
10
+ }
11
+
12
+ if (DEPLOY_ON_HEROKU) {
13
+ await deployOnHeroku(context)
14
+ }
15
+ }
16
+ }
17
+
18
+ export async function deployOnDockerHub (context) {
19
+ const { config: { PRODUCTION_BRANCH, DOCKER_REPOSITORY, DOCKER_HUB_ID, DOCKER_HUB_PWD } } = context
20
+
21
+ docker.login('-u', DOCKER_HUB_ID, '-p', DOCKER_HUB_PWD)
22
+
23
+ const image = PRODUCTION_BRANCH === context.branch.name ? `${DOCKER_REPOSITORY}:${context.nextRelease.version}` : `${DOCKER_REPOSITORY}:${context.branch.name}`
24
+
25
+ docker.tag(`${DOCKER_REPOSITORY}:latest`, image)
26
+
27
+ await docker.push(image)
28
+ }
29
+
30
+ export async function deployOnHeroku (context) {
31
+ const { config: { HEROKU_APP } } = context
32
+
33
+ heroku.containerLogin().sync()
34
+ await heroku.containerPush('web', '-a', HEROKU_APP)
35
+ await heroku.containerRelease('web', '-a', HEROKU_APP)
36
+ }
@@ -0,0 +1,43 @@
1
+ import { dockerPublish } from './docker-publish'
2
+ import { docker } from '../../common'
3
+
4
+ jest.mock('../../common')
5
+
6
+ describe('dockerPublish', () => {
7
+ it('should publish docker image', async () => {
8
+ const context = {
9
+ branch: {
10
+ name: 'branch-name'
11
+ },
12
+ config: {
13
+ DEPLOY_ON_DOCKER: true,
14
+ PRODUCTION_BRANCH: 'production',
15
+ DOCKER_REPOSITORY: 'owner',
16
+ DOCKER_HUB_ID: 'login',
17
+ DOCKER_HUB_PWD: 'password'
18
+ }
19
+ }
20
+ await dockerPublish(context)
21
+
22
+ expect(docker.login).toHaveBeenCalledWith('-u', 'login', '-p', 'password')
23
+ expect(docker.tag).toHaveBeenCalledWith('owner:latest', 'owner:branch-name')
24
+ expect(docker.push).toHaveBeenCalledWith('owner:branch-name')
25
+ })
26
+ it('should do nothing', async () => {
27
+ const context = {
28
+ branch: {
29
+ name: 'branch-name'
30
+ },
31
+ config: {
32
+ DEPLOY_ON_DOCKER: false,
33
+ PRODUCTION_BRANCH: 'production',
34
+ DOCKER_REPOSITORY: 'owner',
35
+ DOCKER_HUB_ID: 'login',
36
+ DOCKER_HUB_PWD: 'password'
37
+ }
38
+ }
39
+ await dockerPublish(context)
40
+
41
+ expect(docker.login).not.toHaveBeenCalled()
42
+ })
43
+ })
@@ -0,0 +1,16 @@
1
+ import { join } from 'path'
2
+ import { writeFileSync } from 'fs'
3
+ import { git } from '../../common'
4
+
5
+ export async function ghPagesPublish (context) {
6
+ const { config: { GITHUB_PAGES_PATH: cwd, GH_TOKEN, REPOSITORY_URL } } = context
7
+ const repository = REPOSITORY_URL.replace('https://', '')
8
+
9
+ writeFileSync(join(cwd, '.nojekyll'), '', { encoding: 'utf8' })
10
+
11
+ git.init().cwd(cwd).sync()
12
+ git.add('-A').cwd(cwd).sync()
13
+ git.commit('-m', 'Deploy documentation v' + context.nextRelease.version).cwd(cwd).sync()
14
+
15
+ await git.push('-f', GH_TOKEN ? `https://${GH_TOKEN}@${repository}` : `https://${repository}`, 'master:gh-pages').cwd(cwd)
16
+ }
@@ -0,0 +1,5 @@
1
+ export function logSection (title, context) {
2
+ context.logger.info('-----------------------------------')
3
+ context.logger.info(`--- ${title}`)
4
+ context.logger.info('-----------------------------------')
5
+ }
@@ -0,0 +1,37 @@
1
+ export const WORKFLOW_CONFIGURATION = [
2
+ {
3
+ type: 'feat',
4
+ label: 'Features',
5
+ release: 'minor'
6
+ },
7
+ {
8
+ type: 'fix',
9
+ label: 'Bug Fixes',
10
+ release: 'patch'
11
+ },
12
+ {
13
+ type: 'chore',
14
+ label: 'Chores',
15
+ release: false
16
+ },
17
+ {
18
+ type: 'ci',
19
+ label: 'CI',
20
+ release: false
21
+ },
22
+ {
23
+ type: 'docs',
24
+ label: 'Documentation',
25
+ release: 'patch'
26
+ },
27
+ {
28
+ type: 'tech',
29
+ label: 'Technical Improvements',
30
+ release: 'patch'
31
+ },
32
+ {
33
+ type: 'default',
34
+ label: 'Miscellaneous',
35
+ release: false
36
+ }
37
+ ]