You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by jd...@apache.org on 2026/07/26 11:33:25 UTC

(grails-intellij-plugin) branch build-hygiene-from-core updated: Generate the vote, result, and announcement emails from checked-in templates

This is an automated email from the ASF dual-hosted git repository.

jdaugherty pushed a commit to branch build-hygiene-from-core
in repository https://gitbox.apache.org/repos/asf/grails-intellij-plugin.git


The following commit(s) were added to refs/heads/build-hygiene-from-core by this push:
     new 88ae0a2  Generate the vote, result, and announcement emails from checked-in templates
88ae0a2 is described below

commit 88ae0a2653569f45921483290b661b8c70508476
Author: James Daugherty <jd...@jdresources.net>
AuthorDate: Sun Jul 26 07:32:27 2026 -0400

    Generate the vote, result, and announcement emails from checked-in templates
    
    Follows the precedent set for Grails releases: the release workflow renders the
    emails instead of leaving the release manager to write them by hand.
    
    Adds .github/vote_templates/{staged,vote_succeeded,announce}.txt, expanded with
    envsubst and printed to the job log with recipient, subject, and body.
    
    The upload job now records the dist.apache.org SVN revision the artifacts were
    committed at and resolves the tag commit id (dereferencing annotated tags), so
    the [VOTE] email cites exactly what was staged. It gains contents:read to check
    out the templates and query the tag.
    
    The release job prints the [RESULT][VOTE] and [ANNOUNCE] emails in place of the
    previous one-line reminder.
    
    RELEASE.md now points at the templates as the single source of truth rather than
    duplicating a hand-written vote email.
---
 .github/vote_templates/announce.txt       |  27 ++++++++
 .github/vote_templates/staged.txt         |  52 +++++++++++++++
 .github/vote_templates/vote_succeeded.txt |  12 ++++
 .github/workflows/release.yml             | 103 +++++++++++++++++++++++++++---
 RELEASE.md                                |  49 ++++++--------
 5 files changed, 204 insertions(+), 39 deletions(-)

diff --git a/.github/vote_templates/announce.txt b/.github/vote_templates/announce.txt
new file mode 100644
index 0000000..112e64b
--- /dev/null
+++ b/.github/vote_templates/announce.txt
@@ -0,0 +1,27 @@
+The Apache Grails community is pleased to announce the release of ${PROJECT_NAME} ${VERSION}.
+
+${PROJECT_DESC}
+
+<IF MILESTONE>
+This is a pre-release of a new version for ${PROJECT_NAME}. We greatly appreciate any feedback you can give us when using this version.
+</IF MILESTONE>
+
+The release notes are available here:
+https://github.com/${REPO_SLUG}/releases/tag/${TAG}
+
+For the complete list of changes:
+https://github.com/${REPO_SLUG}/compare/v<PREVIOUS_VERSION>...${TAG}
+
+The plugin can be installed from inside IntelliJ IDEA Ultimate via
+Settings > Plugins > Marketplace, or from the JetBrains Marketplace:
+https://plugins.jetbrains.com/plugin/org.intellij.grails
+
+Apache Grails website: https://grails.apache.org/
+
+Grails Resources:
+- Grails IntelliJ Plugin GitHub repo: https://github.com/${REPO_SLUG}
+- Issues: https://github.com/${REPO_SLUG}/issues
+- Mailing lists: https://grails.apache.org/community.html
+
+Happy Coding,
+The Apache Grails Team
diff --git a/.github/vote_templates/staged.txt b/.github/vote_templates/staged.txt
new file mode 100644
index 0000000..12741f3
--- /dev/null
+++ b/.github/vote_templates/staged.txt
@@ -0,0 +1,52 @@
+Hi Everyone,
+
+I am happy to start the VOTE thread to release ${PROJECT_NAME} ${VERSION}!
+
+Release notes for the release are here:
+https://github.com/${REPO_SLUG}/releases/tag/${TAG}
+
+The tag for this release is:
+https://github.com/${REPO_SLUG}/releases/tag/${TAG}
+Tag commit id: ${SHA}
+
+The artifacts to be voted on are located as follows (r${DIST_SVN_REVISION}):
+Source release: https://dist.apache.org/repos/dist/dev/${SVN_PROJECT}/${SVN_FOLDER}/${VERSION}/sources
+Binary distribution: https://dist.apache.org/repos/dist/dev/${SVN_PROJECT}/${SVN_FOLDER}/${VERSION}/distribution
+
+The official release is the source distribution. The plugin ZIP in the binary
+distribution is a convenience binary, signed for the JetBrains Marketplace and built
+from the same tagged source.
+
+Release artifacts are signed with a key from the following file:
+https://dist.apache.org/repos/dist/release/grails/KEYS
+
+Please vote on releasing this package as: ${PROJECT_NAME} ${VERSION}.
+
+Reminder on ASF release approval requirements for PMC members:
+https://www.apache.org/legal/release-policy.html#release-approval
+
+Hints on validating checksums/signatures (but replace md5sum with sha512sum):
+https://www.apache.org/info/verification.html
+
+Details of our release process are documented at:
+https://github.com/${REPO_SLUG}/blob/HEAD/RELEASE.md
+
+The staged artifacts can be checked out and verified in one step with the scripts
+checked into the repository:
+
+    etc/bin/verify.sh ${TAG} /tmp/grails-ij-verify
+
+That downloads the artifacts and the KEYS file, verifies the checksums and signatures,
+audits the licenses with Apache RAT, and rebuilds the plugin from the staged source
+distribution to confirm it matches the staged binary.
+
+The vote is open for a minimum of 72 hours and passes if a majority of at least
+three +1 PMC votes are cast.
+
+[ ] +1 Release ${PROJECT_NAME} ${VERSION}
+[ ]  0 I don't have a strong opinion about this, but I assume it's ok
+[ ] -1 Do not release ${PROJECT_NAME} ${VERSION} because...
+
+Here is my vote:
+
++1 (binding)
diff --git a/.github/vote_templates/vote_succeeded.txt b/.github/vote_templates/vote_succeeded.txt
new file mode 100644
index 0000000..f722d5d
--- /dev/null
+++ b/.github/vote_templates/vote_succeeded.txt
@@ -0,0 +1,12 @@
+The vote has passed with <X> +1 binding votes and <Y> +1 additional votes.
+
+<IF NEW EMAIL>
+Vote thread: <VOTE THREAD PERMALINK>
+</IF NEW EMAIL>
+
+I'll proceed with the release and announce it shortly.
+
+Thanks to everyone who participated in the vote!
+
+Regards
+<NAME>
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 5273b52..04a2aaa 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -25,6 +25,11 @@ env:
   DIST_NAME: apache-grails-intellij-plugin
   JAVA_DISTRIBUTION: liberica # .sdkmanrc pins librca = Liberica
   PROJECT_NAME: Apache Grails IntelliJ Plugin
+  PROJECT_DESC: >-
+    The Apache Grails IntelliJ Plugin adds Apache Grails support to IntelliJ IDEA Ultimate:
+    GSP language support, Grails project structure and navigation, run configurations,
+    taglib and domain class support, and integrations for i18n, coverage, Hibernate, Maven,
+    and language injection.
   REPO_SLUG: ${{ github.repository }}
   SVN_FOLDER: INTELLIJ
   SVN_PROJECT: grails
@@ -158,6 +163,8 @@ jobs:
   upload:
     name: "Upload Distributions to dist.apache.org"
     needs: [ publish, source ]
+    permissions:
+      contents: read # to check out the vote templates and resolve the tag SHA
     runs-on: ubuntu-latest
     env:
       SVN_USERNAME: ${{ secrets.SVC_DIST_GRAILS_USERNAME }}
@@ -166,7 +173,7 @@ jobs:
       - name: "📝 Establish release version"
         run: echo "VERSION=${TAG#v}" >> "$GITHUB_ENV"
       - name: "🛠️ Install tools"
-        run: sudo apt-get install -y subversion tree
+        run: sudo apt-get install -y subversion tree gettext-base # gettext-base provides envsubst for the vote email
       - name: "👀 Ensure dev/${{ env.SVN_PROJECT }}/${{ env.SVN_FOLDER }} folder exists"
         run: |
           set -e
@@ -215,11 +222,52 @@ jobs:
           tree
           svn add ${VERSION} --force
           svn commit -m "Upload ${PROJECT_NAME} distribution files for ${VERSION}" --username "${SVN_USERNAME}" --password "${SVN_PASSWORD}" --non-interactive
-      - name: "🗳 MANUAL - Start PMC Vote"
+      - name: "💾 Store Distribution SVN revision in a file"
+        # The vote email cites the SVN revision so voters can confirm they are looking at
+        # the same artifacts that were staged, even if the folder is touched afterwards.
+        run: |
+          cd dev-repo
+          svn info ${VERSION} > DIST_SVN_REVISION.txt
+          cat DIST_SVN_REVISION.txt
+      - name: "📥 Checkout repository"
+        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+        with:
+          path: repo
+          ref: ${{ env.TAG }}
+      - name: "📝 Resolve the tag commit id"
+        env:
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        # An annotated tag points at a tag object, so dereference it to the commit.
+        run: |
+          set -euo pipefail
+          ref_json=$(gh api "repos/${REPO_SLUG}/git/ref/tags/${TAG}")
+          type=$(jq -r '.object.type' <<< "$ref_json")
+          sha=$(jq -r '.object.sha' <<< "$ref_json")
+          if [ "$type" = "tag" ]; then
+            sha=$(gh api "repos/${REPO_SLUG}/git/tags/${sha}" --jq '.object.sha')
+          fi
+          echo "Found sha: $sha"
+          echo "SHA=${sha}" >> "$GITHUB_ENV"
+      - name: "📧 Print Grails PMC Vote Email"
         run: |
-          echo "::group::Manual Vote"
-          echo "Distributions staged at https://dist.apache.org/repos/dist/dev/${SVN_PROJECT}/${SVN_FOLDER}/${VERSION}"
-          echo "Start a [VOTE] thread for ${PROJECT_NAME} ${VERSION} on dev@grails.apache.org."
+          export DIST_SVN_REVISION=$(awk '/Last Changed Rev:/ {print $4}' dev-repo/DIST_SVN_REVISION.txt)
+
+          echo "::group::Grails PMC Vote Email"
+          echo ""
+          echo "TO:"
+          echo "*************************************************"
+          echo "dev@grails.apache.org"
+          echo "*************************************************"
+          echo ""
+          echo "Subject:"
+          echo "*************************************************"
+          echo "[VOTE] Release ${PROJECT_NAME} ${VERSION}"
+          echo "*************************************************"
+          echo ""
+          echo "Body:"
+          echo "*************************************************"
+          cat repo/.github/vote_templates/staged.txt | envsubst
+          echo "*************************************************"
           echo "::endgroup::"
   release:
     environment: release # post-vote gate: required reviewers configured in .asf.yaml
@@ -269,9 +317,46 @@ jobs:
           echo "Update https://reporter.apache.org/addrelease.html?${SVN_PROJECT} to add"
           echo "${SVN_FOLDER}-${VERSION} as complete as of ${TODAY}"
           echo "::endgroup::"
-      - name: "📧 MANUAL - Send Vote Result & Announcement Emails"
+      - name: "📧 MANUAL - Send Vote Result Email"
+        run: |
+          echo "::group::Manual Vote Result Email"
+          echo ""
+          echo "Send a new email or reply to the original vote email by changing the subject."
+          echo ""
+          echo "TO:"
+          echo "*************************************************"
+          echo "dev@grails.apache.org"
+          echo "*************************************************"
+          echo ""
+          echo "Subject:"
+          echo "*************************************************"
+          echo "[RESULT][VOTE] ${PROJECT_NAME} ${VERSION}"
+          echo "*************************************************"
+          echo ""
+          echo "Body:"
+          echo "*************************************************"
+          cat .github/vote_templates/vote_succeeded.txt | envsubst
+          echo "*************************************************"
+          echo "::endgroup::"
+      - name: "📧 MANUAL - Send Announcement Email"
         run: |
-          echo "::group::Manual Emails"
-          echo "Send [RESULT][VOTE] to dev@grails.apache.org and"
-          echo "[ANNOUNCE] ${PROJECT_NAME} ${VERSION} to announce@apache.org, dev@grails.apache.org, users@grails.apache.org."
+          echo "::group::Announcement Email"
+          echo ""
+          echo "Announcements must be sent from your @apache.org address."
+          echo "See https://infra.apache.org/committer-email.html"
+          echo ""
+          echo "TO:"
+          echo "*************************************************"
+          echo "announce@apache.org, dev@grails.apache.org, users@grails.apache.org"
+          echo "*************************************************"
+          echo ""
+          echo "Subject:"
+          echo "*************************************************"
+          echo "[ANNOUNCE] ${PROJECT_NAME} ${VERSION}"
+          echo "*************************************************"
+          echo ""
+          echo "Body:"
+          echo "*************************************************"
+          cat .github/vote_templates/announce.txt | envsubst
+          echo "*************************************************"
           echo "::endgroup::"
diff --git a/RELEASE.md b/RELEASE.md
index 20e3ac2..c18a513 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -229,36 +229,24 @@ following the [Apache voting process](https://www.apache.org/foundation/voting.h
 Only Grails PMC votes are binding; the vote runs a minimum of 72 hours and needs at least
 three +1 votes from PMC members.
 
-Template:
+**You do not need to write the email.** The `upload` job's final step,
+*📧 Print Grails PMC Vote Email*, renders it for you and prints it to the job log with the
+recipient, subject, and body ready to copy. It fills in the version, tag, tag commit id,
+staged artifact URLs, and the `dist.apache.org` SVN revision the artifacts were committed
+at, so voters can confirm they are looking at exactly what was staged.
 
-```
-Subject: [VOTE] Release Apache Grails IntelliJ Plugin <version>
-
-Hi all,
-
-I'd like to call a vote to release Apache Grails IntelliJ Plugin <version>.
-
-The source and binary distributions are staged at:
-  https://dist.apache.org/repos/dist/dev/grails/INTELLIJ/<version>/
-
-The release tag is:
-  https://github.com/apache/grails-intellij-plugin/releases/tag/v<version>
+The email bodies live in [`.github/vote_templates`](.github/vote_templates) and are
+expanded with `envsubst`:
 
-The KEYS file used to sign the artifacts:
-  https://dist.apache.org/repos/dist/release/grails/KEYS
+| Template | Used by | Sent as |
+| --- | --- | --- |
+| `staged.txt` | `upload` job | `[VOTE]` to `dev@grails.apache.org` |
+| `vote_succeeded.txt` | `release` job | `[RESULT][VOTE]` to `dev@grails.apache.org` |
+| `announce.txt` | `release` job | `[ANNOUNCE]` to `announce@apache.org`, `dev@`, `users@` |
 
-Verification instructions are in RELEASE.md; the artifacts can be checked with:
-  etc/bin/verify.sh v<version> /tmp/grails-ij-verify
-
-The vote is open for at least 72 hours.
-
-[ ] +1 Release this package
-[ ]  0 No opinion
-[ ] -1 Do not release this package (please provide the reason)
-
-Thanks,
-<your name>
-```
+Edit the templates rather than the workflow when the wording needs to change. Placeholders
+in angle brackets (`<X>`, `<NAME>`, `<PREVIOUS_VERSION>`) are deliberately left for the
+release manager to fill in; everything in `${...}` is substituted automatically.
 
 ## 8. Publish the release (`release` job)
 
@@ -278,9 +266,10 @@ requires the reviewers listed in `.asf.yaml`):
    JetBrains Marketplace.
 4. **MANUAL:** record the release at <https://reporter.apache.org/addrelease.html?grails>
    as `INTELLIJ-<version>`, dated the day the distributions were promoted.
-5. **MANUAL:** send `[RESULT][VOTE]` to `dev@grails.apache.org`, then `[ANNOUNCE]` to
-   `announce@apache.org`, `dev@grails.apache.org`, and `users@grails.apache.org`.
-   Announcements must come from your `@apache.org` address
+5. **MANUAL:** send the `[RESULT][VOTE]` and `[ANNOUNCE]` emails. The job's last two steps
+   print both, rendered from
+   [`.github/vote_templates`](.github/vote_templates) — copy them from the log and fill in
+   the angle-bracket placeholders. Announcements must come from your `@apache.org` address
    (see <https://infra.apache.org/committer-email.html>).
 6. Flag the GitHub Release as **latest**.