-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathrelease.mjs
170 lines (154 loc) · 5.19 KB
/
release.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import {
getLastTag,
parseCommits,
getCommits,
getCurrentVersion,
getNextVersion,
npmBumpVersion,
generateChangelog,
writeChangelog,
gitPushTags,
gitTag,
npmPublish,
gitCreateBranch,
gitCheckoutBranch,
gitAdd,
gitSetupSshRemote,
gitSetupUser,
getCurrentBranchName,
getSHA1fromRef,
gitWriteTree,
gitCommitTree,
gitUpdateRef,
gitPublishBranch,
gitSetRefOnCommit,
gitPush,
gitDeleteRemoteBranch,
} from "@coveo/semantic-monorepo-tools";
import angularChangelogConvention from "conventional-changelog-angular";
import { Octokit } from "octokit";
import { createAppAuth } from "@octokit/auth-app";
// Get all commits since last release bump the root package.json version.
(async () => {
//#region Constants
const PATH = ".";
const VERSION_PREFIX = "v";
const CONVENTION = await angularChangelogConvention();
const REPO_OWNER = "coveo";
const REPO_NAME = "semantic-monorepo-tools";
const GIT_USERNAME = "developer-experience-bot[bot]";
const GIT_EMAIL =
"91079284+developer-experience-bot[bot]@users.noreply.github.com";
const GIT_SSH_REMOTE = "deploy";
//#endregion
// #region Setup Git
await gitSetupSshRemote(
REPO_OWNER,
REPO_NAME,
process.env.DEPLOY_KEY,
GIT_SSH_REMOTE,
);
await gitSetupUser(GIT_USERNAME, GIT_EMAIL);
// #endregion
//#region GitHub authentication
const authSecrets = {
appId: process.env.RELEASER_APP_ID,
privateKey: process.env.RELEASER_PRIVATE_KEY,
clientId: process.env.RELEASER_CLIENT_ID,
clientSecret: process.env.RELEASER_CLIENT_SECRET,
installationId: process.env.RELEASER_INSTALLATION_ID,
};
const octokit = new Octokit({
authStrategy: createAppAuth,
auth: authSecrets,
});
//#endregion
//#region Find current and new versions
const lastTag = await getLastTag({ prefix: VERSION_PREFIX });
// Passing an empty string allow empty commits (i.e. that does not modify any files) to be included.
const commits = await getCommits("", lastTag);
const parsedCommits = parseCommits(commits, CONVENTION.parserOpts);
const bumpInfo = CONVENTION.recommendedBumpOpts.whatBump(parsedCommits);
const currentVersion = getCurrentVersion(PATH);
const newVersion = getNextVersion(currentVersion, bumpInfo);
const newVersionTag = `${VERSION_PREFIX}${newVersion}`;
//#endregion
// Bump the NPM version.
await npmBumpVersion(newVersion, PATH);
//#region Generate changelog if needed
let changelog = "";
if (parsedCommits.length > 0) {
changelog = await generateChangelog(
parsedCommits,
newVersion,
{
host: "https://github.com",
owner: REPO_OWNER,
repository: REPO_NAME,
linkReferences: true,
currentTag: newVersionTag,
previousTag: lastTag,
},
CONVENTION.writerOpts,
);
await writeChangelog(PATH, changelog);
}
//#endregion
//#region Commit changelog, tag version and push
const tempBranchName = `release/${newVersion}`;
const mainBranchName = await getCurrentBranchName();
const mainBranchCurrentSHA = await getSHA1fromRef(mainBranchName);
// Create a temporary branch and check it out.
await gitCreateBranch(tempBranchName);
await gitCheckoutBranch(tempBranchName);
// Stage all the changes (mainly the changelog)...
await gitAdd(".");
//... and create a Git tree object with the changes).
const treeSHA = await gitWriteTree();
// Create a new commit that references the Git tree object.
const commitTree = await gitCommitTree(treeSHA, tempBranchName, "tempcommit");
// Update the HEAD of the temp branch to point to the new commit, then publish the temp branch.
await gitUpdateRef("HEAD", commitTree);
await gitPublishBranch("origin", tempBranchName);
/**
* Once we pushed the temp branch, the tree object is then known to the remote repository.
* We can now create a new commit that references the tree object using the GitHub API.
* The fact that we use the API makes the commit 'verified'.
* The commit is directly created on the GitHub repository, not on the local repository.
*/
const commit = await octokit.rest.git.createCommit({
message: `chore(release): ${newVersion} [skip ci]`,
owner: REPO_OWNER,
repo: REPO_NAME,
tree: treeSHA,
parents: [mainBranchCurrentSHA],
});
// Forcefully reset `main` to the commit we just created with the GitHub API.
await gitSetRefOnCommit(
GIT_SSH_REMOTE,
`refs/heads/${mainBranchName}`,
commit.data.sha,
);
// Push the branch using the SSH remote to bypass any GitHub checks.
await gitCheckoutBranch(mainBranchName);
await gitPush({ remote: GIT_SSH_REMOTE, refs: [mainBranchName] });
// Finally, delete the temp branch.
await gitDeleteRemoteBranch(GIT_SSH_REMOTE, tempBranchName);
//#endregion
//#region Create & push tag
await gitTag(newVersionTag);
await gitPushTags();
//#endregion
// Publish the new version on NPM
await npmPublish(PATH, { provenance: true });
//#region Create GitHub Release on last tag
const [, ...bodyArray] = changelog.split("\n");
await octokit.rest.repos.createRelease({
owner: REPO_OWNER,
repo: REPO_NAME,
tag_name: newVersionTag,
name: `Release ${newVersionTag}`,
body: bodyArray.join("\n"),
});
//#endregion
})();