diff --git a/scripts/open-cherry-pick-pr.ts b/scripts/open-cherry-pick-pr.ts
new file mode 100644
index 00000000000..0d8109bafea
--- /dev/null
+++ b/scripts/open-cherry-pick-pr.ts
@@ -0,0 +1,94 @@
+///
+// Must reference esnext.asynciterable lib, since octokit uses AsyncIterable internally
+///
+
+import Octokit = require("@octokit/rest");
+import {runSequence} from "./run-sequence";
+import fs = require("fs");
+import path = require("path");
+
+const userName = process.env.GH_USERNAME;
+const reviewers = process.env.REQUESTING_USER ? [process.env.REQUESTING_USER] : ["weswigham", "RyanCavanaugh"];
+const branchName = `pick/${process.env.SOURCE_ISSUE}/${process.env.TARGET_BRANCH}`;
+const remoteUrl = `https://${process.argv[2]}@github.com/${userName}/TypeScript.git`;
+
+async function main() {
+ const currentSha = runSequence([
+ ["git", ["rev-parse", "HEAD"]]
+ ]);
+ const currentAuthor = runSequence([
+ ["git", ["log", "-1", `--pretty="%aN <%aE>"`]]
+ ])
+ let logText = runSequence([
+ ["git", ["log", `master..${currentSha}`, `--pretty="%h %s%n%b"`]]
+ ]);
+ logText = `Cherry-pick PR #${process.env.SOURCE_ISSUE} into ${process.env.TARGET_BRANCH}
+
+Component commits:
+${logText}`
+ const logpath = path.join(__dirname, "../", "logmessage.txt");
+ runSequence([
+ ["git", ["checkout", "-b", "temp-branch"]],
+ ["git", ["reset", "master", "--soft"]]
+ ]);
+ fs.writeFileSync(logpath, logText);
+ runSequence([
+ ["git", ["commit", "-F", logpath, `--author="${currentAuthor}"`]]
+ ]);
+ fs.unlinkSync(logpath);
+ const squashSha = runSequence([
+ ["git", ["rev-parse", "HEAD"]]
+ ]);
+ runSequence([
+ ["git", ["checkout", process.env.TARGET_BRANCH]], // checkout the target branch
+ ["git", ["checkout", "-b", branchName]], // create a new branch
+ ["git", ["cherry-pick", squashSha]], //
+ ["git", ["remote", "add", "fork", remoteUrl]], // Add the remote fork
+ ["git", ["push", "--set-upstream", "fork", branchName, "-f"]] // push the branch
+ ]);
+
+ const gh = new Octokit();
+ gh.authenticate({
+ type: "token",
+ token: process.argv[2]
+ });
+ const r = await gh.pulls.create({
+ owner: "Microsoft",
+ repo: "TypeScript",
+ maintainer_can_modify: true,
+ title: `🤖 Cherry-pick PR #${process.env.SOURCE_ISSUE} into ${process.env.TARGET_BRANCH}`,
+ head: `${userName}:${branchName}`,
+ base: process.env.TARGET_BRANCH,
+ body:
+ `This cherry-pick was triggerd by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.SOURCE_ISSUE}
+ Please review the diff and merge if no changes are unexpected.
+ You can view the cherry-pick log [here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary).
+
+ cc ${reviewers.map(r => "@" + r).join(" ")}`,
+ });
+ const num = r.data.number;
+ console.log(`Pull request ${num} created.`);
+
+ await gh.issues.createComment({
+ number: +process.env.SOURCE_ISSUE,
+ owner: "Microsoft",
+ repo: "TypeScript",
+ body: `Hey @${process.env.REQUESTING_USER}, I've opened #${num} for you.`
+ });
+}
+
+main().catch(async e => {
+ console.error(e);
+ process.exitCode = 1;
+ const gh = new Octokit();
+ gh.authenticate({
+ type: "token",
+ token: process.argv[2]
+ });
+ await gh.issues.createComment({
+ number: +process.env.SOURCE_ISSUE,
+ owner: "Microsoft",
+ repo: "TypeScript",
+ body: `Hey @${process.env.REQUESTING_USER}, I couldn't open a PR with the cherry-pick. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary)). You may need to squash and pick this PR into ${process.env.TARGET_BRANCH} manually.`
+ });
+});
\ No newline at end of file