Support rolling releases in Bazel release scripts.

PiperOrigin-RevId: 376692239
diff --git a/scripts/ci/build.sh b/scripts/ci/build.sh
index 6d9fec9..70cce52 100755
--- a/scripts/ci/build.sh
+++ b/scripts/ci/build.sh
@@ -89,6 +89,11 @@
   RELEASE_CANDIDATE_URL="https://releases.bazel.build/%release_name%/rc%rc%/index.html"
   RELEASE_URL="https://github.com/bazelbuild/bazel/releases/tag/%release_name%"
 
+  if [ "$(is_rolling_release)" -eq 1 ]; then
+    echo "No emails for rolling releases"
+    return 0
+  fi
+
   local release_name=$(get_release_name)
   local rc=$(get_release_candidate)
   local args=(
@@ -146,7 +151,13 @@
     local github_token="$(gsutil cat gs://bazel-trusted-encrypted-secrets/github-trusted-token.enc | \
         gcloud kms decrypt --project bazel-public --location global --keyring buildkite --key github-trusted-token --ciphertext-file - --plaintext-file -)"
 
-    GITHUB_TOKEN="${github_token}" github-release "bazelbuild/bazel" "${release_name}" "" "$(get_release_page)" "${artifact_dir}/*"
+    local cmd = "GITHUB_TOKEN=\"${github_token}\" github-release \"bazelbuild/bazel\" \"${release_name}\" \"\" \"$(get_release_page)\" \"${artifact_dir}/*\""
+
+    if [ "$(is_rolling_release)" -eq 1 ]; then
+        eval "${cmd} -prerelease"
+    else
+        eval "${cmd}"
+    fi
   fi
 }
 
@@ -182,7 +193,10 @@
 
   if [ -n "${release_name}" ]; then
     local release_path="${release_name}/release"
-    if [ -n "${rc}" ]; then
+    if [ "$(is_rolling_release)" -eq 1 ]; then
+      # Store rolling releases and their RCs in the same directory (for simplicity)
+      release_path="$(get_lts_name)/rolling/$(get_full_release_name)"
+    elif [ -n "${rc}" ]; then
       release_path="${release_name}/rc${rc}"
     fi
     create_index_html "${artifact_dir}" > "${artifact_dir}/index.html"
@@ -400,13 +414,16 @@
     gpg --no-tty --detach-sign -u "${APT_GPG_KEY_ID}" "${file}"
   done
 
-  apt_working_dir="$(mktemp -d --tmpdir)"
-  echo "apt_working_dir = ${apt_working_dir}"
-  mkdir "${apt_working_dir}/${release_name}"
-  cp "${artifact_dir}/bazel_${release_label}-linux-x86_64.deb" "${apt_working_dir}/${release_name}"
-  cp "${artifact_dir}/bazel_${release_label}.dsc" "${apt_working_dir}/${release_name}"
-  cp "${artifact_dir}/bazel_${release_label}.tar.gz" "${apt_working_dir}/${release_name}"
-  release_to_apt "${apt_working_dir}"
+  if [ "$(is_rolling_release)" -eq 0 ]; then
+    apt_working_dir="$(mktemp -d --tmpdir)"
+    echo "apt_working_dir = ${apt_working_dir}"
+    mkdir "${apt_working_dir}/${release_name}"
+    cp "${artifact_dir}/bazel_${release_label}-linux-x86_64.deb" "${apt_working_dir}/${release_name}"
+    cp "${artifact_dir}/bazel_${release_label}.dsc" "${apt_working_dir}/${release_name}"
+    cp "${artifact_dir}/bazel_${release_label}.tar.gz" "${apt_working_dir}/${release_name}"
+    release_to_apt "${apt_working_dir}"
+  fi
+
 
   gcs_working_dir="$(mktemp -d --tmpdir)"
   echo "gcs_working_dir = ${gcs_working_dir}"
@@ -419,3 +436,4 @@
   rm -f "${github_working_dir}/bazel_${release_label}"*.{dsc,tar.gz}{,.sha256,.sig}
   release_to_github "${github_working_dir}"
 }
+
diff --git a/scripts/release/common.sh b/scripts/release/common.sh
index 240171f..5035e35 100755
--- a/scripts/release/common.sh
+++ b/scripts/release/common.sh
@@ -62,9 +62,24 @@
 
 # Extract the release name from the git branch name
 function get_release_name() {
-  # Match branch name release-X.X.X-rcY and return X.X.X
-  # or match tag name X.X.X and return X.X.X
-  git_get_branch 2>/dev/null | grep -Po "(?<=release-)([0-9]|\.)*(?=rc)" || git_get_tag | grep -Po "^([0-9]|\.)*$" || true
+  # Match branch name release-X.X.X[-pre.XXXXXXXX.X]rcY and return X.X.X[-pre.XXXXXXXX.X]
+  # or match tag name X.X.X[-pre.XXXXXXXX.X] and return X.X.X[-pre.XXXXXXXX.X]
+   git_get_branch 2>/dev/null | grep -Po "(?<=release-)([0-9]|\.)*(-pre\.[0-9]{8}(\.[0-9]+){1,2})?(?=rc)" || git_get_tag | grep -Po "^([0-9]|\.)*(-pre\.[0-9]{8}(\.[0-9]+){1,2})?$" || true
+}
+
+# Returns whether this is a rolling release (or an RCs of one)
+function is_rolling_release() {
+  if [[ "$(get_release_name)" =~ [0-9]+\.[0-9]+\.[0-9]+-pre\.[0-9]{8}\.[0-9]+(\.[0-9]+)?$ ]]; then
+    echo 1
+  else
+    echo 0
+  fi
+}
+
+# Returns the name of the LTS release that belongs to the current rolling release
+function get_lts_name() {
+  local release_name="$(get_release_name)"
+  echo "${release_name}" | grep -oE "^([0-9]+\.[0-9]+\.[0-9]+)"
 }
 
 # Get the list of commit hashes between two revisions
diff --git a/scripts/release/relnotes.sh b/scripts/release/relnotes.sh
index b0182f2..8e2986a 100755
--- a/scripts/release/relnotes.sh
+++ b/scripts/release/relnotes.sh
@@ -303,16 +303,16 @@
 }
 
 # Returns the release notes for the CHANGELOG.md taken from either from
-# the notes for a release candidate or from the commit message for a
+# the notes for a release candidate/rolling release, or from the commit message for a
 # full release.
 function get_full_release_notes() {
   local release_name="$(get_full_release_name "$@")"
 
-  if [[ "${release_name}" =~ rc[0-9]+$ ]]; then
-    # Release candidate, we need to generate from the notes
+  if [[ "${release_name}" =~ rc[0-9]+$ ]] || [[ "$(is_rolling_release)" -eq 1 ]]; then
+    # Release candidate or rolling release -> generate from the notes
     generate_release_message "${release_name}" "$@"
   else
-    # Full release, returns the commit message
+    # Full LTS release -> return the commit message
     git_commit_msg "$@"
   fi
 }