@@ -1607,13 +1607,6 @@ class Runner {
16071607 });
16081608 }
16091609 catch (error) {
1610- this.logger.error(`Something went wrong backporting to ${pr.base}: ${error}`);
1611- if (!configs.dryRun && configs.errorNotification.enabled && configs.errorNotification.message.length > 0) {
1612- // notify the failure as comment in the original pull request
1613- let comment = (0, runner_util_1.injectError)(configs.errorNotification.message, error);
1614- comment = (0, runner_util_1.injectTargetBranch)(comment, pr.base);
1615- await gitApi.createPullRequestComment(configs.originalPullRequest.url, comment);
1616- }
16171610 failures.push(error);
16181611 }
16191612 }
@@ -1641,41 +1634,143 @@ class Runner {
16411634 return token;
16421635 }
16431636 async executeBackport(configs, backportPR, git) {
1644- this.logger.setContext(backportPR.base);
1645- const originalPR = configs.originalPullRequest;
1646- // 4. clone the repository
1647- this.logger.debug("Cloning repo..");
1648- await git.gitCli.clone(configs.originalPullRequest.targetRepo.cloneUrl, configs.folder, backportPR.base);
1649- // 5. create new branch from target one and checkout
1650- this.logger.debug("Creating local branch..");
1651- await git.gitCli.createLocalBranch(configs.folder, backportPR.head);
1652- // 6. fetch pull request remote if source owner != target owner or pull request still open
1653- if (configs.originalPullRequest.sourceRepo.owner !== configs.originalPullRequest.targetRepo.owner ||
1654- configs.originalPullRequest.state === "open") {
1655- this.logger.debug("Fetching pull request remote..");
1656- const prefix = git.gitClientType === git_types_1.GitClientType.GITLAB ? "merge-requests" : "pull"; // default is for gitlab
1657- await git.gitCli.fetch(configs.folder, `${prefix}/${configs.originalPullRequest.number}/head:pr/${configs.originalPullRequest.number}`);
1637+ let i = 0;
1638+ for (const step of backportSteps(this.logger, configs, backportPR, git.gitCli, git.gitClientType, () => git.gitClientApi.createPullRequest(backportPR))) {
1639+ try {
1640+ await step();
1641+ }
1642+ catch (error) {
1643+ this.logger.error(`Something went wrong backporting to ${backportPR.base}: ${error}`);
1644+ if (!configs.dryRun && configs.errorNotification.enabled && configs.errorNotification.message.length > 0) {
1645+ // notify the failure as comment in the original pull request
1646+ let comment = (0, runner_util_1.injectError)(configs.errorNotification.message, error);
1647+ comment = (0, runner_util_1.injectTargetBranch)(comment, backportPR.base);
1648+ try {
1649+ let script = "Reconstruction of the attempted steps (beware that escaping may be missing):\n```sh\n";
1650+ script += await backportScript(configs, backportPR, git, i);
1651+ script += "```";
1652+ comment += "\n\n" + script;
1653+ }
1654+ catch (scriptError) {
1655+ this.logger.error(`Something went wrong reconstruction the script: ${scriptError}`);
1656+ }
1657+ await git.gitClientApi.createPullRequestComment(configs.originalPullRequest.url, comment);
1658+ }
1659+ throw error;
1660+ }
1661+ i++;
16581662 }
1659- // 7. apply all changes to the new branch
1660- this.logger.debug("Cherry picking commits..");
1661- for (const sha of originalPR.commits) {
1662- await git.gitCli.cherryPick(configs.folder, sha, configs.mergeStrategy, configs.mergeStrategyOption, configs.cherryPickOptions);
1663+ return;
1664+ }
1665+ }
1666+ exports["default"] = Runner;
1667+ async function backportScript(configs, backportPR, git, failed) {
1668+ let s = "";
1669+ const discardLogger = {
1670+ setContext: function (_newContext) { },
1671+ getContext: function () { return undefined; },
1672+ clearContext: function () { },
1673+ trace: function (_message) { },
1674+ debug: function (_message) { },
1675+ info: function (_message) { },
1676+ warn: function (_message) { },
1677+ error: function (_message) { }
1678+ };
1679+ const fakeGitCli = {
1680+ clone: async function (_from, _to, _branch) {
1681+ /* consider that the user already has the repo cloned (or knows how to clone) */
1682+ },
1683+ createLocalBranch: async function (_cwd, newBranch) {
1684+ s += `git fetch origin ${backportPR.base}\n`;
1685+ s += `git switch -c ${newBranch} origin/${backportPR.base}`;
1686+ },
1687+ fetch: async function (_cwd, branch, remote = "origin") {
1688+ s += `git fetch ${remote} ${branch}`;
1689+ },
1690+ cherryPick: async function (_cwd, sha, strategy = "recursive", strategyOption = "theirs", cherryPickOptions) {
1691+ s += `git cherry-pick -m 1 --strategy=${strategy} --strategy-option=${strategyOption} `;
1692+ if (cherryPickOptions !== undefined) {
1693+ s += cherryPickOptions + " ";
1694+ }
1695+ s += sha;
1696+ },
1697+ push: async function (_cwd, branch, remote = "origin", force = false) {
1698+ s += `git push ${remote} ${branch}`;
1699+ if (force) {
1700+ s += " --force";
1701+ }
16631702 }
1664- if (!configs.dryRun) {
1665- // 8. push the new branch to origin
1666- await git.gitCli.push(configs.folder, backportPR.head);
1667- // 9. create pull request new branch -> target branch (using octokit)
1668- const prUrl = await git.gitClientApi.createPullRequest(backportPR);
1669- this.logger.info(`Pull request created: ${prUrl}`);
1703+ };
1704+ let i = 0;
1705+ let gathered = "";
1706+ for (const step of backportSteps(discardLogger, configs, backportPR, fakeGitCli, git.gitClientType, async () => {
1707+ s += `# ${git.gitClientType}.createPullRequest`;
1708+ return "";
1709+ })) {
1710+ if (i == failed) {
1711+ s += "# the step below failed\n";
16701712 }
1671- else {
1672- this.logger.warn("Pull request creation and remote push skipped");
1673- this.logger.info(`${JSON.stringify(backportPR, null, 2)}`);
1713+ await step();
1714+ if (s.length > 0) {
1715+ gathered += s + "\n";
1716+ s = "";
16741717 }
1675- this.logger.clearContext() ;
1718+ i++ ;
16761719 }
1720+ return gathered;
1721+ }
1722+ function* backportSteps(logger, configs, backportPR, gitCli, gitClientType, createPullRequest) {
1723+ // every failible operation should be in a dedicated closure
1724+ // 4. clone the repository
1725+ yield async () => {
1726+ logger.setContext(backportPR.base);
1727+ logger.debug("Cloning repo..");
1728+ await gitCli.clone(configs.originalPullRequest.targetRepo.cloneUrl, configs.folder, backportPR.base);
1729+ };
1730+ // 5. create new branch from target one and checkout
1731+ yield async () => {
1732+ logger.debug("Creating local branch..");
1733+ await gitCli.createLocalBranch(configs.folder, backportPR.head);
1734+ };
1735+ // 6. fetch pull request remote if source owner != target owner or pull request still open
1736+ if (configs.originalPullRequest.sourceRepo.owner !== configs.originalPullRequest.targetRepo.owner ||
1737+ configs.originalPullRequest.state === "open") {
1738+ yield async () => {
1739+ logger.debug("Fetching pull request remote..");
1740+ const prefix = gitClientType === git_types_1.GitClientType.GITLAB ? "merge-requests" : "pull"; // default is for gitlab
1741+ await gitCli.fetch(configs.folder, `${prefix}/${configs.originalPullRequest.number}/head:pr/${configs.originalPullRequest.number}`);
1742+ };
1743+ }
1744+ // 7. apply all changes to the new branch
1745+ yield async () => {
1746+ logger.debug("Cherry picking commits..");
1747+ };
1748+ for (const sha of configs.originalPullRequest.commits) {
1749+ yield async () => {
1750+ await gitCli.cherryPick(configs.folder, sha, configs.mergeStrategy, configs.mergeStrategyOption, configs.cherryPickOptions);
1751+ };
1752+ }
1753+ if (!configs.dryRun) {
1754+ // 8. push the new branch to origin
1755+ yield async () => {
1756+ await gitCli.push(configs.folder, backportPR.head);
1757+ };
1758+ // 9. create pull request new branch -> target branch (using octokit)
1759+ yield async () => {
1760+ const prUrl = await createPullRequest();
1761+ logger.info(`Pull request created: ${prUrl}`);
1762+ };
1763+ }
1764+ else {
1765+ yield async () => {
1766+ logger.warn("Pull request creation and remote push skipped");
1767+ logger.info(`${JSON.stringify(backportPR, null, 2)}`);
1768+ };
1769+ }
1770+ yield async () => {
1771+ logger.clearContext();
1772+ };
16771773}
1678- exports["default"] = Runner;
16791774
16801775
16811776/***/ }),
0 commit comments