docs: release: update release process to match current practice

The documented process has drifted from how releases are actually done:
* Releases are now cut weekly by an automated pipeline, so the manual
  steps are only a fallback, and for rollbacks.
* Releases are tested (both updating an existing checkout and a fresh
  init) before pushing anything.
* The tag is pushed & announced first, and only promoted to stable after
  a day.
* Direct pushes to the stable branch are rejected, so it has to be
  deleted & recreated via the Gerrit REST API instead.

Bug: 575551885
Change-Id: Ib36df07811c225558aba1a925b9703f3b2017e6f
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/649984
Reviewed-by: Gavin Mak <gavinmak@google.com>
Tested-by: Brian Gan <brgan@google.com>
Commit-Queue: Brian Gan <brgan@google.com>
diff --git a/docs/release-process.md b/docs/release-process.md
index 165bf84..ae69c98 100644
--- a/docs/release-process.md
+++ b/docs/release-process.md
@@ -5,11 +5,19 @@
 
 [TOC]
 
-## Schedule
+## Schedule {#schedule}
 
-There is no specific schedule for when releases are made.
-Usually it's more along the lines of "enough minor changes have been merged",
-or "there's a known issue the maintainers know should get fixed".
+Releases are automated.
+Every Tuesday morning [US PT], a pipeline checks if any new commits have landed
+since last release.
+If so, it tags & tests the latest `main`, pushes & announces the tag, and then
+promotes it to `stable` a day later.
+The release is skipped if there's a holiday or [production freeze](#freeze)
+that week.
+Maintainers can also trigger it by hand.
+The [manual steps](#manual) below are only needed as a fallback, or to roll
+back a release.
+
 If you find a fix has been merged for an issue important to you, but hasn't been
 released after a week or so, feel free to [contact] us to request a new release.
 
@@ -48,6 +56,11 @@
 At runtime, repo will check this to see if it needs to be updated (and notify
 the user automatically).
 
+When `VERSION` changes, the release pipeline publishes the new launcher to the
+`git-repo-downloads` Google Cloud Storage bucket.
+To publish it by hand, run `./release/sign-launcher.py`, which signs the
+launcher and prints the commands to upload it.
+
 ## Key management
 
 Every release has a git tag that is signed with a key that repo recognizes.
@@ -96,8 +109,8 @@
 
 If that tag cannot be verified, it gives up and forces the user to resolve.
 
-If env variable `REPO_SKIP_SELF_UPDATE` is defined, this will
-bypass the self update algorithm.
+If the env variable `REPO_SKIP_SELF_UPDATE` is set to anything other than `0`,
+`repo sync` will bypass the self update algorithm.
 
 ### Force an update
 
@@ -110,29 +123,20 @@
 
 Since the repo launcher defaults to tracking the `stable` branch, it is not
 normally updated until a new release is available.
-If something goes wrong with a new release, an older release can be force pushed
-and clients will automatically downgrade.
-
-The `maint` branch is used to track the previous major release of repo.
-It is not normally meant to be used by people as `stable` should be good enough.
-Once a new major release is pushed to the `stable` branch, then the previous
-major release can be pushed to `maint`.
-For example, when `stable` moves from `v1.10.x` to `v1.11.x`, then the `maint`
-branch will be updated from `v1.9.x` to `v1.10.x`.
+If something goes wrong with a new release, `stable` can be pointed back at an
+older release and clients will automatically downgrade.
 
 We don't have parallel release branches/series.
-Typically all tags are made against the `main` branch and then pushed to the
+Typically all tags are made against the `main` branch and then promoted to the
 `stable` branch to make it available to the rest of the world.
 Since repo doesn't typically see a lot of changes, this tends to be OK.
 
-## Creating a new release
+## Creating a new release {#manual}
 
-When you want to create a new release, you'll need to select a good version and
+Releases are normally created automatically (see [Schedule](#schedule)).
+If you need to create one by hand, you'll need to select a good version and
 create a signed tag using a key registered in repo itself.
 Typically we just tag the latest version of the `main` branch.
-The tag could be pushed now, but it won't be used by clients normally (since the
-default `repo-rev` setting is `stable`).
-This would allow some early testing on systems who explicitly select `main`.
 
 ### Creating a signed tag
 
@@ -147,10 +151,10 @@
 
 ```sh
 # Pick the new version.
-$ t=v2.30
+$ t=v2.XX
 
-# Create a new signed tag with the current HEAD.
-$ ./release/sign-tag.py $t
+# Create a new signed tag of the latest main branch.
+$ ./release/sign-tag.py $t origin/main
 
 # Verify the signed tag.
 $ git show $t
@@ -158,43 +162,49 @@
 
 ### Push the new release
 
-Once you're ready to make the release available to everyone, push it to the
-`stable` branch.
-
-Make sure you never push the tag itself to the stable branch!
-Only push the commit -- note the use of `^0` below.
+First push the tag, [announce](#announce) it, and wait a day to get feedback
+from people testing new releases early.
 
 ```sh
 $ git push https://gerrit-review.googlesource.com/git-repo $t
-$ git push https://gerrit-review.googlesource.com/git-repo $t^0:stable
 ```
 
-If something goes horribly wrong, you can force push the previous version to the
-`stable` branch and people should automatically recover.
-Again, make sure you never push the tag itself!
+Then make the release available to everyone by updating the `stable` branch.
+Direct pushes to it are rejected, so it has to be deleted & recreated via the
+authenticated [Gerrit REST API] (see [go/repo-release] for maintainers).
+
+Make sure you never point the stable branch at the tag itself!
+Only use the commit -- note the use of `^0` below.
+The commit is resolved before deleting anything so that a bad `$t` can't leave
+`stable` missing.
 
 ```sh
-$ oldrev="whatever-old-commit"
-$ git push https://gerrit-review.googlesource.com/git-repo $oldrev:stable --force
+$ api=https://gerrit-review.googlesource.com/a/projects/git-repo/branches/stable
+$ rev=$(git rev-parse --verify "$t^0") && \
+    curl --fail -X DELETE "$api" && \
+    curl --fail -X PUT -H 'Content-Type: application/json' \
+      -d "{\"revision\":\"$rev\"}" "$api"
 ```
 
-### Announce the release
+If something goes horribly wrong, run the same commands with the previous
+release (e.g. `t=$(git describe --abbrev=0 $t^0~)`) and people should
+automatically recover.
 
-Once you do push a new release to `stable`, make sure to announce it on the
-[repo-discuss@googlegroups.com] group.
+### Announce the release {#announce}
+
+Once you push a new release, make sure to announce it on the
+[repo-discuss@googlegroups.com] group, and follow up once it's on `stable`.
 Here is an [example announcement].
 
-You can create a short changelog using the command:
+You can create a short changelog since the previous release using the command:
 
 ```sh
-# If you haven't pushed to the stable branch yet, you can use origin/stable.
-# If you have pushed, change origin/stable to the previous release tag.
-# This assumes "main" is the current tagged release.  If it's newer, change it
-# to the current release tag too.
-$ git log --format="%h (%aN) %s" --no-merges origin/stable..main
+$ git log --format="%h (%aN) %s" --no-merges \
+    $(git describe --abbrev=0 $t^0~)..$t
 ```
 
 [contact]: ../README.md#contact
 [example announcement]: https://groups.google.com/d/topic/repo-discuss/UGBNismWo1M/discussion
 [repo-discuss@googlegroups.com]: https://groups.google.com/forum/#!forum/repo-discuss
 [go/repo-release]: https://goto.google.com/repo-release
+[Gerrit REST API]: https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#branch-endpoints