deploy-vir 3.4.3 → 3.5.0
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/dist/commit.d.ts +4 -2
- package/dist/commit.js +59 -3
- package/dist/git.js +8 -6
- package/dist/notifications/slack.js +6 -5
- package/package.json +19 -19
- package/src/commit.ts +82 -5
- package/src/git.ts +8 -9
- package/src/notifications/slack.ts +11 -7
package/dist/commit.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PartialWithUndefined } from '@augment-vir/common';
|
|
1
2
|
import { type DefaultLogFields, type ListLogLine } from 'simple-git';
|
|
2
3
|
/**
|
|
3
4
|
* A git commit.
|
|
@@ -8,8 +9,9 @@ export type Commit = DefaultLogFields & ListLogLine;
|
|
|
8
9
|
/**
|
|
9
10
|
* Extract the human author name for a commit. Commits authored by a bot (a name with a `[bot]`
|
|
10
11
|
* suffix, like GitHub's merge queue bot) are attributed to their first non-bot `Co-authored-by:`
|
|
11
|
-
* trailer instead.
|
|
12
|
+
* trailer instead. If the commit has no such trailer, its pull request's first non-bot assignee is
|
|
13
|
+
* used (requires the `gh` CLI). All fallbacks resolve to the original bot name.
|
|
12
14
|
*
|
|
13
15
|
* @category Internal
|
|
14
16
|
*/
|
|
15
|
-
export declare function getCommitAuthorName(commit: Readonly<Pick<Commit, 'author_name' | 'body'
|
|
17
|
+
export declare function getCommitAuthorName(commit: Readonly<Pick<Commit, 'author_name' | 'body'> & PartialWithUndefined<Pick<Commit, 'hash' | 'message'>>>): Promise<string>;
|
package/dist/commit.js
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
|
+
import { check } from '@augment-vir/assert';
|
|
2
|
+
import { extractErrorMessage, log } from '@augment-vir/common';
|
|
3
|
+
import { runShellCommand } from '@augment-vir/node';
|
|
1
4
|
const coAuthorRegExp = /^co[- \t]*authored[- \t]*by:(.*)$/gim;
|
|
5
|
+
const pullRequestNumberRegExp = /#(\d+)/;
|
|
2
6
|
const botNameSuffix = '[bot]';
|
|
7
|
+
/**
|
|
8
|
+
* Each `gh` lookup is a network request and each commit's author name gets read more than once (CLI
|
|
9
|
+
* output and notifications), so results are cached by their lookup key.
|
|
10
|
+
*/
|
|
11
|
+
const pullRequestAssigneeCache = new Map();
|
|
3
12
|
/**
|
|
4
13
|
* Extract the human author name for a commit. Commits authored by a bot (a name with a `[bot]`
|
|
5
14
|
* suffix, like GitHub's merge queue bot) are attributed to their first non-bot `Co-authored-by:`
|
|
6
|
-
* trailer instead.
|
|
15
|
+
* trailer instead. If the commit has no such trailer, its pull request's first non-bot assignee is
|
|
16
|
+
* used (requires the `gh` CLI). All fallbacks resolve to the original bot name.
|
|
7
17
|
*
|
|
8
18
|
* @category Internal
|
|
9
19
|
*/
|
|
10
|
-
export function getCommitAuthorName(commit) {
|
|
20
|
+
export async function getCommitAuthorName(commit) {
|
|
11
21
|
if (!commit.author_name.endsWith(botNameSuffix)) {
|
|
12
22
|
return commit.author_name;
|
|
13
23
|
}
|
|
@@ -15,5 +25,51 @@ export function getCommitAuthorName(commit) {
|
|
|
15
25
|
/** Strip the trailing `<email>` from each trailer. */
|
|
16
26
|
.map((match) => (match[1] || '').split('<')[0]?.trim())
|
|
17
27
|
.find((name) => name && !name.endsWith(botNameSuffix));
|
|
18
|
-
return coAuthorName || commit.author_name;
|
|
28
|
+
return coAuthorName || (await getPullRequestAssigneeName(commit)) || commit.author_name;
|
|
29
|
+
}
|
|
30
|
+
function getPullRequestAssigneeName(commit) {
|
|
31
|
+
const pullRequestNumber = commit.message?.match(pullRequestNumberRegExp)?.[1];
|
|
32
|
+
const cacheKey = pullRequestNumber || commit.hash;
|
|
33
|
+
if (!cacheKey) {
|
|
34
|
+
return Promise.resolve(undefined);
|
|
35
|
+
}
|
|
36
|
+
const cached = pullRequestAssigneeCache.get(cacheKey);
|
|
37
|
+
if (cached) {
|
|
38
|
+
return cached;
|
|
39
|
+
}
|
|
40
|
+
const pending = fetchPullRequestAssigneeName(pullRequestNumber
|
|
41
|
+
? `gh pr view ${pullRequestNumber} --json assignees`
|
|
42
|
+
: `gh pr list --search ${cacheKey} --state merged --limit 1 --json assignees`);
|
|
43
|
+
pullRequestAssigneeCache.set(cacheKey, pending);
|
|
44
|
+
return pending;
|
|
45
|
+
}
|
|
46
|
+
async function fetchPullRequestAssigneeName(command) {
|
|
47
|
+
try {
|
|
48
|
+
const output = await runShellCommand(command, {
|
|
49
|
+
rejectOnError: true,
|
|
50
|
+
});
|
|
51
|
+
return extractAssigneeName(JSON.parse(output.stdout));
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
log.faint(`Failed to read a pull request assignee: ${extractErrorMessage(error)}`);
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function extractAssigneeName(parsedJson) {
|
|
59
|
+
/** `gh pr list` outputs an array, `gh pr view` outputs a single pull request. */
|
|
60
|
+
const pullRequest = check.isArray(parsedJson) ? parsedJson[0] : parsedJson;
|
|
61
|
+
if (!check.hasKey(pullRequest, 'assignees') || !check.isArray(pullRequest.assignees)) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
return pullRequest.assignees
|
|
65
|
+
.map((assignee) => {
|
|
66
|
+
const name = check.hasKey(assignee, 'name') && check.isString(assignee.name)
|
|
67
|
+
? assignee.name
|
|
68
|
+
: '';
|
|
69
|
+
const login = check.hasKey(assignee, 'login') && check.isString(assignee.login)
|
|
70
|
+
? assignee.login
|
|
71
|
+
: '';
|
|
72
|
+
return name || login;
|
|
73
|
+
})
|
|
74
|
+
.find((name) => name && !name.endsWith(botNameSuffix));
|
|
19
75
|
}
|
package/dist/git.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { assert, assertWrap, check } from '@augment-vir/assert';
|
|
2
|
-
import { awaitedBlockingMap, log, logColors } from '@augment-vir/common';
|
|
2
|
+
import { awaitedBlockingMap, awaitedForEach, log, logColors } from '@augment-vir/common';
|
|
3
3
|
import { confirm } from '@inquirer/prompts';
|
|
4
4
|
import { getCommitAuthorName } from './commit.js';
|
|
5
5
|
import { KnownError } from './known.error.js';
|
|
@@ -13,7 +13,9 @@ export async function getGitRemoteName(git, repoConfig) {
|
|
|
13
13
|
assert.isTruthy(repoConfig.name, 'Repo config name cannot be empty.');
|
|
14
14
|
assert.isTruthy(repoConfig.gitUrl, 'Repo git URL cannot be empty.');
|
|
15
15
|
const remotes = await git.getRemotes(true);
|
|
16
|
-
const remoteMatchByUrl = remotes.find((remote) =>
|
|
16
|
+
const remoteMatchByUrl = remotes.find((remote) => {
|
|
17
|
+
return remote.refs.fetch === repoConfig.gitUrl || remote.refs.push === repoConfig.gitUrl;
|
|
18
|
+
});
|
|
17
19
|
if (remoteMatchByUrl) {
|
|
18
20
|
return remoteMatchByUrl.name;
|
|
19
21
|
}
|
|
@@ -65,13 +67,13 @@ export async function pushDeploy(git, branchConfig, repoConfig, remoteName, noti
|
|
|
65
67
|
])).all;
|
|
66
68
|
const requiresForcePush = commitsBehind.length > 0;
|
|
67
69
|
log.info(`\n${requiresForcePush ? 'Only on' : 'Releasing from'} ${logColors.bold}${fromBranch}${logColors.reset}:`);
|
|
68
|
-
commitsAhead
|
|
69
|
-
log.faint(` ${index + 1}. ${commit.hash.slice(0, 7)} (${getCommitAuthorName(commit)}) - ${commit.message}`);
|
|
70
|
+
await awaitedForEach(commitsAhead, async (commit, index) => {
|
|
71
|
+
log.faint(` ${index + 1}. ${commit.hash.slice(0, 7)} (${await getCommitAuthorName(commit)}) - ${commit.message}`);
|
|
70
72
|
});
|
|
71
73
|
if (requiresForcePush) {
|
|
72
74
|
log.info(`\nOnly on ${logColors.bold}${toBranch}${logColors.reset}:`);
|
|
73
|
-
commitsBehind
|
|
74
|
-
log.faint(` ${index + 1}. ${commit.hash.slice(0, 7)} (${getCommitAuthorName(commit)}) - ${commit.message}`);
|
|
75
|
+
await awaitedForEach(commitsBehind, async (commit, index) => {
|
|
76
|
+
log.faint(` ${index + 1}. ${commit.hash.slice(0, 7)} (${await getCommitAuthorName(commit)}) - ${commit.message}`);
|
|
75
77
|
});
|
|
76
78
|
}
|
|
77
79
|
const shouldPush = bypassConfirmation ||
|
|
@@ -9,12 +9,13 @@ function truncateString(value, truncateAt = 100) {
|
|
|
9
9
|
return value;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
-
function formatCommit(baseCommitUrl, commit) {
|
|
12
|
+
async function formatCommit(baseCommitUrl, commit) {
|
|
13
|
+
const authorName = await getCommitAuthorName(commit);
|
|
13
14
|
if (baseCommitUrl) {
|
|
14
|
-
return `<${joinUrlPaths(baseCommitUrl, commit.hash)}|${commit.hash.slice(0, 7)}> (${
|
|
15
|
+
return `<${joinUrlPaths(baseCommitUrl, commit.hash)}|${commit.hash.slice(0, 7)}> (${authorName}) ${truncateString(commit.message)}`;
|
|
15
16
|
}
|
|
16
17
|
else {
|
|
17
|
-
return `${commit.hash.slice(0, 7)} (${
|
|
18
|
+
return `${commit.hash.slice(0, 7)} (${authorName}) ${truncateString(commit.message)}`;
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
const slackMaxSectionLength = 2500;
|
|
@@ -43,8 +44,8 @@ function chunkSectionLines(lines) {
|
|
|
43
44
|
* @category Internal
|
|
44
45
|
*/
|
|
45
46
|
export async function sendNotificationToSlack({ deployResult: { deployCommits: { deployedCommits, overwrittenCommits }, branchStatus: { after, before }, toBranchName, }, hookResult, notification, repoConfig, }) {
|
|
46
|
-
const deployedCommitBullets = deployedCommits.map((commit) => formatCommit(repoConfig.commitBaseUrl, commit));
|
|
47
|
-
const overwrittenCommitBullets = overwrittenCommits.map((commit) => formatCommit(repoConfig.commitBaseUrl, commit));
|
|
47
|
+
const deployedCommitBullets = await Promise.all(deployedCommits.map(async (commit) => await formatCommit(repoConfig.commitBaseUrl, commit)));
|
|
48
|
+
const overwrittenCommitBullets = await Promise.all(overwrittenCommits.map(async (commit) => await formatCommit(repoConfig.commitBaseUrl, commit)));
|
|
48
49
|
const deployedCommitBulletLines = deployedCommitBullets.map((bullet) => `- ${bullet}`);
|
|
49
50
|
const overwrittenCommitBulletLines = overwrittenCommitBullets.length
|
|
50
51
|
? overwrittenCommitBullets.map((bullet) => `- ${bullet}`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deploy-vir",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "Deploy a branch to another branch with notifications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deploy",
|
|
@@ -42,39 +42,39 @@
|
|
|
42
42
|
"test:update": "npm run test update"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@augment-vir/assert": "^32.2.
|
|
46
|
-
"@augment-vir/common": "^32.2.
|
|
47
|
-
"@augment-vir/node": "^32.2.
|
|
45
|
+
"@augment-vir/assert": "^32.2.2",
|
|
46
|
+
"@augment-vir/common": "^32.2.2",
|
|
47
|
+
"@augment-vir/node": "^32.2.2",
|
|
48
48
|
"@inquirer/prompts": "^8.5.2",
|
|
49
49
|
"@slack/web-api": "^8.0.0",
|
|
50
|
-
"cli-vir": "^1.0.
|
|
50
|
+
"cli-vir": "^1.0.5",
|
|
51
51
|
"simple-git": "^3.36.0",
|
|
52
|
-
"tsx": "^4.23.
|
|
53
|
-
"url-vir": "^2.1
|
|
52
|
+
"tsx": "^4.23.12",
|
|
53
|
+
"url-vir": "^2.2.1"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@augment-vir/test": "^32.2.
|
|
56
|
+
"@augment-vir/test": "^32.2.2",
|
|
57
57
|
"@eslint/eslintrc": "^3.3.6",
|
|
58
58
|
"@eslint/js": "^10.0.1",
|
|
59
59
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
60
60
|
"@stylistic/eslint-plugin-ts": "^4.4.1",
|
|
61
|
-
"@types/node": "^26.
|
|
62
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
61
|
+
"@types/node": "^26.2.0",
|
|
62
|
+
"@typescript-eslint/eslint-plugin": "^8.66.0",
|
|
63
63
|
"cspell": "^10.0.1",
|
|
64
|
-
"dependency-cruiser": "^18.1.
|
|
65
|
-
"esbuild": "^0.28.
|
|
66
|
-
"eslint": "^10.8.
|
|
64
|
+
"dependency-cruiser": "^18.1.1",
|
|
65
|
+
"esbuild": "^0.28.2",
|
|
66
|
+
"eslint": "^10.8.1",
|
|
67
67
|
"eslint-config-prettier": "^10.1.8",
|
|
68
|
-
"eslint-plugin-jsdoc": "^
|
|
68
|
+
"eslint-plugin-jsdoc": "^64.0.2",
|
|
69
69
|
"eslint-plugin-monorepo-cop": "^1.0.2",
|
|
70
|
-
"eslint-plugin-playwright": "^2.
|
|
70
|
+
"eslint-plugin-playwright": "^2.11.0",
|
|
71
71
|
"eslint-plugin-prettier": "^5.5.6",
|
|
72
72
|
"eslint-plugin-require-extensions": "^0.1.3",
|
|
73
73
|
"eslint-plugin-sonarjs": "^4.2.0",
|
|
74
|
-
"eslint-plugin-unicorn": "^
|
|
74
|
+
"eslint-plugin-unicorn": "^73.0.0",
|
|
75
75
|
"istanbul-smart-text-reporter": "^1.1.5",
|
|
76
76
|
"markdown-code-example-inserter": "^3.0.6",
|
|
77
|
-
"npm-check-updates": "^
|
|
77
|
+
"npm-check-updates": "^23.0.2",
|
|
78
78
|
"prettier": "~3.3.3",
|
|
79
79
|
"prettier-plugin-interpolated-html-tags": "^2.0.2",
|
|
80
80
|
"prettier-plugin-jsdoc": "^1.8.1",
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"runstorm": "^1.0.6",
|
|
87
87
|
"typedoc": "^0.28.20",
|
|
88
88
|
"typescript": "^6.0.3",
|
|
89
|
-
"typescript-eslint": "^8.
|
|
90
|
-
"virmator": "^14.30.
|
|
89
|
+
"typescript-eslint": "^8.66.0",
|
|
90
|
+
"virmator": "^14.30.6"
|
|
91
91
|
},
|
|
92
92
|
"engines": {
|
|
93
93
|
"node": ">=22"
|
package/src/commit.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {check} from '@augment-vir/assert';
|
|
2
|
+
import {extractErrorMessage, log, type PartialWithUndefined} from '@augment-vir/common';
|
|
3
|
+
import {runShellCommand} from '@augment-vir/node';
|
|
1
4
|
import {type DefaultLogFields, type ListLogLine} from 'simple-git';
|
|
2
5
|
|
|
3
6
|
/**
|
|
@@ -8,18 +11,29 @@ import {type DefaultLogFields, type ListLogLine} from 'simple-git';
|
|
|
8
11
|
export type Commit = DefaultLogFields & ListLogLine;
|
|
9
12
|
|
|
10
13
|
const coAuthorRegExp = /^co[- \t]*authored[- \t]*by:(.*)$/gim;
|
|
14
|
+
const pullRequestNumberRegExp = /#(\d+)/;
|
|
11
15
|
const botNameSuffix = '[bot]';
|
|
12
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Each `gh` lookup is a network request and each commit's author name gets read more than once (CLI
|
|
19
|
+
* output and notifications), so results are cached by their lookup key.
|
|
20
|
+
*/
|
|
21
|
+
const pullRequestAssigneeCache = new Map<string, Promise<string | undefined>>();
|
|
22
|
+
|
|
13
23
|
/**
|
|
14
24
|
* Extract the human author name for a commit. Commits authored by a bot (a name with a `[bot]`
|
|
15
25
|
* suffix, like GitHub's merge queue bot) are attributed to their first non-bot `Co-authored-by:`
|
|
16
|
-
* trailer instead.
|
|
26
|
+
* trailer instead. If the commit has no such trailer, its pull request's first non-bot assignee is
|
|
27
|
+
* used (requires the `gh` CLI). All fallbacks resolve to the original bot name.
|
|
17
28
|
*
|
|
18
29
|
* @category Internal
|
|
19
30
|
*/
|
|
20
|
-
export function getCommitAuthorName(
|
|
21
|
-
commit: Readonly<
|
|
22
|
-
|
|
31
|
+
export async function getCommitAuthorName(
|
|
32
|
+
commit: Readonly<
|
|
33
|
+
Pick<Commit, 'author_name' | 'body'> &
|
|
34
|
+
PartialWithUndefined<Pick<Commit, 'hash' | 'message'>>
|
|
35
|
+
>,
|
|
36
|
+
): Promise<string> {
|
|
23
37
|
if (!commit.author_name.endsWith(botNameSuffix)) {
|
|
24
38
|
return commit.author_name;
|
|
25
39
|
}
|
|
@@ -29,5 +43,68 @@ export function getCommitAuthorName(
|
|
|
29
43
|
.map((match) => (match[1] || '').split('<')[0]?.trim())
|
|
30
44
|
.find((name) => name && !name.endsWith(botNameSuffix));
|
|
31
45
|
|
|
32
|
-
return coAuthorName || commit.author_name;
|
|
46
|
+
return coAuthorName || (await getPullRequestAssigneeName(commit)) || commit.author_name;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getPullRequestAssigneeName(
|
|
50
|
+
commit: Readonly<PartialWithUndefined<Pick<Commit, 'hash' | 'message'>>>,
|
|
51
|
+
): Promise<string | undefined> {
|
|
52
|
+
const pullRequestNumber = commit.message?.match(pullRequestNumberRegExp)?.[1];
|
|
53
|
+
const cacheKey = pullRequestNumber || commit.hash;
|
|
54
|
+
|
|
55
|
+
if (!cacheKey) {
|
|
56
|
+
return Promise.resolve(undefined);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const cached = pullRequestAssigneeCache.get(cacheKey);
|
|
60
|
+
|
|
61
|
+
if (cached) {
|
|
62
|
+
return cached;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const pending = fetchPullRequestAssigneeName(
|
|
66
|
+
pullRequestNumber
|
|
67
|
+
? `gh pr view ${pullRequestNumber} --json assignees`
|
|
68
|
+
: `gh pr list --search ${cacheKey} --state merged --limit 1 --json assignees`,
|
|
69
|
+
);
|
|
70
|
+
pullRequestAssigneeCache.set(cacheKey, pending);
|
|
71
|
+
|
|
72
|
+
return pending;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function fetchPullRequestAssigneeName(command: string): Promise<string | undefined> {
|
|
76
|
+
try {
|
|
77
|
+
const output = await runShellCommand(command, {
|
|
78
|
+
rejectOnError: true,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return extractAssigneeName(JSON.parse(output.stdout));
|
|
82
|
+
} catch (error) {
|
|
83
|
+
log.faint(`Failed to read a pull request assignee: ${extractErrorMessage(error)}`);
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function extractAssigneeName(parsedJson: unknown): string | undefined {
|
|
89
|
+
/** `gh pr list` outputs an array, `gh pr view` outputs a single pull request. */
|
|
90
|
+
const pullRequest = check.isArray(parsedJson) ? parsedJson[0] : parsedJson;
|
|
91
|
+
|
|
92
|
+
if (!check.hasKey(pullRequest, 'assignees') || !check.isArray(pullRequest.assignees)) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return pullRequest.assignees
|
|
97
|
+
.map((assignee) => {
|
|
98
|
+
const name =
|
|
99
|
+
check.hasKey(assignee, 'name') && check.isString(assignee.name)
|
|
100
|
+
? assignee.name
|
|
101
|
+
: '';
|
|
102
|
+
const login =
|
|
103
|
+
check.hasKey(assignee, 'login') && check.isString(assignee.login)
|
|
104
|
+
? assignee.login
|
|
105
|
+
: '';
|
|
106
|
+
|
|
107
|
+
return name || login;
|
|
108
|
+
})
|
|
109
|
+
.find((name) => name && !name.endsWith(botNameSuffix));
|
|
33
110
|
}
|
package/src/git.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {assert, assertWrap, check} from '@augment-vir/assert';
|
|
2
|
-
import {awaitedBlockingMap, log, logColors} from '@augment-vir/common';
|
|
2
|
+
import {awaitedBlockingMap, awaitedForEach, log, logColors} from '@augment-vir/common';
|
|
3
3
|
import {confirm} from '@inquirer/prompts';
|
|
4
4
|
import {type SimpleGit} from 'simple-git';
|
|
5
5
|
import {getCommitAuthorName, type Commit} from './commit.js';
|
|
@@ -27,10 +27,9 @@ export async function getGitRemoteName(
|
|
|
27
27
|
|
|
28
28
|
const remotes = await git.getRemotes(true);
|
|
29
29
|
|
|
30
|
-
const remoteMatchByUrl = remotes.find(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
);
|
|
30
|
+
const remoteMatchByUrl = remotes.find((remote) => {
|
|
31
|
+
return remote.refs.fetch === repoConfig.gitUrl || remote.refs.push === repoConfig.gitUrl;
|
|
32
|
+
});
|
|
34
33
|
|
|
35
34
|
if (remoteMatchByUrl) {
|
|
36
35
|
return remoteMatchByUrl.name;
|
|
@@ -157,17 +156,17 @@ export async function pushDeploy(
|
|
|
157
156
|
log.info(
|
|
158
157
|
`\n${requiresForcePush ? 'Only on' : 'Releasing from'} ${logColors.bold}${fromBranch}${logColors.reset}:`,
|
|
159
158
|
);
|
|
160
|
-
commitsAhead
|
|
159
|
+
await awaitedForEach(commitsAhead, async (commit, index) => {
|
|
161
160
|
log.faint(
|
|
162
|
-
` ${index + 1}. ${commit.hash.slice(0, 7)} (${getCommitAuthorName(commit)}) - ${commit.message}`,
|
|
161
|
+
` ${index + 1}. ${commit.hash.slice(0, 7)} (${await getCommitAuthorName(commit)}) - ${commit.message}`,
|
|
163
162
|
);
|
|
164
163
|
});
|
|
165
164
|
|
|
166
165
|
if (requiresForcePush) {
|
|
167
166
|
log.info(`\nOnly on ${logColors.bold}${toBranch}${logColors.reset}:`);
|
|
168
|
-
commitsBehind
|
|
167
|
+
await awaitedForEach(commitsBehind, async (commit, index) => {
|
|
169
168
|
log.faint(
|
|
170
|
-
` ${index + 1}. ${commit.hash.slice(0, 7)} (${getCommitAuthorName(commit)}) - ${commit.message}`,
|
|
169
|
+
` ${index + 1}. ${commit.hash.slice(0, 7)} (${await getCommitAuthorName(commit)}) - ${commit.message}`,
|
|
171
170
|
);
|
|
172
171
|
});
|
|
173
172
|
}
|
|
@@ -15,11 +15,13 @@ function truncateString(value: string, truncateAt = 100): string {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
function formatCommit(baseCommitUrl: string | undefined, commit: Readonly<Commit>) {
|
|
18
|
+
async function formatCommit(baseCommitUrl: string | undefined, commit: Readonly<Commit>) {
|
|
19
|
+
const authorName = await getCommitAuthorName(commit);
|
|
20
|
+
|
|
19
21
|
if (baseCommitUrl) {
|
|
20
|
-
return `<${joinUrlPaths(baseCommitUrl, commit.hash)}|${commit.hash.slice(0, 7)}> (${
|
|
22
|
+
return `<${joinUrlPaths(baseCommitUrl, commit.hash)}|${commit.hash.slice(0, 7)}> (${authorName}) ${truncateString(commit.message)}`;
|
|
21
23
|
} else {
|
|
22
|
-
return `${commit.hash.slice(0, 7)} (${
|
|
24
|
+
return `${commit.hash.slice(0, 7)} (${authorName}) ${truncateString(commit.message)}`;
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
|
|
@@ -65,11 +67,13 @@ export async function sendNotificationToSlack({
|
|
|
65
67
|
notification,
|
|
66
68
|
repoConfig,
|
|
67
69
|
}: Readonly<NotificationParams>) {
|
|
68
|
-
const deployedCommitBullets =
|
|
69
|
-
formatCommit(repoConfig.commitBaseUrl, commit),
|
|
70
|
+
const deployedCommitBullets = await Promise.all(
|
|
71
|
+
deployedCommits.map(async (commit) => await formatCommit(repoConfig.commitBaseUrl, commit)),
|
|
70
72
|
);
|
|
71
|
-
const overwrittenCommitBullets =
|
|
72
|
-
|
|
73
|
+
const overwrittenCommitBullets = await Promise.all(
|
|
74
|
+
overwrittenCommits.map(
|
|
75
|
+
async (commit) => await formatCommit(repoConfig.commitBaseUrl, commit),
|
|
76
|
+
),
|
|
73
77
|
);
|
|
74
78
|
|
|
75
79
|
const deployedCommitBulletLines = deployedCommitBullets.map((bullet) => `- ${bullet}`);
|