Add 2.0 release logic 
diff --git a/.azure-pipelines/2.0-prerelease.yml b/.azure-pipelines/2.0-prerelease.yml
deleted file mode 100644
index 2cdcf8f3035..00000000000
--- a/.azure-pipelines/2.0-prerelease.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-# Pipeline for testing, building, and deploying Certbot 2.0 pre-releases.
-trigger: none
-pr: none
-
-variables:
-  # We don't publish our Docker images in this pipeline, but when building them
-  # for testing, let's use the nightly tag.
-  dockerTag: nightly
-  snapBuildTimeout: 5400
-
-stages:
-  - template: templates/stages/test-and-package-stage.yml
-  - stage: DeploySnaps
-    jobs:
-      - template: templates/jobs/snap-deploy-job.yml
-        parameters:
-          snapReleaseChannel: beta
-  - template: templates/stages/notify-failure-stage.yml
diff --git a/.azure-pipelines/release.yml b/.azure-pipelines/release.yml
index 9169dc950f9..1c983a3b647 100644
--- a/.azure-pipelines/release.yml
+++ b/.azure-pipelines/release.yml
@@ -15,5 +15,11 @@ stages:
   - template: templates/stages/changelog-stage.yml
   - template: templates/stages/deploy-stage.yml
     parameters:
-      snapReleaseChannel: candidate
+      ${{ if startsWith(variables['Build.SourceBranchName'], 'v2') }}:
+        snapReleaseChannel: beta
+      ${{ elseif startsWith(variables['Build.SourceBranchName'], 'v1') }}:
+        snapReleaseChannel: candidate
+      ${{ else }}:
+        # This should never happen
+        snapReleaseChannel: somethingInvalid
   - template: templates/stages/notify-failure-stage.yml
diff --git a/tools/docker/deploy.sh b/tools/docker/deploy.sh
index 9b04f3e49fc..f9446a99142 100755
--- a/tools/docker/deploy.sh
+++ b/tools/docker/deploy.sh
@@ -23,9 +23,9 @@ ParseRequestedArch "${2}"
 
 # Creates and pushes all Docker images aliases for the requested architectures
 # set in the environment variable ALL_REQUESTED_ARCH.  If the value of the
-# global variable TAG_BASE is a version tag such as v0.35.0, the "latest" tag
-# is also updated. Tags without the architecture part are also created for the
-# default architecture.
+# global variable TAG_BASE is a 2.0.0 or greater version tag such as v2.1.0,
+# the "latest" tag is also updated. Tags without the architecture part are also
+# created for the default architecture.
 # As an example, for amd64 (the default architecture) and the tag v0.35.0, the
 # following tags would be created:
 #  - certbot/certbot:v0.35.0
@@ -52,7 +52,8 @@ TagAndPushForAllRequestedArch() {
         # another timeout & can get the deubg logs, we're leaving them in.
         docker --debug push "${DOCKER_REPO}:${TARGET_ARCH}-${TAG_BASE}"
 
-        if [[ "${TAG_BASE}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+        # If TAG_BASE is a valid tag for version 2.0.0 or greater
+        if [[ "${TAG_BASE}" =~ ^v([2-9]|[1-9][0-9]+)\.[0-9]+\.[0-9]+$ ]]; then
             docker tag "${DOCKER_REPO}:${TARGET_ARCH}-${TAG_BASE}" "${DOCKER_REPO}:${TARGET_ARCH}-latest"
             docker --debug push "${DOCKER_REPO}:${TARGET_ARCH}-latest"
             if [ "${TARGET_ARCH}" == "${DEFAULT_ARCH}" ]; then
diff --git a/tools/finish_release.py b/tools/finish_release.py
index 18aa8ee30ee..f44bb77e531 100755
--- a/tools/finish_release.py
+++ b/tools/finish_release.py
@@ -65,15 +65,6 @@ def parse_args(args):
     parser = argparse.ArgumentParser(description=__doc__,
                                      formatter_class=argparse.RawDescriptionHelpFormatter)
     parser.add_argument('--css', type=str, required=True, help='hostname of code signing server')
-    group = parser.add_mutually_exclusive_group()
-    # We use 'store_false' and a destination related to the other type of
-    # artifact to cause the flag being set to disable publishing of the other
-    # artifact. This makes using the parsed arguments later on a little simpler
-    # and cleaner.
-    group.add_argument('--snaps-only', action='store_false', dest='publish_windows',
-                        help='Skip publishing other artifacts and only publish the snaps')
-    group.add_argument('--windows-only', action='store_false', dest='publish_snaps',
-                        help='Skip publishing other artifacts and only publish the Windows installer')
     return parser.parse_args(args)
 
     
@@ -195,9 +186,15 @@ def main(args):
     # again fails. Publishing the snaps can be done multiple times though
     # so we do that first to make it easier to run the script again later
     # if something goes wrong.        
-    if parsed_args.publish_snaps:
+    #
+    # For now though, we're only going to publish snaps to the stable channel
+    # for 1.x.y releases and only going to update our Windows installer for
+    # 2.x.y releases. Once we feel confident enough about Certbot 2.0, we
+    # should stop doing 1.x.y releases and unconditionally publish both snaps
+    # and the Windows installer.
+    if version.startswith('1.'):
         promote_snaps(version)
-    if parsed_args.publish_windows:
+    else:
         publish_windows(css)
 
 if __name__ == "__main__":

This cherry picks #9467 to this branch per the plan there in case we want to do 1.32 point releases.