deploy-vir 0.2.8 → 0.3.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/git.js +41 -52
- package/dist/notifications/notification-params.d.ts +1 -1
- package/dist/notifications/slack.js +52 -20
- package/package.json +27 -25
- package/src/git.ts +54 -65
- package/src/notifications/notification-params.ts +1 -1
- package/src/notifications/slack.ts +60 -21
package/dist/git.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { assert, assertWrap, check } from '@augment-vir/assert';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { log, logColors } from '@augment-vir/common';
|
|
3
|
+
import { confirm } from '@inquirer/prompts';
|
|
4
4
|
import { KnownError } from './known.error.js';
|
|
5
5
|
/**
|
|
6
6
|
* Find the git remote's name, or create a new one.
|
|
@@ -54,56 +54,45 @@ export async function pushDeploy(git, { deployName, fromBranch, toBranch }, remo
|
|
|
54
54
|
if (!commitsAhead.length) {
|
|
55
55
|
throw new KnownError('No commit diff: nothing to deploy!');
|
|
56
56
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
log.error(`Push failed: ${extractErrorMessage(error)}`);
|
|
72
|
-
/** Get commits that are on {@link toBranch} but not on {@link fromBranch}. */
|
|
73
|
-
const commitsBehind = (await git.log([
|
|
74
|
-
`${remoteName}/${fromBranch}..${remoteName}/${toBranch}`,
|
|
75
|
-
])).all;
|
|
76
|
-
if (commitsBehind.length > 0) {
|
|
77
|
-
log.info(`\nOnly on ${logColors.bold}${fromBranch}${logColors.reset}:`);
|
|
78
|
-
commitsAhead.forEach((commit, index) => {
|
|
79
|
-
log.faint(` ${index + 1}. ${commit.hash.slice(0, 7)} (${commit.author_name}) - ${commit.message}`);
|
|
80
|
-
});
|
|
81
|
-
log.info(`\nOnly on ${logColors.bold}${toBranch}${logColors.reset}:`);
|
|
82
|
-
commitsBehind.forEach((commit, index) => {
|
|
83
|
-
log.faint(` ${index + 1}. ${commit.hash.slice(0, 7)} (${commit.author_name}) - ${commit.message}`);
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
const shouldForcePush = await askQuestion(`\nDo you want to force push ${logColors.bold}${fromBranch}${logColors.reset} to ${logColors.bold}${toBranch}${logColors.reset}?\n\n${logColors.warning}This will overwrite the commits only on ${logColors.bold}${toBranch}${logColors.normalWeight}.${logColors.reset} (y/N): `, {
|
|
87
|
-
timeout: {
|
|
88
|
-
hours: 2,
|
|
89
|
-
},
|
|
57
|
+
/** Get commits that are on {@link toBranch} but not on {@link fromBranch}. */
|
|
58
|
+
const commitsBehind = (await git.log([
|
|
59
|
+
`${remoteName}/${fromBranch}..${remoteName}/${toBranch}`,
|
|
60
|
+
])).all;
|
|
61
|
+
const requiresForcePush = commitsBehind.length > 0;
|
|
62
|
+
log.info(`\n${requiresForcePush ? 'Only on' : 'Releasing from'} ${logColors.bold}${fromBranch}${logColors.reset}:`);
|
|
63
|
+
commitsAhead.forEach((commit, index) => {
|
|
64
|
+
log.faint(` ${index + 1}. ${commit.hash.slice(0, 7)} (${commit.author_name}) - ${commit.message}`);
|
|
65
|
+
});
|
|
66
|
+
if (requiresForcePush) {
|
|
67
|
+
log.info(`\nOnly on ${logColors.bold}${toBranch}${logColors.reset}:`);
|
|
68
|
+
commitsBehind.forEach((commit, index) => {
|
|
69
|
+
log.faint(` ${index + 1}. ${commit.hash.slice(0, 7)} (${commit.author_name}) - ${commit.message}`);
|
|
90
70
|
});
|
|
91
|
-
if (shouldForcePush.toLowerCase() === 'y' || shouldForcePush.toLowerCase() === 'yes') {
|
|
92
|
-
await git.push(remoteName, pushString, ['--force']);
|
|
93
|
-
log.warning(`Force pushed ${logColors.bold}${fromBranch}${logColors.reset} to ${logColors.bold}${toBranch}${logColors.reset}.`);
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
throw new KnownError(`Deploy aborted.`);
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
deployCommits: {
|
|
100
|
-
deployedCommits: commitsAhead,
|
|
101
|
-
overwrittenCommits: commitsBehind,
|
|
102
|
-
},
|
|
103
|
-
branchStatus: {
|
|
104
|
-
before: beforeCommit,
|
|
105
|
-
after: afterCommit,
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
71
|
}
|
|
72
|
+
const shouldPush = await confirm({
|
|
73
|
+
message: requiresForcePush
|
|
74
|
+
? `\n${logColors.warning}Do you want to force push ${logColors.bold}${fromBranch}${logColors.normalWeight} to ${logColors.bold}${toBranch}${logColors.normalWeight}?\n\nThis will overwrite the commits only on ${logColors.bold}${toBranch}${logColors.normalWeight}.${logColors.reset}?`
|
|
75
|
+
: 'Ready to deploy?',
|
|
76
|
+
default: false,
|
|
77
|
+
});
|
|
78
|
+
if (!shouldPush) {
|
|
79
|
+
throw new KnownError(`Deploy aborted.`);
|
|
80
|
+
}
|
|
81
|
+
if (requiresForcePush) {
|
|
82
|
+
await git.push(remoteName, pushString, ['--force']);
|
|
83
|
+
log.warning(`Force pushed ${logColors.bold}${fromBranch}${logColors.normalWeight} to ${logColors.bold}${toBranch}${logColors.reset}.`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
await git.push(remoteName, pushString);
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
deployCommits: {
|
|
90
|
+
deployedCommits: commitsAhead,
|
|
91
|
+
overwrittenCommits: commitsBehind,
|
|
92
|
+
},
|
|
93
|
+
branchStatus: {
|
|
94
|
+
before: beforeCommit,
|
|
95
|
+
after: afterCommit,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
109
98
|
}
|
|
@@ -8,7 +8,7 @@ import { type DeployResult } from '../git.js';
|
|
|
8
8
|
export type NotificationParams<Target extends NotificationTarget = NotificationTarget> = {
|
|
9
9
|
deployResult: Readonly<DeployResult>;
|
|
10
10
|
branchConfig: Readonly<DeployVirBranchConfig>;
|
|
11
|
-
repoConfig: Readonly<Pick<DeployVirRepoConfig, 'commitBaseUrl'>>;
|
|
11
|
+
repoConfig: Readonly<Pick<DeployVirRepoConfig, 'commitBaseUrl' | 'name'>>;
|
|
12
12
|
notification: Readonly<Extract<NotificationConfig, {
|
|
13
13
|
target: Target;
|
|
14
14
|
}>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addPrefix,
|
|
1
|
+
import { addPrefix, log, setFirstLetterCasing, StringCase } from '@augment-vir/common';
|
|
2
2
|
import { joinUrlPaths } from 'url-vir';
|
|
3
3
|
function truncateString(value, truncateAt = 100) {
|
|
4
4
|
if (value.length > truncateAt) {
|
|
@@ -16,6 +16,23 @@ function formatCommit(baseCommitUrl, commit) {
|
|
|
16
16
|
return `${commit.hash.slice(0, 7)} (${commit.author_name}) ${truncateString(commit.message)}`;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
const slackMaxSectionLength = 2500;
|
|
20
|
+
function pushAndGet(array, item) {
|
|
21
|
+
array.push(item);
|
|
22
|
+
return item;
|
|
23
|
+
}
|
|
24
|
+
function chunkSectionLines(lines) {
|
|
25
|
+
const sectionLines = [];
|
|
26
|
+
lines.forEach((line) => {
|
|
27
|
+
const latestSection = sectionLines.slice(-1)[0];
|
|
28
|
+
const currentSection = latestSection && latestSection.length + line.length < slackMaxSectionLength
|
|
29
|
+
? latestSection
|
|
30
|
+
: pushAndGet(sectionLines, { length: 0, lines: [] });
|
|
31
|
+
currentSection.length += line.length;
|
|
32
|
+
currentSection.lines.push(line);
|
|
33
|
+
});
|
|
34
|
+
return sectionLines.map(({ lines }) => lines);
|
|
35
|
+
}
|
|
19
36
|
/**
|
|
20
37
|
* Send a notification to Slack.
|
|
21
38
|
*
|
|
@@ -24,11 +41,9 @@ function formatCommit(baseCommitUrl, commit) {
|
|
|
24
41
|
export async function sendNotificationToSlack({ branchConfig, deployResult: { deployCommits: { deployedCommits, overwrittenCommits }, branchStatus: { after, before }, }, notification, repoConfig, }) {
|
|
25
42
|
const deployedCommitBullets = deployedCommits.map((commit) => formatCommit(repoConfig.commitBaseUrl, commit));
|
|
26
43
|
const overwrittenCommitBullets = overwrittenCommits.map((commit) => formatCommit(repoConfig.commitBaseUrl, commit));
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
.
|
|
30
|
-
const overwrittenCommitBulletsText = overwrittenCommitBullets.length
|
|
31
|
-
? overwrittenCommitBullets.map((bullet) => `- ${bullet}`).join('\n')
|
|
44
|
+
const deployedCommitBulletLines = deployedCommitBullets.map((bullet) => `- ${bullet}`);
|
|
45
|
+
const overwrittenCommitBulletLines = overwrittenCommitBullets.length
|
|
46
|
+
? overwrittenCommitBullets.map((bullet) => `- ${bullet}`)
|
|
32
47
|
: undefined;
|
|
33
48
|
const beforeText = repoConfig.commitBaseUrl
|
|
34
49
|
? `<${joinUrlPaths(repoConfig.commitBaseUrl, before.hash)}|${before.hash.slice(0, 7)}>`
|
|
@@ -36,23 +51,12 @@ export async function sendNotificationToSlack({ branchConfig, deployResult: { de
|
|
|
36
51
|
const afterText = repoConfig.commitBaseUrl
|
|
37
52
|
? `<${joinUrlPaths(repoConfig.commitBaseUrl, after.hash)}|${after.hash.slice(0, 7)}>`
|
|
38
53
|
: before.hash;
|
|
39
|
-
const overwrittenCommitBlocks = overwrittenCommitBulletsText
|
|
40
|
-
? [
|
|
41
|
-
{
|
|
42
|
-
type: 'section',
|
|
43
|
-
text: {
|
|
44
|
-
type: 'mrkdwn',
|
|
45
|
-
text: `\n*Overwritten Commits*\n${overwrittenCommitBulletsText}`,
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
]
|
|
49
|
-
: [];
|
|
50
54
|
const blocks = [
|
|
51
55
|
{
|
|
52
56
|
type: 'section',
|
|
53
57
|
text: {
|
|
54
58
|
type: 'mrkdwn',
|
|
55
|
-
text: `*${
|
|
59
|
+
text: `*${setFirstLetterCasing(repoConfig.name, StringCase.Upper)} ${setFirstLetterCasing(branchConfig.deployName, StringCase.Upper)}* Pushed`,
|
|
56
60
|
},
|
|
57
61
|
},
|
|
58
62
|
{
|
|
@@ -68,10 +72,38 @@ export async function sendNotificationToSlack({ branchConfig, deployResult: { de
|
|
|
68
72
|
type: 'section',
|
|
69
73
|
text: {
|
|
70
74
|
type: 'mrkdwn',
|
|
71
|
-
text: `\n*Deployed Commits*\n
|
|
75
|
+
text: `\n*Deployed Commits*\n`,
|
|
72
76
|
},
|
|
73
77
|
},
|
|
74
|
-
...
|
|
78
|
+
...chunkSectionLines(deployedCommitBulletLines).map((lines) => {
|
|
79
|
+
return {
|
|
80
|
+
type: 'section',
|
|
81
|
+
text: {
|
|
82
|
+
type: 'mrkdwn',
|
|
83
|
+
text: lines.join('\n'),
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}),
|
|
87
|
+
...(overwrittenCommitBulletLines?.length
|
|
88
|
+
? [
|
|
89
|
+
{
|
|
90
|
+
type: 'section',
|
|
91
|
+
text: {
|
|
92
|
+
type: 'mrkdwn',
|
|
93
|
+
text: `\n*Overwritten Commits*\n`,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
...chunkSectionLines(overwrittenCommitBulletLines).map((lines) => {
|
|
97
|
+
return {
|
|
98
|
+
type: 'section',
|
|
99
|
+
text: {
|
|
100
|
+
type: 'mrkdwn',
|
|
101
|
+
text: lines.join('\n'),
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}),
|
|
105
|
+
]
|
|
106
|
+
: []),
|
|
75
107
|
];
|
|
76
108
|
await sendSlackMessage(notification, {
|
|
77
109
|
attachments: [],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deploy-vir",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Deploy a branch to another branch with notifications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deploy",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"format": "virmator format",
|
|
33
33
|
"lint": "virmator lint fix",
|
|
34
34
|
"publish": "virmator publish npm run test:all",
|
|
35
|
-
"test:all": "npm run compile &&
|
|
35
|
+
"test:all": "npm run compile && runstorm --names spelling,format,docs,deps,lint \"npm run test:spelling\" \"npm run test:format\" \"npm run test:docs\" \"npm run test:deps\" \"npm run test:lint\"",
|
|
36
36
|
"test:deps": "virmator deps check",
|
|
37
37
|
"test:docs": "virmator docs check",
|
|
38
38
|
"test:format": "virmator format check",
|
|
@@ -41,37 +41,38 @@
|
|
|
41
41
|
"test:update": "npm run test update"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@augment-vir/assert": "^31.
|
|
45
|
-
"@augment-vir/common": "^31.
|
|
46
|
-
"@augment-vir/node": "^31.
|
|
47
|
-
"@
|
|
44
|
+
"@augment-vir/assert": "^31.33.0",
|
|
45
|
+
"@augment-vir/common": "^31.33.0",
|
|
46
|
+
"@augment-vir/node": "^31.33.0",
|
|
47
|
+
"@inquirer/prompts": "^7.8.4",
|
|
48
|
+
"@slack/web-api": "^7.10.0",
|
|
48
49
|
"simple-git": "^3.28.0",
|
|
49
|
-
"tsx": "^4.20.
|
|
50
|
-
"url-vir": "^2.1.
|
|
50
|
+
"tsx": "^4.20.5",
|
|
51
|
+
"url-vir": "^2.1.4"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@eslint/eslintrc": "^3.3.1",
|
|
54
|
-
"@eslint/js": "^9.
|
|
55
|
-
"@stylistic/eslint-plugin": "^5.2.
|
|
55
|
+
"@eslint/js": "^9.34.0",
|
|
56
|
+
"@stylistic/eslint-plugin": "^5.2.3",
|
|
56
57
|
"@stylistic/eslint-plugin-ts": "^4.4.1",
|
|
57
|
-
"@types/node": "^24.
|
|
58
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
58
|
+
"@types/node": "^24.3.0",
|
|
59
|
+
"@typescript-eslint/eslint-plugin": "^8.41.0",
|
|
59
60
|
"cspell": "^9.2.0",
|
|
60
|
-
"dependency-cruiser": "^17.0.
|
|
61
|
-
"esbuild": "^0.25.
|
|
62
|
-
"eslint": "^9.
|
|
61
|
+
"dependency-cruiser": "^17.0.1",
|
|
62
|
+
"esbuild": "^0.25.9",
|
|
63
|
+
"eslint": "^9.34.0",
|
|
63
64
|
"eslint-config-prettier": "^10.1.8",
|
|
64
|
-
"eslint-plugin-jsdoc": "^
|
|
65
|
+
"eslint-plugin-jsdoc": "^54.1.1",
|
|
65
66
|
"eslint-plugin-monorepo-cop": "^1.0.2",
|
|
66
|
-
"eslint-plugin-playwright": "^2.2.
|
|
67
|
-
"eslint-plugin-prettier": "^5.5.
|
|
67
|
+
"eslint-plugin-playwright": "^2.2.2",
|
|
68
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
68
69
|
"eslint-plugin-require-extensions": "^0.1.3",
|
|
69
|
-
"eslint-plugin-sonarjs": "^3.0.
|
|
70
|
+
"eslint-plugin-sonarjs": "^3.0.5",
|
|
70
71
|
"eslint-plugin-unicorn": "^57.0.0",
|
|
71
72
|
"istanbul-smart-text-reporter": "^1.1.5",
|
|
72
73
|
"markdown-code-example-inserter": "^3.0.3",
|
|
73
|
-
"npm-check-updates": "^18.0.
|
|
74
|
-
"prettier": "
|
|
74
|
+
"npm-check-updates": "^18.0.3",
|
|
75
|
+
"prettier": "~3.3.3",
|
|
75
76
|
"prettier-plugin-interpolated-html-tags": "^2.0.1",
|
|
76
77
|
"prettier-plugin-jsdoc": "^1.3.3",
|
|
77
78
|
"prettier-plugin-multiline-arrays": "^4.0.3",
|
|
@@ -79,10 +80,11 @@
|
|
|
79
80
|
"prettier-plugin-packagejson": "^2.5.19",
|
|
80
81
|
"prettier-plugin-sort-json": "^4.1.1",
|
|
81
82
|
"prettier-plugin-toml": "^2.0.6",
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"typescript
|
|
85
|
-
"
|
|
83
|
+
"runstorm": "^0.6.1",
|
|
84
|
+
"typedoc": "^0.28.11",
|
|
85
|
+
"typescript": "^5.9.2",
|
|
86
|
+
"typescript-eslint": "^8.41.0",
|
|
87
|
+
"virmator": "^14.0.1"
|
|
86
88
|
},
|
|
87
89
|
"engines": {
|
|
88
90
|
"node": ">=22"
|
package/src/git.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {assert, assertWrap, check} from '@augment-vir/assert';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import {log, logColors} from '@augment-vir/common';
|
|
3
|
+
import {confirm} from '@inquirer/prompts';
|
|
4
4
|
import {type DefaultLogFields, type ListLogLine, type SimpleGit} from 'simple-git';
|
|
5
5
|
import {type DeployVirBranchConfig, type DeployVirRepoConfig} from './config.js';
|
|
6
6
|
import {KnownError} from './known.error.js';
|
|
@@ -134,72 +134,61 @@ export async function pushDeploy(
|
|
|
134
134
|
throw new KnownError('No commit diff: nothing to deploy!');
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
/** Get commits that are on {@link toBranch} but not on {@link fromBranch}. */
|
|
138
|
+
const commitsBehind = (
|
|
139
|
+
await git.log([
|
|
140
|
+
`${remoteName}/${fromBranch}..${remoteName}/${toBranch}`,
|
|
141
|
+
])
|
|
142
|
+
).all;
|
|
139
143
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
},
|
|
149
|
-
};
|
|
150
|
-
} catch (error) {
|
|
151
|
-
log.error(`Push failed: ${extractErrorMessage(error)}`);
|
|
152
|
-
|
|
153
|
-
/** Get commits that are on {@link toBranch} but not on {@link fromBranch}. */
|
|
154
|
-
const commitsBehind = (
|
|
155
|
-
await git.log([
|
|
156
|
-
`${remoteName}/${fromBranch}..${remoteName}/${toBranch}`,
|
|
157
|
-
])
|
|
158
|
-
).all;
|
|
159
|
-
|
|
160
|
-
if (commitsBehind.length > 0) {
|
|
161
|
-
log.info(`\nOnly on ${logColors.bold}${fromBranch}${logColors.reset}:`);
|
|
162
|
-
commitsAhead.forEach((commit, index) => {
|
|
163
|
-
log.faint(
|
|
164
|
-
` ${index + 1}. ${commit.hash.slice(0, 7)} (${commit.author_name}) - ${commit.message}`,
|
|
165
|
-
);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
log.info(`\nOnly on ${logColors.bold}${toBranch}${logColors.reset}:`);
|
|
169
|
-
commitsBehind.forEach((commit, index) => {
|
|
170
|
-
log.faint(
|
|
171
|
-
` ${index + 1}. ${commit.hash.slice(0, 7)} (${commit.author_name}) - ${commit.message}`,
|
|
172
|
-
);
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const shouldForcePush = await askQuestion(
|
|
177
|
-
`\nDo you want to force push ${logColors.bold}${fromBranch}${logColors.reset} to ${logColors.bold}${toBranch}${logColors.reset}?\n\n${logColors.warning}This will overwrite the commits only on ${logColors.bold}${toBranch}${logColors.normalWeight}.${logColors.reset} (y/N): `,
|
|
178
|
-
{
|
|
179
|
-
timeout: {
|
|
180
|
-
hours: 2,
|
|
181
|
-
},
|
|
182
|
-
},
|
|
144
|
+
const requiresForcePush = commitsBehind.length > 0;
|
|
145
|
+
|
|
146
|
+
log.info(
|
|
147
|
+
`\n${requiresForcePush ? 'Only on' : 'Releasing from'} ${logColors.bold}${fromBranch}${logColors.reset}:`,
|
|
148
|
+
);
|
|
149
|
+
commitsAhead.forEach((commit, index) => {
|
|
150
|
+
log.faint(
|
|
151
|
+
` ${index + 1}. ${commit.hash.slice(0, 7)} (${commit.author_name}) - ${commit.message}`,
|
|
183
152
|
);
|
|
153
|
+
});
|
|
184
154
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
155
|
+
if (requiresForcePush) {
|
|
156
|
+
log.info(`\nOnly on ${logColors.bold}${toBranch}${logColors.reset}:`);
|
|
157
|
+
commitsBehind.forEach((commit, index) => {
|
|
158
|
+
log.faint(
|
|
159
|
+
` ${index + 1}. ${commit.hash.slice(0, 7)} (${commit.author_name}) - ${commit.message}`,
|
|
189
160
|
);
|
|
190
|
-
}
|
|
191
|
-
throw new KnownError(`Deploy aborted.`);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return {
|
|
195
|
-
deployCommits: {
|
|
196
|
-
deployedCommits: commitsAhead,
|
|
197
|
-
overwrittenCommits: commitsBehind,
|
|
198
|
-
},
|
|
199
|
-
branchStatus: {
|
|
200
|
-
before: beforeCommit,
|
|
201
|
-
after: afterCommit,
|
|
202
|
-
},
|
|
203
|
-
};
|
|
161
|
+
});
|
|
204
162
|
}
|
|
163
|
+
|
|
164
|
+
const shouldPush = await confirm({
|
|
165
|
+
message: requiresForcePush
|
|
166
|
+
? `\n${logColors.warning}Do you want to force push ${logColors.bold}${fromBranch}${logColors.normalWeight} to ${logColors.bold}${toBranch}${logColors.normalWeight}?\n\nThis will overwrite the commits only on ${logColors.bold}${toBranch}${logColors.normalWeight}.${logColors.reset}?`
|
|
167
|
+
: 'Ready to deploy?',
|
|
168
|
+
default: false,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
if (!shouldPush) {
|
|
172
|
+
throw new KnownError(`Deploy aborted.`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (requiresForcePush) {
|
|
176
|
+
await git.push(remoteName, pushString, ['--force']);
|
|
177
|
+
log.warning(
|
|
178
|
+
`Force pushed ${logColors.bold}${fromBranch}${logColors.normalWeight} to ${logColors.bold}${toBranch}${logColors.reset}.`,
|
|
179
|
+
);
|
|
180
|
+
} else {
|
|
181
|
+
await git.push(remoteName, pushString);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
deployCommits: {
|
|
186
|
+
deployedCommits: commitsAhead,
|
|
187
|
+
overwrittenCommits: commitsBehind,
|
|
188
|
+
},
|
|
189
|
+
branchStatus: {
|
|
190
|
+
before: beforeCommit,
|
|
191
|
+
after: afterCommit,
|
|
192
|
+
},
|
|
193
|
+
};
|
|
205
194
|
}
|
|
@@ -14,6 +14,6 @@ import {type DeployResult} from '../git.js';
|
|
|
14
14
|
export type NotificationParams<Target extends NotificationTarget = NotificationTarget> = {
|
|
15
15
|
deployResult: Readonly<DeployResult>;
|
|
16
16
|
branchConfig: Readonly<DeployVirBranchConfig>;
|
|
17
|
-
repoConfig: Readonly<Pick<DeployVirRepoConfig, 'commitBaseUrl'>>;
|
|
17
|
+
repoConfig: Readonly<Pick<DeployVirRepoConfig, 'commitBaseUrl' | 'name'>>;
|
|
18
18
|
notification: Readonly<Extract<NotificationConfig, {target: Target}>>;
|
|
19
19
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {addPrefix,
|
|
1
|
+
import {addPrefix, log, setFirstLetterCasing, StringCase} from '@augment-vir/common';
|
|
2
2
|
import {type ChatPostMessageArguments, type KnownBlock} from '@slack/web-api';
|
|
3
3
|
import {joinUrlPaths} from 'url-vir';
|
|
4
4
|
import {type SlackNotificationConfig} from '../config.js';
|
|
@@ -23,6 +23,30 @@ function formatCommit(baseCommitUrl: string | undefined, commit: Readonly<Commit
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
const slackMaxSectionLength = 2500;
|
|
27
|
+
|
|
28
|
+
function pushAndGet<T>(array: T[], item: T) {
|
|
29
|
+
array.push(item);
|
|
30
|
+
return item;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function chunkSectionLines(lines: ReadonlyArray<string>): string[][] {
|
|
34
|
+
const sectionLines: {length: number; lines: string[]}[] = [];
|
|
35
|
+
|
|
36
|
+
lines.forEach((line) => {
|
|
37
|
+
const latestSection = sectionLines.slice(-1)[0];
|
|
38
|
+
|
|
39
|
+
const currentSection =
|
|
40
|
+
latestSection && latestSection.length + line.length < slackMaxSectionLength
|
|
41
|
+
? latestSection
|
|
42
|
+
: pushAndGet(sectionLines, {length: 0, lines: []});
|
|
43
|
+
currentSection.length += line.length;
|
|
44
|
+
currentSection.lines.push(line);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return sectionLines.map(({lines}) => lines);
|
|
48
|
+
}
|
|
49
|
+
|
|
26
50
|
/**
|
|
27
51
|
* Send a notification to Slack.
|
|
28
52
|
*
|
|
@@ -44,12 +68,10 @@ export async function sendNotificationToSlack({
|
|
|
44
68
|
formatCommit(repoConfig.commitBaseUrl, commit),
|
|
45
69
|
);
|
|
46
70
|
|
|
47
|
-
const
|
|
48
|
-
.map((bullet) => `- ${bullet}`)
|
|
49
|
-
.join('\n');
|
|
71
|
+
const deployedCommitBulletLines = deployedCommitBullets.map((bullet) => `- ${bullet}`);
|
|
50
72
|
|
|
51
|
-
const
|
|
52
|
-
? overwrittenCommitBullets.map((bullet) => `- ${bullet}`)
|
|
73
|
+
const overwrittenCommitBulletLines = overwrittenCommitBullets.length
|
|
74
|
+
? overwrittenCommitBullets.map((bullet) => `- ${bullet}`)
|
|
53
75
|
: undefined;
|
|
54
76
|
|
|
55
77
|
const beforeText = repoConfig.commitBaseUrl
|
|
@@ -59,24 +81,12 @@ export async function sendNotificationToSlack({
|
|
|
59
81
|
? `<${joinUrlPaths(repoConfig.commitBaseUrl, after.hash)}|${after.hash.slice(0, 7)}>`
|
|
60
82
|
: before.hash;
|
|
61
83
|
|
|
62
|
-
const overwrittenCommitBlocks: KnownBlock[] = overwrittenCommitBulletsText
|
|
63
|
-
? [
|
|
64
|
-
{
|
|
65
|
-
type: 'section',
|
|
66
|
-
text: {
|
|
67
|
-
type: 'mrkdwn',
|
|
68
|
-
text: `\n*Overwritten Commits*\n${overwrittenCommitBulletsText}`,
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
]
|
|
72
|
-
: [];
|
|
73
|
-
|
|
74
84
|
const blocks: KnownBlock[] = [
|
|
75
85
|
{
|
|
76
86
|
type: 'section',
|
|
77
87
|
text: {
|
|
78
88
|
type: 'mrkdwn',
|
|
79
|
-
text: `*${
|
|
89
|
+
text: `*${setFirstLetterCasing(repoConfig.name, StringCase.Upper)} ${setFirstLetterCasing(branchConfig.deployName, StringCase.Upper)}* Pushed`,
|
|
80
90
|
},
|
|
81
91
|
},
|
|
82
92
|
{
|
|
@@ -92,10 +102,39 @@ export async function sendNotificationToSlack({
|
|
|
92
102
|
type: 'section',
|
|
93
103
|
text: {
|
|
94
104
|
type: 'mrkdwn',
|
|
95
|
-
text: `\n*Deployed Commits*\n
|
|
105
|
+
text: `\n*Deployed Commits*\n`,
|
|
96
106
|
},
|
|
97
107
|
},
|
|
98
|
-
...
|
|
108
|
+
...chunkSectionLines(deployedCommitBulletLines).map((lines): KnownBlock => {
|
|
109
|
+
return {
|
|
110
|
+
type: 'section',
|
|
111
|
+
text: {
|
|
112
|
+
type: 'mrkdwn',
|
|
113
|
+
text: lines.join('\n'),
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}),
|
|
117
|
+
...(overwrittenCommitBulletLines?.length
|
|
118
|
+
? ([
|
|
119
|
+
{
|
|
120
|
+
type: 'section',
|
|
121
|
+
text: {
|
|
122
|
+
type: 'mrkdwn',
|
|
123
|
+
text: `\n*Overwritten Commits*\n`,
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
...chunkSectionLines(overwrittenCommitBulletLines).map((lines): KnownBlock => {
|
|
128
|
+
return {
|
|
129
|
+
type: 'section',
|
|
130
|
+
text: {
|
|
131
|
+
type: 'mrkdwn',
|
|
132
|
+
text: lines.join('\n'),
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}),
|
|
136
|
+
] satisfies KnownBlock[])
|
|
137
|
+
: []),
|
|
99
138
|
];
|
|
100
139
|
|
|
101
140
|
await sendSlackMessage(notification, {
|