diff --git a/changelog.d/13393.misc b/changelog.d/13393.misc
new file mode 100644
index 0000000000..be2b0153ea
--- /dev/null
+++ b/changelog.d/13393.misc
@@ -0,0 +1 @@
+Add a `merge-back` command to the release script, which automates merging the correct branches after a release.
\ No newline at end of file
diff --git a/scripts-dev/release.py b/scripts-dev/release.py
index 5bfd750118..46220c4dd3 100755
--- a/scripts-dev/release.py
+++ b/scripts-dev/release.py
@@ -32,6 +32,7 @@ import click
import commonmark
import git
from click.exceptions import ClickException
+from git import GitCommandError, Repo
from github import Github
from packaging import version
@@ -78,6 +79,8 @@ def cli() -> None:
# Optional: generate some nice links for the announcement
+ ./scripts-dev/release.py merge-back
+
./scripts-dev/release.py announce
If the env var GH_TOKEN (or GITHUB_TOKEN) is set, or passed into the
@@ -441,6 +444,79 @@ def upload() -> None:
)
+def _merge_into(repo: Repo, source: str, target: str) -> None:
+ """
+ Merges branch `source` into branch `target`.
+ Pulls both before merging and pushes the result.
+ """
+
+ # Update our branches and switch to the target branch
+ for branch in [source, target]:
+ click.echo(f"Switching to {branch} and pulling...")
+ repo.heads[branch].checkout()
+ # Pull so we're up to date
+ repo.remote().pull()
+
+ assert repo.active_branch.name == target
+
+ try:
+ # TODO This seemed easier than using GitPython directly
+ click.echo(f"Merging {source}...")
+ repo.git.merge(source)
+ except GitCommandError as exc:
+ # If a merge conflict occurs, give some context and try to
+ # make it easy to abort if necessary.
+ click.echo(exc)
+ if not click.confirm(
+ f"Likely merge conflict whilst merging ({source} → {target}). "
+ f"Have you resolved it?"
+ ):
+ repo.git.merge("--abort")
+ return
+
+ # Push result.
+ click.echo("Pushing...")
+ repo.remote().push()
+
+
+@cli.command()
+def merge_back() -> None:
+ """Merge the release branch back into the appropriate branches.
+ All branches will be automatically pulled from the remote and the results
+ will be pushed to the remote."""
+
+ synapse_repo = get_repo_and_check_clean_checkout()
+ branch_name = synapse_repo.active_branch.name
+
+ if not branch_name.startswith("release-v"):
+ raise RuntimeError("Not on a release branch. This does not seem sensible.")
+
+ # Pull so we're up to date
+ synapse_repo.remote().pull()
+
+ current_version = get_package_version()
+
+ if current_version.is_prerelease:
+ # Release candidate
+ if click.confirm(f"Merge {branch_name} → develop?", default=True):
+ _merge_into(synapse_repo, branch_name, "develop")
+ else:
+ # Full release
+ sytest_repo = get_repo_and_check_clean_checkout("../sytest", "sytest")
+
+ if click.confirm(f"Merge {branch_name} → master?", default=True):
+ _merge_into(synapse_repo, branch_name, "master")
+
+ if click.confirm("Merge master → develop?", default=True):
+ _merge_into(synapse_repo, "master", "develop")
+
+ if click.confirm(f"On SyTest, merge {branch_name} → master?", default=True):
+ _merge_into(sytest_repo, branch_name, "master")
+
+ if click.confirm("On SyTest, merge master → develop?", default=True):
+ _merge_into(sytest_repo, "master", "develop")
+
+
@cli.command()
def announce() -> None:
"""Generate markdown to announce the release."""
|