Skip to content

Commit 25c6fa8

Browse files
committed
chore: add custom release script
1 parent c74068a commit 25c6fa8

3 files changed

Lines changed: 198 additions & 0 deletions

File tree

bin/release.mjs

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import { execSync } from "child_process";
2+
import { Octokit } from "@octokit/rest";
3+
import dotenv from "dotenv";
4+
import { readFileSync } from "fs";
5+
import readlineSync from "readline-sync";
6+
7+
dotenv.config();
8+
9+
const args = process.argv.slice(2);
10+
const isFrontend = args.includes("--fe");
11+
const noDeploy = args.includes("--no-deploy");
12+
const isBackend = args.includes("--be");
13+
const isDryRun = args.includes("--dry");
14+
15+
const runCommand = (command, force) => {
16+
if (isDryRun && !force) {
17+
console.log(`[Dry Run] Command: ${command}`);
18+
return "[Dry Run] Command executed.";
19+
} else {
20+
try {
21+
const output = execSync(command, { stdio: "pipe" }).toString();
22+
return output;
23+
} catch (error) {
24+
console.error(`Error executing command ${command}`);
25+
console.error(error);
26+
process.exit(1);
27+
}
28+
}
29+
};
30+
31+
const getCurrentVersion = () => {
32+
console.log("Getting current version...");
33+
const packageJson = JSON.parse(readFileSync("./package.json", "utf-8"));
34+
return packageJson.version;
35+
};
36+
37+
const incrementVersion = (currentVersion) => {
38+
console.log("Incrementing version...");
39+
const now = new Date();
40+
const year = now.getFullYear().toString().slice(-2);
41+
const start = new Date(now.getFullYear(), 0, 1);
42+
const week = Math.ceil(((now - start) / 86400000 + start.getDay() + 1) / 7);
43+
const [prevYear, prevWeek, minor] = currentVersion.split(".").map(Number);
44+
45+
let newMinor = minor + 1;
46+
if (year != prevYear || week != prevWeek) {
47+
newMinor = 0;
48+
}
49+
50+
const v = `v${year}.${week}.${newMinor}`;
51+
52+
return v;
53+
};
54+
55+
const updatePackage = (newVersion) => {
56+
console.log("Updating package.json...");
57+
if (isDryRun) {
58+
console.log(`[Dry Run] Updated package.json to version ${newVersion}`);
59+
return;
60+
}
61+
const packagePath = path.resolve(__dirname, "package.json");
62+
63+
// Read the package.json file
64+
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
65+
66+
// Update the version field
67+
packageJson.version = newVersion.replace("v", "");
68+
69+
// Write the updated JSON back to package.json
70+
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2), "utf8");
71+
72+
console.log(`Updated package.json to version ${newVersion}`);
73+
};
74+
75+
const checkUncommittedChanges = () => {
76+
console.log("Checking uncommitted changes...");
77+
const status = execSync("git status --porcelain").toString().trim();
78+
if (isDryRun) {
79+
console.log("[Dry Run] Checking uncommitted changes...");
80+
} else if (status) {
81+
console.error(
82+
"You have uncommitted changes. Please commit or stash them before proceeding."
83+
);
84+
process.exit(1);
85+
}
86+
};
87+
88+
const buildProject = () => {
89+
console.log("Building project...");
90+
let filter = "";
91+
92+
if (isFrontend && !isBackend) {
93+
filter = "--filter @monkeytype/frontend";
94+
} else if (isBackend && !isFrontend) {
95+
filter = "--filter @monkeytype/backend";
96+
}
97+
98+
runCommand("npx turbo lint test validate-json build " + filter);
99+
};
100+
101+
const deployBackend = () => {
102+
console.log("Deploying backend...");
103+
runCommand("sh ./bin/deployBackend.sh");
104+
};
105+
106+
const deployFrontend = () => {
107+
console.log("Deploying frontend...");
108+
runCommand("cd frontend && npx firebase deploy -P live --only hosting");
109+
};
110+
111+
const purgeCache = () => {
112+
console.log("Purging Cloudflare cache...");
113+
runCommand("sh ./bin/purgeCfCache.sh");
114+
};
115+
116+
const generateChangelog = async () => {
117+
console.log("Generating changelog...");
118+
119+
const changelog = runCommand("node bin/buildChangelog.mjs", true);
120+
121+
return changelog;
122+
};
123+
124+
const createCommitAndTag = (version) => {
125+
console.log("Creating commit and tag... Pushing to Github...");
126+
runCommand(`git add .`);
127+
runCommand(`git commit -m "chore: release ${version}"`);
128+
runCommand(`git tag ${version}`);
129+
runCommand(`git push origin master --tags`);
130+
};
131+
132+
const createGithubRelease = async (version, changelogContent) => {
133+
console.log("Creating GitHub release...");
134+
if (isDryRun) {
135+
console.log(
136+
`[Dry Run] Sent release request to GitHub for version ${version}`
137+
);
138+
} else {
139+
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
140+
const { owner, repo } = {
141+
owner: "monkeytypegame",
142+
repo: "monkeytype",
143+
};
144+
await octokit.repos.createRelease({
145+
owner,
146+
repo,
147+
tag_name: version,
148+
name: `${version}`,
149+
body: changelogContent,
150+
});
151+
}
152+
};
153+
154+
const main = async () => {
155+
console.log("Starting release process...");
156+
checkUncommittedChanges();
157+
158+
const changelogContent = await generateChangelog();
159+
160+
console.log(changelogContent);
161+
162+
if (!readlineSync.keyInYN("Changelog looks good?")) {
163+
console.log("Exiting.");
164+
process.exit(1);
165+
}
166+
167+
const currentVersion = getCurrentVersion();
168+
const newVersion = incrementVersion(currentVersion);
169+
170+
buildProject();
171+
172+
if (!readlineSync.keyInYN(`Ready to release ${newVersion}?`)) {
173+
console.log("Exiting.");
174+
process.exit(1);
175+
}
176+
177+
if (!noDeploy && (isBackend || (!isFrontend && !isBackend))) {
178+
deployBackend();
179+
}
180+
181+
if (!noDeploy && (isFrontend || (!isFrontend && !isBackend))) {
182+
deployFrontend();
183+
}
184+
185+
if (!noDeploy) purgeCache();
186+
updatePackage(newVersion);
187+
createCommitAndTag(newVersion);
188+
await createGithubRelease(newVersion, changelogContent);
189+
190+
console.log(`Release ${newVersion} completed successfully.`);
191+
process.exit(0);
192+
};
193+
194+
main();

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"lint-staged": "13.2.3",
7070
"only-allow": "1.2.1",
7171
"prettier": "2.5.1",
72+
"readline-sync": "1.4.10",
7273
"release-it": "16.1.4",
7374
"turbo": "2.0.9",
7475
"typescript": "5.3.3",

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)