@cmflow/cli 2.3.1 → 3.0.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.
package/.yarn/install-state.gz
CHANGED
|
Binary file
|
package/README.md
CHANGED
|
@@ -331,16 +331,12 @@ Note: Jira versions are expected to follow `<COMPONENT>-<version>` or similar. F
|
|
|
331
331
|
### Detailed behavior
|
|
332
332
|
1. Fetch all Jira versions for the project (`projectId`).
|
|
333
333
|
2. Keep those whose version (after stripping `component-`, `version-`, and `v` prefixes) is semver <= the provided `--tag`.
|
|
334
|
-
3.
|
|
335
|
-
|
|
336
|
-
- `Sous-tâche` → `tech`
|
|
337
|
-
- `Tâche` → `chore`
|
|
338
|
-
- `Bug` → `fix`
|
|
339
|
-
4. Print the delivery note to stdout (example below).
|
|
340
|
-
5. If `--update` is provided:
|
|
334
|
+
3. Print the delivery note to stdout (example below).
|
|
335
|
+
4. If `--update` is provided:
|
|
341
336
|
- Mark the relevant version(s) as `released=true` with `releaseDate=YYYY-MM-DD` (today's date).
|
|
342
|
-
|
|
343
|
-
|
|
337
|
+
5. If the Directus config is complete, trigger the workflow by passing the list of `version` values for the processed releases.
|
|
338
|
+
|
|
339
|
+
> Important: moving issue isn't supported from the cmflow. You have to create a jira automation script to move the issue on your board.
|
|
344
340
|
|
|
345
341
|
### Example
|
|
346
342
|
|
|
@@ -365,23 +361,6 @@ Raw CLI example:
|
|
|
365
361
|
cm jira-releases --project-id CMAB --component API --tag v0.3241.3 --update
|
|
366
362
|
```
|
|
367
363
|
|
|
368
|
-
### Example of generated note
|
|
369
|
-
The console output includes a share-ready message (note: the tool prints the message in French by default):
|
|
370
|
-
|
|
371
|
-
```text
|
|
372
|
-
Hello,
|
|
373
|
-
We will deploy to production version <TAG> of the <COMPONENT>
|
|
374
|
-
Here is what this delivery includes:
|
|
375
|
-
|
|
376
|
-
- v<version>:
|
|
377
|
-
- feat(CMAB-123): Story title
|
|
378
|
-
- fix(CMAB-456): XYZ fix
|
|
379
|
-
|
|
380
|
-
The API team
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
The exact structure may vary depending on how many versions are included and which issues are associated.
|
|
384
|
-
|
|
385
364
|
### Best practices
|
|
386
365
|
- Use a valid semver `--tag` (the `v`/`version-` prefixes are accepted).
|
|
387
366
|
- Ensure your Jira versions follow a consistent schema that includes the component (`<COMPONENT>-<version>`) to allow matching.
|
package/package.json
CHANGED
|
@@ -3,28 +3,10 @@ import figures from "figures";
|
|
|
3
3
|
import moment from "moment";
|
|
4
4
|
|
|
5
5
|
import { triggerDirectusFlow } from "../common/back/directus/directus-flow.js";
|
|
6
|
-
import {
|
|
7
|
-
import { jiraIssueMoveTo } from "../common/back/jira/jira-issue-move-to.js";
|
|
6
|
+
import { getSortedReleases } from "../common/back/jira/get-sorted-releases.js";
|
|
8
7
|
import { updateJiraRelease } from "../common/back/jira/jira-releases.js";
|
|
9
8
|
import { getConfig } from "../common/index.js";
|
|
10
9
|
|
|
11
|
-
const TYPES = {
|
|
12
|
-
Story: "feat",
|
|
13
|
-
"Sous-tâche": "tech",
|
|
14
|
-
Tâche: "chore",
|
|
15
|
-
Bug: "fix"
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
function getSummary(issue) {
|
|
19
|
-
return issue.fields.summary
|
|
20
|
-
.replace("CLONE -", "")
|
|
21
|
-
.replace("[FEAT]", "")
|
|
22
|
-
.replace(/\[(.*)]:/, "$1 -")
|
|
23
|
-
.replace("[BUG]", "")
|
|
24
|
-
.replace("[FIX]", "")
|
|
25
|
-
.trim();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
10
|
export class JiraReleases {
|
|
29
11
|
mapContext(commander, context) {
|
|
30
12
|
return {
|
|
@@ -46,35 +28,26 @@ export class JiraReleases {
|
|
|
46
28
|
{
|
|
47
29
|
title: `List all releases under ${context.tag} for ${context.component} component and ${context.projectId} project`,
|
|
48
30
|
task: async () => {
|
|
49
|
-
context.releases = await
|
|
31
|
+
context.releases = (await getSortedReleases(context.projectId, context.component, context.tag))
|
|
32
|
+
.filter(Boolean)
|
|
33
|
+
.filter((release) => release.released === false);
|
|
50
34
|
}
|
|
51
35
|
},
|
|
52
36
|
{
|
|
53
37
|
title: `Update ${context.tag} on ${context.component} component`,
|
|
54
|
-
skip: () => !context.update,
|
|
38
|
+
skip: () => !context.update || context.releases.length === 0,
|
|
55
39
|
task: async () => {
|
|
56
|
-
for (const release of context.releases
|
|
40
|
+
for (const release of context.releases) {
|
|
57
41
|
release.released = true;
|
|
58
42
|
release.releaseDate = moment().format("YYYY-MM-DD");
|
|
59
43
|
|
|
60
44
|
await updateJiraRelease(release);
|
|
61
|
-
|
|
62
|
-
await Promise.all(
|
|
63
|
-
release.issues.map((issue) => {
|
|
64
|
-
return jiraIssueMoveTo(issue, {
|
|
65
|
-
id: "18",
|
|
66
|
-
name: "Livré en production"
|
|
67
|
-
}).catch((er) => {
|
|
68
|
-
console.error(chalk.red(figures.cross), `Error moving issue ${issue.key} to production: ${er.message}`);
|
|
69
|
-
});
|
|
70
|
-
})
|
|
71
|
-
);
|
|
72
45
|
}
|
|
73
46
|
}
|
|
74
47
|
},
|
|
75
48
|
{
|
|
76
49
|
title: `Trigger CMS API Workflow`,
|
|
77
|
-
skip: () => !getConfig().CAN_TRIGGER_WORKFLOW,
|
|
50
|
+
skip: () => !getConfig().CAN_TRIGGER_WORKFLOW || context.releases.length === 0,
|
|
78
51
|
task: () => {
|
|
79
52
|
return triggerDirectusFlow(
|
|
80
53
|
context.projectId,
|
|
@@ -86,32 +59,4 @@ export class JiraReleases {
|
|
|
86
59
|
}
|
|
87
60
|
];
|
|
88
61
|
}
|
|
89
|
-
|
|
90
|
-
success(context) {
|
|
91
|
-
console.log(chalk.green(figures.tick), "Release notes generated successfully");
|
|
92
|
-
console.log("\n");
|
|
93
|
-
|
|
94
|
-
const note = `Bonjour,
|
|
95
|
-
Nous allons livrer en production la version ${context.tag} de l'${context.component}
|
|
96
|
-
Au menu de cette livraison :
|
|
97
|
-
|
|
98
|
-
${context.releases
|
|
99
|
-
.filter(Boolean)
|
|
100
|
-
.reverse()
|
|
101
|
-
.map((release) => {
|
|
102
|
-
const issues =
|
|
103
|
-
release.issues?.map((issue) => {
|
|
104
|
-
return ` - ${TYPES[issue.fields.issuetype.name] || issue.fields.issuetype.name}(${issue.key}): ${getSummary(issue)}`;
|
|
105
|
-
}) || [];
|
|
106
|
-
|
|
107
|
-
return issues.length ? (context.releases.length > 1 ? "- v" + release.version + ":\n" : "") + issues.join(",\n") : false;
|
|
108
|
-
})
|
|
109
|
-
.filter((line) => line !== false)
|
|
110
|
-
.join("\n\n")}
|
|
111
|
-
|
|
112
|
-
L'Equipe API
|
|
113
|
-
`;
|
|
114
|
-
|
|
115
|
-
console.log(note);
|
|
116
|
-
}
|
|
117
62
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import semver from "semver";
|
|
2
2
|
|
|
3
|
-
import { getJiraReleases
|
|
3
|
+
import { getJiraReleases } from "./jira-releases.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Returns all releases under the tag version for the given project and component.
|
|
@@ -8,7 +8,7 @@ import { getJiraReleases, getJiraVersionRelatedIssues } from "./jira-releases.js
|
|
|
8
8
|
* @param component {string}
|
|
9
9
|
* @param tagVersion {string}
|
|
10
10
|
*/
|
|
11
|
-
export async function
|
|
11
|
+
export async function getSortedReleases(projectId, component, tagVersion) {
|
|
12
12
|
const releases = await getJiraReleases(projectId);
|
|
13
13
|
|
|
14
14
|
const promises = releases
|
|
@@ -25,11 +25,6 @@ export async function jiraGetReleasesAndIssues(projectId, component, tagVersion)
|
|
|
25
25
|
})
|
|
26
26
|
.sort((ra, rb) => {
|
|
27
27
|
return semver.rcompare(ra.version, rb.version);
|
|
28
|
-
})
|
|
29
|
-
.map(async (release) => {
|
|
30
|
-
const { issues } = await getJiraVersionRelatedIssues(projectId, release.name);
|
|
31
|
-
release.issues = issues;
|
|
32
|
-
return release;
|
|
33
28
|
});
|
|
34
29
|
|
|
35
30
|
const [current, ...others] = await Promise.all(promises);
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { jiraRequest } from "./jira-request.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Moves a JIRA issue to the correct state using the specified transition.
|
|
5
|
-
* @param issue
|
|
6
|
-
* @param toTransition
|
|
7
|
-
* @return {Promise<void>}
|
|
8
|
-
*/
|
|
9
|
-
export async function jiraIssueMoveTo(issue, toTransition) {
|
|
10
|
-
/**
|
|
11
|
-
* {
|
|
12
|
-
* transitions: {
|
|
13
|
-
* id: string;
|
|
14
|
-
* name: string;
|
|
15
|
-
* to: { id: string; name: string };
|
|
16
|
-
* }[];
|
|
17
|
-
* }
|
|
18
|
-
*/
|
|
19
|
-
const { transitions } = await jiraRequest(`/rest/api/3/issue/${issue.key}/transitions`);
|
|
20
|
-
const transition = transitions.find((transition) => {
|
|
21
|
-
return transition.id === toTransition.id;
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
if (transition) {
|
|
25
|
-
await jiraRequest(`/rest/api/3/issue/${issue.key}/transitions`, {
|
|
26
|
-
method: "post",
|
|
27
|
-
headers: {
|
|
28
|
-
"Content-Type": "application/json",
|
|
29
|
-
Accept: "application/json"
|
|
30
|
-
},
|
|
31
|
-
body: {
|
|
32
|
-
transition: {
|
|
33
|
-
id: transition.id
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
}
|