@cmflow/cli 1.0.16 → 1.1.1-alpha.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 (124) hide show
  1. package/.prettierignore +5 -0
  2. package/.prettierrc +10 -0
  3. package/README.md +106 -32
  4. package/bin/cm-changelog.js +20 -12
  5. package/bin/cm-clean.js +4 -7
  6. package/bin/cm-config.js +8 -8
  7. package/bin/cm-deploy.js +4 -8
  8. package/bin/cm-fetch.js +7 -7
  9. package/bin/cm-finish.js +9 -9
  10. package/bin/cm-merge.js +7 -7
  11. package/bin/cm-publish.js +10 -10
  12. package/bin/cm-push.js +10 -10
  13. package/bin/cm-rebase.js +10 -10
  14. package/bin/cm-republish.js +7 -7
  15. package/bin/cm-start.js +10 -10
  16. package/bin/cm.js +20 -20
  17. package/bin/cmrelease.js +2 -2
  18. package/eslint.config.mjs +67 -0
  19. package/package.json +27 -21
  20. package/release.config.mjs +49 -19
  21. package/src/commands/changelog.js +23 -23
  22. package/src/commands/clean.js +13 -13
  23. package/src/commands/config.js +8 -8
  24. package/src/commands/deploy.js +15 -20
  25. package/src/commands/fetch.js +7 -10
  26. package/src/commands/finish.js +18 -19
  27. package/src/commands/index.js +10 -11
  28. package/src/commands/merge.js +30 -14
  29. package/src/commands/prompts/branches.js +20 -20
  30. package/src/commands/push.js +11 -14
  31. package/src/commands/rebase.js +17 -19
  32. package/src/commands/release.js +10 -11
  33. package/src/commands/republish.js +11 -14
  34. package/src/commands/start.js +66 -38
  35. package/src/commands/tasks/merge-branch.js +41 -37
  36. package/src/commands/tasks/push-branch.js +5 -11
  37. package/src/commands/tasks/rebase-all-branches.js +19 -24
  38. package/src/commands/tasks/refresh-repository.js +26 -24
  39. package/src/commands/tasks/run-test.js +11 -17
  40. package/src/commands/tasks/update-branch.js +33 -30
  41. package/src/commands/tasks/update-dependencies.js +38 -32
  42. package/src/commands/utils/check-install.js +16 -15
  43. package/src/common/cli/cli.js +55 -57
  44. package/src/common/cli/docker.js +31 -28
  45. package/src/common/cli/docker.test.js +94 -96
  46. package/src/common/cli/git.js +59 -68
  47. package/src/common/cli/git.test.js +187 -189
  48. package/src/common/cli/lerna.js +12 -12
  49. package/src/common/cli/lerna.test.js +38 -40
  50. package/src/common/cli/npm.js +17 -17
  51. package/src/common/cli/npm.test.js +38 -40
  52. package/src/common/cli/yarn.js +17 -17
  53. package/src/common/cli/yarn.test.js +40 -40
  54. package/src/common/configure-git-workspace.js +11 -17
  55. package/src/common/get-config.js +63 -119
  56. package/src/common/get-package-json.js +4 -4
  57. package/src/common/get-release-config.js +4 -5
  58. package/src/common/index.js +10 -10
  59. package/src/common/run-command.js +26 -28
  60. package/src/common/run-command.test.js +35 -39
  61. package/src/index.js +10 -1
  62. package/src/semantic/core/analyze-commits.js +17 -0
  63. package/src/semantic/core/fail.js +29 -0
  64. package/src/semantic/core/generate-notes.js +11 -0
  65. package/src/semantic/core/prepare/bump-version.js +38 -0
  66. package/src/semantic/core/prepare/post.js +38 -0
  67. package/src/semantic/core/prepare/run.js +22 -0
  68. package/src/semantic/core/publish.js +9 -0
  69. package/src/semantic/core/success.js +37 -0
  70. package/src/semantic/core/verify-conditions.js +32 -0
  71. package/src/semantic/core/verify-release.js +9 -0
  72. package/src/semantic/define-config.js +68 -0
  73. package/src/semantic/docker/publish.js +5 -0
  74. package/src/semantic/docker/success.js +9 -0
  75. package/src/semantic/utils/bump-packages-version.js +52 -0
  76. package/src/semantic/utils/bump-packages-version.test.js +75 -0
  77. package/src/semantic/utils/calculate-snapshot-version.js +15 -0
  78. package/src/semantic/utils/calculate-snapshot-version.test.js +67 -0
  79. package/src/semantic/utils/display-package-info.js +11 -0
  80. package/src/semantic/utils/display-release-info.js +12 -0
  81. package/src/semantic/utils/docker-clean-tags.js +51 -0
  82. package/src/semantic/utils/docker-clean-tags.test.js +61 -0
  83. package/src/semantic/utils/docker-publish.js +23 -0
  84. package/src/semantic/utils/docker-publish.test.js +44 -0
  85. package/src/semantic/utils/log-section.js +5 -0
  86. package/src/semantic/utils/release-rules.js +5 -0
  87. package/src/semantic/utils/transform-writer.js +75 -0
  88. package/src/workflow/index.js +22 -22
  89. package/tsconfig.json +54 -0
  90. package/vitest.config.mts +10 -0
  91. package/bin/cm-publish-pages.js +0 -12
  92. package/semantic.js +0 -1
  93. package/src/commands/publish-pages.js +0 -29
  94. package/src/common/cli/heroku.js +0 -21
  95. package/src/common/cli/heroku.test.js +0 -62
  96. package/src/main.js +0 -10
  97. package/src/semantic-release/actions/analyze-commits.js +0 -14
  98. package/src/semantic-release/actions/fail.js +0 -16
  99. package/src/semantic-release/actions/generate-notes.js +0 -12
  100. package/src/semantic-release/actions/index.js +0 -8
  101. package/src/semantic-release/actions/prepare.js +0 -114
  102. package/src/semantic-release/actions/publish.js +0 -17
  103. package/src/semantic-release/actions/success.js +0 -32
  104. package/src/semantic-release/actions/verify-conditions.js +0 -30
  105. package/src/semantic-release/actions/verify-release.js +0 -9
  106. package/src/semantic-release/get-semantic-config.js +0 -115
  107. package/src/semantic-release/utils/bump-packages-version.js +0 -51
  108. package/src/semantic-release/utils/bump-packages-version.test.js +0 -78
  109. package/src/semantic-release/utils/calculate-snapshot-version.js +0 -10
  110. package/src/semantic-release/utils/calculate-snapshot-version.test.js +0 -69
  111. package/src/semantic-release/utils/display-package-info.js +0 -11
  112. package/src/semantic-release/utils/display-release-info.js +0 -12
  113. package/src/semantic-release/utils/docker-clean-tags.js +0 -45
  114. package/src/semantic-release/utils/docker-clean-tags.test.js +0 -63
  115. package/src/semantic-release/utils/docker-publish.js +0 -47
  116. package/src/semantic-release/utils/docker-publish.test.js +0 -67
  117. package/src/semantic-release/utils/ghpages-publish.js +0 -16
  118. package/src/semantic-release/utils/log-section.js +0 -5
  119. /package/src/{semantic-release → semantic}/utils/__mock__/test1/package.json +0 -0
  120. /package/src/{semantic-release → semantic}/utils/__mock__/test1/packages/a/package.json +0 -0
  121. /package/src/{semantic-release → semantic}/utils/__mock__/test1/packages/b/package.json +0 -0
  122. /package/src/{semantic-release → semantic}/utils/__mock__/test2/package.json +0 -0
  123. /package/src/{semantic-release → semantic}/utils/__mock__/test2/packages/a/package.json +0 -0
  124. /package/src/{semantic-release → semantic}/utils/__mock__/test2/packages/b/package.json +0 -0
@@ -0,0 +1,9 @@
1
+ export async function publish(pluginConfig, context) {
2
+ const { branch } = context;
3
+
4
+ if (branch.type === "release" && pluginConfig.runAfter) {
5
+ const { publish } = await import(pluginConfig.runAfter);
6
+
7
+ await publish(pluginConfig, context);
8
+ }
9
+ }
@@ -0,0 +1,37 @@
1
+ import { getConfig } from "../../common/get-config.js";
2
+ import { git } from "../../common/index.js";
3
+
4
+ /**
5
+ * Add runAfter property with the semantic-release plugin name to run after the success task
6
+ * depending on the branch type.
7
+ *
8
+ * @param pluginConfig {{runAfter: string}}
9
+ * @param context
10
+ * @return {Promise<void>}
11
+ */
12
+ export async function success(pluginConfig, context) {
13
+ context.config = getConfig();
14
+ const {
15
+ branch,
16
+ logger,
17
+ config: { PRODUCTION_BRANCH, ORIGIN, DEVELOP_BRANCH }
18
+ } = context;
19
+
20
+ if (branch.type !== "prerelease") {
21
+ await git.push("--quiet", "--set-upstream", ORIGIN, PRODUCTION_BRANCH);
22
+
23
+ if (PRODUCTION_BRANCH !== DEVELOP_BRANCH) {
24
+ logger.start(`Reset HEAD of ${ORIGIN}/${DEVELOP_BRANCH} branch to HEAD of ${ORIGIN}/${PRODUCTION_BRANCH} `);
25
+
26
+ await git.push("-f", ORIGIN, `refs/remotes/${ORIGIN}/${PRODUCTION_BRANCH}:refs/heads/${DEVELOP_BRANCH}`);
27
+
28
+ logger.success(`${ORIGIN}/${DEVELOP_BRANCH} branch correctly updated`);
29
+ }
30
+
31
+ if (pluginConfig.runAfter) {
32
+ const { success } = await import(pluginConfig.runAfter);
33
+
34
+ await success(pluginConfig, context);
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,32 @@
1
+ import chalk from "chalk";
2
+
3
+ import { getConfig, git } from "../../common/index.js";
4
+
5
+ export function verifyConditions(pluginConfig, context) {
6
+ if (pluginConfig.dryRun) {
7
+ return;
8
+ }
9
+
10
+ context.config = getConfig();
11
+ const {
12
+ branch,
13
+ config: { USER, EMAIL, ORIGIN }
14
+ } = context;
15
+
16
+ if (USER && EMAIL) {
17
+ context.logger.info("Configure git with username");
18
+
19
+ git.config("--global", "user.name", USER);
20
+ git.config("--global", "user.email", EMAIL);
21
+
22
+ context.logger.info("Configure git branch");
23
+ context.logger.success("Workspace is correctly configured");
24
+ } else {
25
+ context.logger.error(chalk.red("Ignore git configuration (Empty GIT_USER_EMAIL or/and GIT_USER_NAME variables)"));
26
+ process.exit(1);
27
+ }
28
+
29
+ git.fetch().sync();
30
+ git.checkout(branch.name).sync();
31
+ git.branch(`--set-upstream-to=${ORIGIN}/${branch.name}`, branch.name).sync();
32
+ }
@@ -0,0 +1,9 @@
1
+ import { getConfig } from "../../common/index.js";
2
+ import { displayPackageInfo } from "../utils/display-package-info.js";
3
+ import { displayReleaseInfo } from "../utils/display-release-info.js";
4
+
5
+ export function verifyRelease(pluginConfig, context) {
6
+ context.config = getConfig();
7
+ displayPackageInfo(context);
8
+ displayReleaseInfo(context);
9
+ }
@@ -0,0 +1,68 @@
1
+ import { getConfig } from "../common/get-config.js";
2
+ import { releaseRules } from "./utils/release-rules.js";
3
+ import { transformWriter } from "./utils/transform-writer.js";
4
+
5
+ /**
6
+ * Define the semantic-release configuration based on the ClubMed API configuration.
7
+ * @param {import('semantic-release').GlobalConfig} opts
8
+ * @returns {import('semantic-release').GlobalConfig}
9
+ */
10
+ export function defineConfig(opts = {}) {
11
+ const { PRODUCTION_BRANCH: productBranch, BRANCH_NAME: branchName } = getConfig();
12
+
13
+ return {
14
+ noCi: productBranch !== branchName,
15
+ branches: [
16
+ {
17
+ name: productBranch,
18
+ channel: "release"
19
+ },
20
+ // Use this hack to always run semantic-release (as prerelease for feature/fix branch)
21
+ {
22
+ name: branchName,
23
+ channel: "prerelease",
24
+ prerelease: true
25
+ }
26
+ ],
27
+ verifyConditions: ["@cmflow/cli/semantic/verify-conditions"],
28
+ analyzeCommits: ["@cmflow/cli/semantic/analyze-commits"],
29
+ verifyRelease: ["@cmflow/cli/semantic/verify-release"],
30
+ generateNotes: ["@cmflow/cli/semantic/generate-notes"],
31
+ prepare: [
32
+ "@cmflow/cli/semantic/prepare/bump-version",
33
+ // '@cmflow/cli/semantic/prepare/build',
34
+ // '@cmflow/cli/semantic/prepare/e2e',
35
+ "@cmflow/cli/semantif/prepare/post" // need to avoid semantic next step
36
+ ],
37
+ publish: [
38
+ [
39
+ "@cmflow/cli/semantic/publish",
40
+ {
41
+ runAfter: opts.runAfter
42
+ }
43
+ ]
44
+ ],
45
+ success: [
46
+ [
47
+ "@cmflow/cli/semantic/success",
48
+ {
49
+ runAfter: opts.runAfter
50
+ }
51
+ ]
52
+ ],
53
+ fail: [
54
+ [
55
+ "@cmflow/cli/semantic/fail",
56
+ {
57
+ runAfter: opts.runAfter
58
+ }
59
+ ]
60
+ ],
61
+ releaseRules,
62
+ parserOpts: {
63
+ noteKeywords: ["BREAKING CHANGE", "BREAKING CHANGES"]
64
+ },
65
+ writerOpts: { transform: transformWriter },
66
+ ...opts
67
+ };
68
+ }
@@ -0,0 +1,5 @@
1
+ import { dockerPublish } from "../utils/docker-publish.js";
2
+
3
+ export async function publish(pluginConfig, context) {
4
+ await dockerPublish(context);
5
+ }
@@ -0,0 +1,9 @@
1
+ import { dockerCleanTags } from "../utils/docker-clean-tags.js";
2
+
3
+ export async function success(pluginConfig, context) {
4
+ try {
5
+ await dockerCleanTags(context);
6
+ } catch (er) {
7
+ context.logger.warn(er);
8
+ }
9
+ }
@@ -0,0 +1,52 @@
1
+ import fs from "fs-extra";
2
+ import globby from "globby";
3
+ import { dirname } from "path";
4
+
5
+ const PACKAGE_JSON_PROPS = ["dependencies", "devDependencies", "peerDependencies"];
6
+
7
+ export async function bumpPackagesVersion(version, workspaces, cwd = process.cwd()) {
8
+ const patterns = workspaces.map((path) => `${path}/package.json`).concat("package.json");
9
+
10
+ const files = await globby(patterns, {
11
+ cwd,
12
+ absolute: true
13
+ });
14
+
15
+ const names = new Set();
16
+
17
+ const packages = await Promise.all(
18
+ files.map(async (file) => {
19
+ const pkg = await fs.readJson(file);
20
+
21
+ names.add(pkg.name);
22
+
23
+ return {
24
+ file,
25
+ pkg
26
+ };
27
+ })
28
+ );
29
+
30
+ return Promise.all(
31
+ packages.map(({ pkg, file }) => {
32
+ pkg.version = version;
33
+
34
+ PACKAGE_JSON_PROPS.forEach((key) => bumpDependencies(pkg, key, version, names));
35
+
36
+ fs.ensureDirSync(dirname(file));
37
+ return fs.writeFile(file, JSON.stringify(pkg, null, 2), { encoding: "utf8" });
38
+ })
39
+ );
40
+ }
41
+
42
+ function bumpDependencies(pkg, key, version, names) {
43
+ pkg[key] = pkg[key] || {};
44
+
45
+ if (pkg[key]) {
46
+ names.forEach((name) => {
47
+ if (pkg[key][name] && !pkg[key][name].startsWith("workspace:")) {
48
+ pkg[key][name] = version;
49
+ }
50
+ });
51
+ }
52
+ }
@@ -0,0 +1,75 @@
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+ import * as url from "url";
4
+
5
+ import { bumpPackagesVersion } from "./bump-packages-version.js";
6
+
7
+ const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
8
+
9
+ describe("bumpPackagesVersion()", () => {
10
+ beforeEach(() => {
11
+ vi.resetAllMocks();
12
+ vi.spyOn(fs, "writeFile").mockResolvedValue();
13
+ vi.spyOn(fs, "ensureDirSync").mockResolvedValue();
14
+ });
15
+
16
+ it("should upgrade dependencies (package manager: npm/yarn)", async () => {
17
+ await bumpPackagesVersion("1.1.0", ["packages/*"], path.join(__dirname, "__mock__/test1"));
18
+
19
+ const calls = fs.writeFile.mock.calls.sort(([a], [b]) => (a > b ? -1 : 1));
20
+
21
+ expect(JSON.parse(calls[0][1])).toEqual({
22
+ version: "1.1.0",
23
+ name: "@package/b",
24
+ dependencies: {},
25
+ devDependencies: {},
26
+ peerDependencies: {}
27
+ });
28
+
29
+ expect(JSON.parse(calls[1][1])).toEqual({
30
+ name: "@package/a",
31
+ version: "1.1.0",
32
+ dependencies: { "@package/b": "1.1.0" },
33
+ devDependencies: {},
34
+ peerDependencies: {}
35
+ });
36
+
37
+ expect(JSON.parse(calls[2][1])).toEqual({
38
+ name: "@package/root",
39
+ version: "1.1.0",
40
+ dependencies: {},
41
+ devDependencies: {},
42
+ peerDependencies: {}
43
+ });
44
+ });
45
+ it("should upgrade dependencies (package manager: yarn berry)", async () => {
46
+ await bumpPackagesVersion("1.1.0", ["packages/*"], path.join(__dirname, "__mock__/test2"));
47
+ const calls = fs.writeFile.mock.calls.sort(([a], [b]) => (a > b ? -1 : 1));
48
+
49
+ expect(JSON.parse(calls[0][1])).toEqual({
50
+ dependencies: {},
51
+ devDependencies: {},
52
+ name: "@package/b",
53
+ peerDependencies: {},
54
+ version: "1.1.0"
55
+ });
56
+
57
+ expect(JSON.parse(calls[1][1])).toEqual({
58
+ dependencies: {
59
+ "@package/b": "workspace:*"
60
+ },
61
+ devDependencies: {},
62
+ name: "@package/a",
63
+ peerDependencies: {},
64
+ version: "1.1.0"
65
+ });
66
+
67
+ expect(JSON.parse(calls[2][1])).toEqual({
68
+ dependencies: {},
69
+ devDependencies: {},
70
+ name: "@package/root",
71
+ peerDependencies: {},
72
+ version: "1.1.0"
73
+ });
74
+ });
75
+ });
@@ -0,0 +1,15 @@
1
+ import semver from "semver";
2
+
3
+ import { getConfig, git } from "../../common/index.js";
4
+
5
+ export function calculateSnapshotVersion(context) {
6
+ context.config = getConfig();
7
+ const {
8
+ nextRelease: { type },
9
+ lastRelease,
10
+ config: { REF_COMMIT }
11
+ } = context;
12
+ const { major, minor, patch } = semver.parse(lastRelease.version);
13
+
14
+ return `${semver.inc(`${major}.${minor}.${patch}`, type)}-beta${git.getCommitTag(REF_COMMIT)}`;
15
+ }
@@ -0,0 +1,67 @@
1
+ vi.mock("../../common/index.js", () => {
2
+ return {
3
+ git: {
4
+ getCommitTag: vi.fn()
5
+ },
6
+ getConfig: vi.fn()
7
+ };
8
+ });
9
+ const { git, getConfig } = await import("../../common/index.js");
10
+ const { calculateSnapshotVersion } = await import("./calculate-snapshot-version.js");
11
+
12
+ describe("calculateSnapshotVersion", () => {
13
+ beforeEach(() => {
14
+ git.getCommitTag.mockReturnValue("13246u");
15
+ getConfig.mockReturnValue({
16
+ DEPLOY_ON_DOCKER: true,
17
+ PRODUCTION_BRANCH: "production",
18
+ DOCKER_REPOSITORY: "owner",
19
+ DOCKER_HUB_ID: "login",
20
+ DOCKER_HUB_PWD: "password"
21
+ });
22
+ });
23
+ it("should return the snapshot version", () => {
24
+ const context = {
25
+ nextRelease: { type: "patch" },
26
+ lastRelease: {
27
+ version: "1.0.0"
28
+ }
29
+ };
30
+
31
+ const version = calculateSnapshotVersion(context);
32
+ expect(git.getCommitTag).toHaveBeenCalledWith(context.config.REF_COMMIT);
33
+ expect(version).toEqual("1.0.1-beta13246u");
34
+ });
35
+
36
+ it("should return the snapshot version", () => {
37
+ const context = {
38
+ nextRelease: { type: "minor" },
39
+ lastRelease: {
40
+ version: "1.0.0"
41
+ },
42
+ config: {
43
+ REF_COMMIT: "REF_COMMIT"
44
+ }
45
+ };
46
+
47
+ const version = calculateSnapshotVersion(context);
48
+ expect(git.getCommitTag).toHaveBeenCalledWith(context.config.REF_COMMIT);
49
+ expect(version).toEqual("1.1.0-beta13246u");
50
+ });
51
+
52
+ it("should return the snapshot version", () => {
53
+ const context = {
54
+ nextRelease: { type: "major" },
55
+ lastRelease: {
56
+ version: "1.0.0"
57
+ },
58
+ config: {
59
+ REF_COMMIT: "REF_COMMIT"
60
+ }
61
+ };
62
+
63
+ const version = calculateSnapshotVersion(context);
64
+ expect(git.getCommitTag).toHaveBeenCalledWith(context.config.REF_COMMIT);
65
+ expect(version).toEqual("2.0.0-beta13246u");
66
+ });
67
+ });
@@ -0,0 +1,11 @@
1
+ import { logSection } from "./log-section.js";
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.js";
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,51 @@
1
+ import { docker } from "../../common/index.js";
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
+ })
11
+ .sort((a, b) => b.date - a.date);
12
+
13
+ let tagFound = false;
14
+
15
+ return tags.reduce((result, tag) => {
16
+ if (tag.name.match(/\d+\.\d+\.\d+/)) {
17
+ tagFound = true;
18
+ } else if (tagFound) {
19
+ result.push(tag);
20
+ }
21
+ return result;
22
+ }, []);
23
+ }
24
+
25
+ export async function dockerCleanTags(context) {
26
+ const {
27
+ logger,
28
+ config: { DOCKER_HUB_ID, DOCKER_HUB_PWD, DOCKER_REPOSITORY }
29
+ } = context;
30
+
31
+ if (DOCKER_HUB_ID && DOCKER_HUB_PWD) {
32
+ logger.info("Start clean Docker Hub...");
33
+
34
+ const token = await docker.getToken(DOCKER_HUB_ID, DOCKER_HUB_PWD);
35
+ const options = {
36
+ token,
37
+ repository: DOCKER_REPOSITORY
38
+ };
39
+
40
+ const tags = mapTags(await docker.getTags(options));
41
+
42
+ await Promise.all(
43
+ tags.map(async (tag) => {
44
+ await docker.deleteTag(tag.name, options);
45
+ logger.info(`TAG : ${tag.name} deleted`);
46
+ })
47
+ );
48
+
49
+ logger.info("Docker Hub Clean !");
50
+ }
51
+ }
@@ -0,0 +1,61 @@
1
+ vi.mock("../../common", () => {
2
+ return {
3
+ docker: {
4
+ getToken: vi.fn(),
5
+ getTags: vi.fn(),
6
+ deleteTag: vi.fn()
7
+ }
8
+ };
9
+ });
10
+ const { docker } = await import("../../common/index.js");
11
+ const { dockerCleanTags } = await import("./docker-clean-tags.js");
12
+
13
+ describe("dockerCleanTags", () => {
14
+ beforeEach(() => {
15
+ docker.getToken.mockReturnValue("token");
16
+ docker.getTags.mockReturnValue([
17
+ {
18
+ name: "branch-1",
19
+ last_updated: new Date("2020-06-01")
20
+ },
21
+ {
22
+ name: "1.1.0",
23
+ last_updated: new Date("2020-05-20")
24
+ },
25
+ {
26
+ name: "branch-2",
27
+ last_updated: new Date("2020-05-01")
28
+ },
29
+ {
30
+ name: "1.0.0",
31
+ last_updated: new Date("2020-04-01")
32
+ }
33
+ ]);
34
+ });
35
+ it("should clean obsolete tags", async () => {
36
+ const context = {
37
+ logger: {
38
+ info: vi.fn(),
39
+ warn: vi.fn()
40
+ },
41
+ config: {
42
+ DOCKER_HUB_ID: "DOCKER_HUB_ID",
43
+ DOCKER_HUB_PWD: "DOCKER_HUB_PWD",
44
+ DOCKER_REPOSITORY: "DOCKER_REPOSITORY"
45
+ }
46
+ };
47
+
48
+ await dockerCleanTags(context);
49
+
50
+ expect(docker.getToken).toHaveBeenCalledWith("DOCKER_HUB_ID", "DOCKER_HUB_PWD");
51
+ expect(docker.getTags).toHaveBeenCalledWith({
52
+ token: "token",
53
+ repository: "DOCKER_REPOSITORY"
54
+ });
55
+ expect(docker.deleteTag).toHaveBeenCalledWith("branch-2", {
56
+ token: "token",
57
+ repository: "DOCKER_REPOSITORY"
58
+ });
59
+ expect(docker.deleteTag).toHaveBeenCalledTimes(1);
60
+ });
61
+ });
@@ -0,0 +1,23 @@
1
+ import { docker } from "../../common/cli/docker.js";
2
+ import { getConfig } from "../../common/get-config.js";
3
+
4
+ export async function dockerPublish(context) {
5
+ context.config = getConfig();
6
+ const {
7
+ logger,
8
+ config: { PRODUCTION_BRANCH, DOCKER_REPOSITORY, DOCKER_HUB_ID, DOCKER_HUB_PWD }
9
+ } = context;
10
+
11
+ docker.login("-u", DOCKER_HUB_ID, "-p", DOCKER_HUB_PWD);
12
+
13
+ const image =
14
+ PRODUCTION_BRANCH === context.branch.name
15
+ ? `${DOCKER_REPOSITORY}:${context.nextRelease.version}`
16
+ : `${DOCKER_REPOSITORY}:${context.branch.name}`;
17
+ logger.info("context.branch.name : ", context.branch.name);
18
+ logger.info("context.nextRelease.version : ", context.nextRelease && context.nextRelease.version);
19
+ logger.info("PRODUCTION_BRANCH : ", PRODUCTION_BRANCH);
20
+ docker.tag(`${DOCKER_REPOSITORY}:latest`, image);
21
+
22
+ await docker.push(image);
23
+ }
@@ -0,0 +1,44 @@
1
+ import { docker } from "../../common/cli/docker.js";
2
+ import { getConfig } from "../../common/get-config.js";
3
+ import { dockerPublish } from "./docker-publish.js";
4
+
5
+ vi.mock("../../common/cli/docker.js", () => {
6
+ return {
7
+ docker: {
8
+ login: vi.fn(),
9
+ tag: vi.fn(),
10
+ push: vi.fn()
11
+ }
12
+ };
13
+ });
14
+
15
+ vi.mock("../../common/get-config.js", () => {
16
+ return {
17
+ getConfig: vi.fn()
18
+ };
19
+ });
20
+
21
+ describe("dockerPublish", () => {
22
+ it("should publish docker image", async () => {
23
+ getConfig.mockReturnValue({
24
+ PRODUCTION_BRANCH: "production",
25
+ DOCKER_REPOSITORY: "owner",
26
+ DOCKER_HUB_ID: "login",
27
+ DOCKER_HUB_PWD: "password"
28
+ });
29
+ const context = {
30
+ logger: {
31
+ info: vi.fn(),
32
+ warn: vi.fn()
33
+ },
34
+ branch: {
35
+ name: "branch-name"
36
+ }
37
+ };
38
+ await dockerPublish(context);
39
+
40
+ expect(docker.login).toHaveBeenCalledWith("-u", "login", "-p", "password");
41
+ expect(docker.tag).toHaveBeenCalledWith("owner:latest", "owner:branch-name");
42
+ expect(docker.push).toHaveBeenCalledWith("owner:branch-name");
43
+ });
44
+ });
@@ -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,5 @@
1
+ import omit from "lodash/omit.js";
2
+
3
+ import { WORKFLOW_CONFIGURATION } from "../../workflow/index.js";
4
+
5
+ export const releaseRules = WORKFLOW_CONFIGURATION.map((props) => omit(props, ["label"]));
@@ -0,0 +1,75 @@
1
+ import { WORKFLOW_CONFIGURATION } from "../../workflow/index.js";
2
+
3
+ const commitTypeMapping = WORKFLOW_CONFIGURATION.reduce((obj, { type, label }) => {
4
+ return {
5
+ ...obj,
6
+ [type]: label
7
+ };
8
+ }, {});
9
+
10
+ const transformCommitType = (commit) => {
11
+ if (commitTypeMapping[commit.type]) {
12
+ return commitTypeMapping[commit.type];
13
+ }
14
+
15
+ return commitTypeMapping.default;
16
+ };
17
+
18
+ export function transformWriter(commit, context) {
19
+ const issues = [];
20
+
21
+ commit.notes.forEach((note) => {
22
+ note.title = "BREAKING CHANGES";
23
+ });
24
+
25
+ commit.type = transformCommitType(commit);
26
+
27
+ if (commit.message && commit.message.match(/^[\w-]+$/i)) {
28
+ return;
29
+ }
30
+
31
+ if (commit.subject) {
32
+ commit.subject = commit.subject.replace("[MEP]", "");
33
+ }
34
+
35
+ if (commit.scope === "*") {
36
+ commit.scope = "";
37
+ }
38
+
39
+ if (typeof commit.hash === "string") {
40
+ commit.shortHash = commit.hash.substring(0, 7);
41
+ }
42
+
43
+ if (typeof commit.subject === "string") {
44
+ let url = context.repository ? `${context.host}/${context.owner}/${context.repository}` : context.repoUrl;
45
+ if (url) {
46
+ url = `${url}/issues/`;
47
+ // Issue URLs.
48
+ commit.subject = commit.subject.replace(/#([0-9]+)/g, (_, issue) => {
49
+ issues.push(issue);
50
+ return `[#${issue}](${url}${issue})`;
51
+ });
52
+ }
53
+ if (context.host) {
54
+ // User URLs.
55
+ commit.subject = commit.subject.replace(/\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g, (_, username) => {
56
+ if (username.includes("/")) {
57
+ return `@${username}`;
58
+ }
59
+
60
+ return `[@${username}](${context.host}/${username})`;
61
+ });
62
+ }
63
+ }
64
+
65
+ // remove references that already appear in the subject
66
+ commit.references = commit.references.filter((reference) => {
67
+ if (issues.indexOf(reference.issue) === -1) {
68
+ return true;
69
+ }
70
+
71
+ return false;
72
+ });
73
+
74
+ return commit;
75
+ }