@uxf/scripts 11.14.0 → 11.23.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxf/scripts",
3
- "version": "11.14.0",
3
+ "version": "11.23.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -26,7 +26,6 @@
26
26
  "author": "",
27
27
  "license": "ISC",
28
28
  "dependencies": {
29
- "@commitlint/parse": "19.0.3",
30
29
  "axios": "1.6.7",
31
30
  "cheerio": "1.0.0-rc.12",
32
31
  "dayjs": "1.11.10",
package/src/GitLab.js CHANGED
@@ -1,7 +1,6 @@
1
1
  const { env } = require("process");
2
2
  const { create } = require("axios");
3
3
  const dayjs = require("dayjs");
4
- const parse = import("@commitlint/parse");
5
4
 
6
5
  const axios = create({
7
6
  baseURL: `${env.CI_SERVER_URL}/api/v4`,
@@ -36,7 +35,6 @@ async function getAll(url, config) {
36
35
 
37
36
  async function loadCommits(from) {
38
37
  const commits = [];
39
- console.log(`- start date: ${from}`);
40
38
 
41
39
  let nextPage = "1";
42
40
  do {
@@ -52,38 +50,7 @@ async function loadCommits(from) {
52
50
  commits.push(...response.data);
53
51
  } while (nextPage);
54
52
 
55
- const preparedCommits = [];
56
- for (const commit of commits) {
57
- if (commit.created_at === from) {
58
- continue;
59
- }
60
-
61
- const parsedTitle = await parse(commit.title, undefined, { issuePrefixes: ["#"] });
62
-
63
- preparedCommits.push({
64
- ...commit,
65
- parsedTitle: {
66
- scope: parsedTitle.scope,
67
- type: parsedTitle.type,
68
- subject: (parsedTitle.subject || commit.title).replace(/(#[0-9]*)/g, "").trim(),
69
- },
70
- issueIds: parsedTitle.references.map((ref) => Number.parseInt(ref.issue)).filter((i) => !!i),
71
- });
72
- }
73
-
74
- return preparedCommits;
75
- }
76
-
77
- async function loadIssues(iids) {
78
- if (iids.length === 0) {
79
- return [];
80
- }
81
-
82
- const { data } = await axios.get(`/projects/${env.CI_PROJECT_ID}/issues`, {
83
- params: { iids },
84
- });
85
-
86
- return data;
53
+ return commits.filter((commit) => commit.created_at !== from);
87
54
  }
88
55
 
89
56
  async function getLastTag() {
@@ -121,11 +88,14 @@ function getSingleMergeRequestChanges(projectId, mr_iid) {
121
88
  return axios.get(`/projects/${projectId}/merge_requests/${mr_iid}/changes`).then((r) => r.data);
122
89
  }
123
90
 
124
- function getAllMergeRequests() {
91
+ /**
92
+ * @param {boolean} includeWip
93
+ */
94
+ function getAllMergeRequests(includeWip) {
125
95
  return getAll("/merge_requests", {
126
96
  params: {
127
97
  approwed: "no",
128
- wip: "no",
98
+ wip: includeWip ? undefined : "no",
129
99
  sort: "asc",
130
100
  scope: "all",
131
101
  state: "opened",
@@ -140,7 +110,6 @@ function getAllProjects() {
140
110
 
141
111
  module.exports = {
142
112
  loadCommits,
143
- loadIssues,
144
113
  getLastTag,
145
114
  createRelease,
146
115
  getAllMergeRequests,
@@ -1,12 +1,15 @@
1
1
  const { argv, env } = require("process");
2
2
 
3
+ const AVAILABLE_VARIANTS = ["CR", "STALE"];
4
+
3
5
  module.exports = async () => {
4
6
  const cli = require("yargs")
5
7
  .command("$0", "UXF merge requests notifier", (yargs) => {
6
8
  yargs.demandCommand(0, 0).usage(`Usage:
7
9
  uxf-merge-requests-notifier [options]
8
-
10
+
9
11
  Environment variables:
12
+ VARIANT - optional - CR (default), STALE
10
13
  GITLAB_TOKEN - required
11
14
  GOOGLE_WEBHOOK_URL - required
12
15
  CI_SERVER_URL - required - setting by GitLab CI`);
@@ -32,7 +35,14 @@ Environment variables:
32
35
  return 1;
33
36
  }
34
37
 
35
- await require("./index")();
38
+ const variant = env.VARIANT?.toUpperCase() ?? "CR";
39
+
40
+ if (!AVAILABLE_VARIANTS.includes(variant)) {
41
+ console.log(`Unknown "${variant}" variant. Available variants are ${AVAILABLE_VARIANTS.join(", ")}.`);
42
+ return 1;
43
+ }
44
+
45
+ await require("./index")(variant);
36
46
  } catch (e) {
37
47
  console.error(e);
38
48
  return 1;
@@ -10,41 +10,59 @@ function inflect(value, word1, word2, word3) {
10
10
  return `${value} ${value === 1 ? word1 : value <= 4 ? word2 : word3}`;
11
11
  }
12
12
 
13
- module.exports = async function run() {
13
+ function mapMergeRequests(mrs, projects) {
14
+ return mrs.map((mr) => ({
15
+ id: mr.id,
16
+ iid: mr.iid,
17
+ reviewers: mr.reviewers ?? [],
18
+ project: projects.find((project) => project.id === mr.project_id),
19
+ title: mr.title,
20
+ author: mr.author,
21
+ createdAt: mr.created_at,
22
+ updatedAt: mr.updated_at,
23
+ webUrl: mr.web_url,
24
+ state: mr.state.toUpperCase(),
25
+ targetBranch: mr.target_branch,
26
+ sourceBranch: mr.source_branch,
27
+ }));
28
+ }
29
+
30
+ function getChatPostMessage(resultsCount, variant) {
31
+ switch (variant) {
32
+ case "CR":
33
+ return `🔥🔥🔥 ${inflect(resultsCount, "MR čekající na code review", "MR čekající na code review", "MR čekajících na code review",)}`;
34
+ case "STALE":
35
+ return `❗❗❗ ${inflect(resultsCount, "MR starší než měsíc", "MR starší než měsíc", "MR starších než měsíc")}`;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * @param variant
41
+ */
42
+ module.exports = async function run(variant) {
14
43
  const projects = await GitLab.getAllProjects();
15
- const allMergeRequests = await GitLab.getAllMergeRequests();
44
+ const allMergeRequests = await GitLab.getAllMergeRequests(variant === "STALE");
16
45
 
17
- const result = allMergeRequests
18
- .map((mr) => ({
19
- id: mr.id,
20
- iid: mr.iid,
21
- reviewers: mr.reviewers ?? [],
22
- project: projects.find((project) => project.id === mr.project_id),
23
- title: mr.title,
24
- author: mr.author,
25
- createdAt: mr.created_at,
26
- updatedAt: mr.updated_at,
27
- webUrl: mr.web_url,
28
- state: mr.state.toUpperCase(),
29
- targetBranch: mr.target_branch,
30
- sourceBranch: mr.source_branch,
31
- }))
32
- .filter((mr) => mr.reviewers.length === 0)
46
+ let result = mapMergeRequests(allMergeRequests, projects)
33
47
  .filter((mr) => mr.sourceBranch !== "develop" || mr.targetBranch !== "master")
34
48
  .filter((mr) => !mr.project.archived);
35
49
 
50
+ switch (variant) {
51
+ case "CR":
52
+ result = result.filter((mr) => mr.reviewers.length === 0);
53
+ break;
54
+ case "STALE":
55
+ result = result.filter(mr => dayjs().diff(mr.updatedAt, "days") > 30);
56
+ break;
57
+ }
58
+
36
59
  if (result.length === 0) {
37
- console.log("No merge requests to code review.");
60
+ console.log("No merge requests.");
38
61
  return;
39
62
  }
40
63
 
41
64
  await GoogleChat.chatPostMessage({
42
- text: `🔥🔥🔥 ${inflect(
43
- result.length,
44
- "MR čekající na code review",
45
- "MR čekající na code review",
46
- "MR čekajících na code review",
47
- )}`,
65
+ text: getChatPostMessage(result.length, variant),
48
66
  });
49
67
 
50
68
  for (const mr of result) {
@@ -2,16 +2,17 @@ const { argv, env } = require("process");
2
2
 
3
3
  module.exports = async () => {
4
4
  const cli = require("yargs")
5
- .command("$0", "UXF release helper", yargs => {
5
+ .command("$0", "UXF release helper", (yargs) => {
6
6
  yargs.demandCommand(0, 0).usage(`UXF release helper
7
7
  Usage:
8
8
  uxf-release [options]
9
9
 
10
10
  Environment variables:
11
- GITLAB_TOKEN - required
12
- CI_SERVER_URL - required - setting by GitLab CI
13
- CI_PROJECT_ID - required - setting by GitLab CI
14
- SLACK_TOKEN - optional`);
11
+ GITLAB_TOKEN - required
12
+ CI_SERVER_URL - required - setting by GitLab CI
13
+ CI_PROJECT_ID - required - setting by GitLab CI
14
+ SLACK_TOKEN - optional
15
+ GOOGLE_WEBHOOK_URL - optional`);
15
16
  })
16
17
  .option("m", {
17
18
  alias: "message",
@@ -55,11 +56,6 @@ Environment variables:
55
56
  env.CI_PROJECT_ID = projectId;
56
57
  }
57
58
 
58
- if (!slackChannel) {
59
- console.log("Slack channel must be set. Use parameter -s or --slack-channel");
60
- return 1;
61
- }
62
-
63
59
  if (!env.CI_SERVER_URL) {
64
60
  console.log("GitLab url must be set. Use environment variable CI_SERVER_URL.");
65
61
  return 1;
@@ -2,98 +2,129 @@ const GitLab = require("../GitLab");
2
2
  const Slack = require("../Slack");
3
3
  const GoogleChat = require("../GoogleChat");
4
4
 
5
- function addCommitsToIssues(commits, issues) {
6
- issues.forEach(issue => {
7
- if (issue.commits === undefined) {
8
- issue.commits = [];
9
- }
10
- });
11
-
12
- commits.forEach(commit => {
13
- if (commit.issueIds.length > 0) {
14
- issues.forEach(issue => {
15
- if (commit.issueIds.includes(issue.iid)) {
16
- issue.commits.push(commit);
17
- }
18
- });
19
- }
20
- });
5
+ function parseCommitMessage(commitMessage) {
6
+ /* fix(bo): [KLK-123] commit message */
7
+ const result = /^(.*)\((.*)\): \[(.*)\] (.*)/.exec(commitMessage);
8
+
9
+ if (result !== null) {
10
+ return {
11
+ type: result[1],
12
+ issues: result[3].replace(" ", "").split(","),
13
+ message: result[4],
14
+ };
15
+ }
16
+
17
+ /* fix: [KLK-123] commit message */
18
+ const result_1 = /^(.*): \[(.*)\] (.*)/.exec(commitMessage);
19
+
20
+ if (result_1 !== null) {
21
+ return {
22
+ type: result_1[1],
23
+ issues: result_1[3].replace(" ", "").split(","),
24
+ message: result_1[4],
25
+ };
26
+ }
27
+
28
+ /* [KLK-123] commit message */
29
+ const result_2 = /^\[(.*)\] (.*)/.exec(commitMessage);
30
+
31
+ if (result_2 !== null) {
32
+ return {
33
+ type: null,
34
+ issues: result_2[1].replace(" ", "").split(","),
35
+ message: result_2[2],
36
+ };
37
+ }
38
+
39
+ return null;
40
+ }
41
+
42
+ function generateSlackCommitMessage(commit) {
43
+ const { title, short_id, web_url, author_email } = commit;
44
+
45
+ const parsedCommit = parseCommitMessage(title);
46
+
47
+ return parsedCommit?.type
48
+ ? `• _${parsedCommit.type.toUpperCase()}_ - ${parsedCommit.message} <${web_url}|${short_id}> (${author_email})`
49
+ : `• ${title} <${web_url}|${short_id}> (${author_email})`;
21
50
  }
22
51
 
23
- function getIssueIdsFromCommits(commits) {
24
- const ids = [];
25
- commits.forEach(c => ids.push(...c.issueIds));
26
- return ids.filter((v, i, s) => s.indexOf(v) === i);
52
+ function generateSlackMessage(commits, messageTitle) {
53
+ return {
54
+ text: `${messageTitle}
55
+
56
+ ${commits.map(generateSlackCommitMessage).join("\n")}
57
+ `,
58
+ };
27
59
  }
28
60
 
29
- function generateSlackMessage(issues, commitsWithoutIssues, messageTitle) {
30
- let message = messageTitle;
61
+ function generateGoogleCommitMessage(commit) {
62
+ const { title, short_id, web_url, author_email } = commit;
63
+ const parsedCommit = parseCommitMessage(title);
64
+
65
+ const issues = parsedCommit?.issues.map((issue) => `<https://youtrack.uxf.dev/issue/${issue}|${issue}>`) ?? [];
31
66
 
32
- issues.forEach(issue => {
33
- message += `\n\n*${issue.title}* <${issue.web_url}|#${issue.iid}>\n${issue.commits
34
- .map(generateSlackCommitMessage)
35
- .join("\n")}`;
36
- });
67
+ const suffix = [`<${web_url}|${short_id}>`, author_email, issues.length > 0 ? issues.join(", ") : null]
68
+ .filter((i) => !!i)
69
+ .join(" | ");
37
70
 
38
- if (commitsWithoutIssues.length > 0) {
39
- message += `\n\n*Commity bez issue*\n${commitsWithoutIssues.map(generateSlackCommitMessage).join("\n")}`;
71
+ if (parsedCommit === null) {
72
+ return `* ${title} ${suffix}`;
40
73
  }
41
74
 
42
- return message;
43
- }
75
+ if (parsedCommit.type !== null && parsedCommit.message !== null) {
76
+ return `* _${parsedCommit.type.toUpperCase()}_ ${parsedCommit.message} ${suffix}`;
77
+ }
44
78
 
45
- function generateGoogleMessage(issues, commitsWithoutIssues, messageTitle) {
46
- const texts = [messageTitle];
47
- issues.forEach(issue => {
48
- texts.push(`*${issue.title}* <${issue.web_url}|#${issue.iid}>`);
49
- issue.commits.forEach((commit) => texts.push(generateSlackCommitMessage(commit)));
50
- });
51
- if (commitsWithoutIssues.length > 0) {
52
- texts.push(`*Commity bez issue*`);
53
- commitsWithoutIssues.forEach((commit) => texts.push(generateSlackCommitMessage(commit)));
79
+ if (parsedCommit.message) {
80
+ return `* ${parsedCommit.message} ${suffix}`;
54
81
  }
82
+
83
+ return `* ${title} ${suffix}`;
84
+ }
85
+
86
+ function generateGoogleMessage(commits, messageTitle) {
55
87
  return {
56
- text: texts.join('\n')
88
+ text: `${messageTitle}
89
+
90
+ ${commits.map(generateGoogleCommitMessage).join("\n")}
91
+ `,
57
92
  };
58
93
  }
59
94
 
60
- function generateSlackCommitMessage(commit) {
61
- const { title, parsedTitle, short_id, web_url, author_email } = commit;
95
+ function generateReleaseCommitMessage(commit) {
96
+ const { title, short_id, web_url, author_email } = commit;
62
97
 
63
- return parsedTitle.type
64
- ? `• _${parsedTitle.type.toUpperCase()}_ ${parsedTitle.scope} - ${
65
- parsedTitle.subject
66
- } <${web_url}|${short_id}> (${author_email})`
67
- : `• ${title} <${web_url}|${short_id}> (${author_email})`;
68
- }
98
+ const parsedCommit = parseCommitMessage(title);
99
+
100
+ const issues = parsedCommit?.issues.map((issue) => `[${issue}](https://youtrack.uxf.dev/issue/${issue})`) ?? [];
69
101
 
70
- function generateCommitMessage(commit) {
71
- const { title, parsedTitle, short_id, web_url, author_email } = commit;
102
+ const suffix = [`[${short_id}](${web_url})`, author_email, issues.length > 0 ? issues.join(", ") : null]
103
+ .filter((i) => !!i)
104
+ .join(" | ");
72
105
 
73
- return parsedTitle.type
74
- ? `- **${parsedTitle.type.toUpperCase()}** ${parsedTitle.subject} [${short_id}](${web_url}) (${author_email})`
75
- : `- ${title} [${short_id}](${web_url}) (${author_email})`;
106
+ if (parsedCommit === null) {
107
+ return `- ${title} ${suffix}`;
108
+ }
109
+
110
+ if (parsedCommit.type !== null && parsedCommit.message !== null) {
111
+ return `- **${parsedCommit.type.toUpperCase()}** ${parsedCommit.message} ${suffix}`;
112
+ }
113
+
114
+ if (parsedCommit.message) {
115
+ return `- ${parsedCommit.message} ${suffix}`;
116
+ }
117
+
118
+ return `- ${title} ${suffix}`;
76
119
  }
77
120
 
78
121
  module.exports = async (dryRun, channel, messageTitle) => {
79
122
  const lastTag = await GitLab.getLastTag();
80
123
  const commits = await GitLab.loadCommits(lastTag ? lastTag.commit.committed_date : null);
81
- const issues = await GitLab.loadIssues(getIssueIdsFromCommits(commits));
82
-
83
- addCommitsToIssues(commits, issues);
84
-
85
- const commitsWithoutIssue = commits.filter(c => c.issueIds.length === 0);
86
124
 
87
- await Slack.chatPostMessage(
88
- channel,
89
- { text: generateSlackMessage(issues, commitsWithoutIssue, messageTitle) },
90
- dryRun,
91
- );
125
+ await Slack.chatPostMessage(channel, { text: generateSlackMessage(commits, messageTitle) }, dryRun);
92
126
 
93
- await GoogleChat.chatPostMessage(
94
- generateGoogleMessage(issues, commitsWithoutIssue, messageTitle),
95
- dryRun,
96
- );
127
+ await GoogleChat.chatPostMessage(generateGoogleMessage(commits, messageTitle), dryRun);
97
128
 
98
- await GitLab.createRelease(commits.map(generateCommitMessage).join("\n"), dryRun);
129
+ await GitLab.createRelease(commits.map(generateReleaseCommitMessage).join("\n"), dryRun);
99
130
  };