Add a release workflow. (#993)

* Add a release workflow.
* clean up release note generator
   - do not include google specific maintainer instructions
   - remove "snip" marks which were needed when you had to copy paste from terminal to github page.
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..a3d70e3
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,57 @@
+name: "Create release"
+
+on:
+  workflow_dispatch:
+    inputs:
+      version:
+        required: true
+        type: string
+        description: "Match the value in version.bzl"
+
+permissions:
+  id-token: write
+  attestations: write
+  contents: write
+
+jobs:
+  tests:
+    name: "Release Tests"
+    uses: "./.github/workflows/checks.yml"
+
+  create_tag:
+    name: "Create tag"
+    runs-on:
+      - "ubuntu-latest"
+    needs:
+      - "tests"
+
+    steps:
+      - uses: actions/checkout@v6
+
+      - name: "Create tag"
+        id: "tag"
+        env:
+          VERSION: "${{ inputs.version }}"
+
+          GIT_AUTHOR_NAME: "${{ github.actor }}"
+          GIT_AUTHOR_EMAIL: "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
+          GIT_COMMITTER_NAME: "${{ github.actor }}"
+          GIT_COMMITTER_EMAIL: "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
+        run: |
+          # 3. Push release tag.
+          git tag "${VERSION}" "HEAD"
+          git push origin "${VERSION}"
+
+  release:
+    name: "Create GitHub release"
+    needs:
+      - "create_tag"
+
+    uses: "bazel-contrib/.github/.github/workflows/release_ruleset.yaml@v7.2.3"
+    with:
+      # Create a distribution tarball with the release branded in to MODULE.bazel
+      # The workflow appends `--disk_cache` here. There seems to be now way to
+      # opt out, so use `|| false` to make it be |stuff we want || false --disk_cache|
+      bazel_test_command: bazel build //distro:distro || false
+      release_files: "bazel-bin/distro/rules_pkg-*.tar.gz"
+      tag_name: "${{ inputs.version }}"
diff --git a/.github/workflows/release_prep.sh b/.github/workflows/release_prep.sh
new file mode 100755
index 0000000..98e4493
--- /dev/null
+++ b/.github/workflows/release_prep.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+set -o errexit -o nounset -o pipefail
+
+# Passed as argument when invoking the script.
+TAG="${1}"
+
+# The prefix is chosen to match what GitHub generates for source archives
+# This guarantees that users can easily switch from a released artifact to a source archive
+# with minimal differences in their code (e.g. strip_prefix remains the same)
+PREFIX="rules_pkg--${TAG:1}"
+ARCHIVE="rules_pkg-$TAG.tar.gz"
+
+bazel build distro:relnotes
+cat bazel-bin/distro/relnotes.txt
diff --git a/pkg/releasing/print_rel_notes.py b/pkg/releasing/print_rel_notes.py
index 379d0c0..b9c4545 100644
--- a/pkg/releasing/print_rel_notes.py
+++ b/pkg/releasing/print_rel_notes.py
@@ -38,7 +38,6 @@
       deps_method=deps_method, toolchains_method=toolchains_method)
   relnotes_template = string.Template(textwrap.dedent(
       """
-      ------------------------ snip ----------------------------
       **New Features**
 
       **Incompatible Changes**
@@ -61,8 +60,6 @@
       **Using the rules**
 
       See [the source](https://github.com/${org}/${repo}/tree/${version}).
-      ------------------------ snip ----------------------------
-
       """).strip())
   print(relnotes_template.substitute({
       'changelog': changelog,
@@ -79,21 +76,27 @@
         version=version,
         file=file
     )
-    mirroring_template = string.Template(textwrap.dedent(
-        """
 
-        !!!: Make sure to copy the file to the release notes.
-        If you are using Google Cloud Storage, you might use a command like
-        gsutil cp bazel-bin/distro/${file} gs://bazel-mirror/${path}
-        gsutil setmeta -h "Cache-Control: public, max-age=31536000" "gs://bazel-mirror/${path}"
-        """).strip())
-    print(mirroring_template.substitute({
-        'org': org,
-        'repo': repo,
-        'version': version,
-        'file': file,
-        'path': path,
-    }))
+    if False:
+        # TODO: This matters for the Bazel team at Googel, who can mirror it, but
+        # does not make sense for the rest of the world.  Figure out if we should
+        # keep it or not.
+        mirroring_template = string.Template(textwrap.dedent(
+            """
+
+            !!!: Make sure to copy the file to the release notes.
+            If you are using Google Cloud Storage, you might use a command like
+            gsutil cp bazel-bin/distro/${file} gs://bazel-mirror/${path}
+            gsutil setmeta -h "Cache-Control: public, max-age=31536000" "gs://bazel-mirror/${path}"
+            """).strip())
+
+        print(mirroring_template.substitute({
+            'org': org,
+            'repo': repo,
+            'version': version,
+            'file': file,
+            'path': path,
+        }))
 
 
 def main():