Skip to content

feat: add release email generation tooling#743

Open
hussain-s wants to merge 4 commits into
apache:mainfrom
hussain-s:feat/issue-719-release-email-tooling
Open

feat: add release email generation tooling#743
hussain-s wants to merge 4 commits into
apache:mainfrom
hussain-s:feat/issue-719-release-email-tooling

Conversation

@hussain-s
Copy link
Copy Markdown

Add release email generation tooling to scripts/apache_release.py for vote, result, and announcement emails.

Changes

  • add vote-email, result-email, and announce-email commands to scripts/apache_release.py
  • add Jinja templates for each generated email under scripts/templates/
  • align the generated email wording with Apache Incubator guidance and an Iceberg-style structure
  • add unit coverage for email rendering and argument handling in tests/test_apache_release_email.py
  • document the release-email commands in scripts/README.md

How I tested this

  • ran python3 scripts/apache_release.py vote-email --version 0.41.0 --rc 1
  • ran python3 scripts/apache_release.py result-email --version 0.41.0 --rc 1 --binding-yes 3
  • ran python3 scripts/apache_release.py announce-email --version 0.41.0
  • ran .venv/bin/python -m pytest tests/test_apache_release_email.py
  • ran .venv/bin/python -m pytest tests/

Notes

  • full test suite passed locally: 520 passed, 5 skipped
  • generated emails now explicitly mention incubation status and keep incubating in the artifact/release context where appropriate

Checklist

  • PR has an informative and human-readable title (this will be pulled into the release notes)
  • Changes are limited to a single goal (no scope creep)
  • Code passed the pre-commit check & code is left cleaner/nicer than when first encountered.
  • Any change in functionality is tested
  • New functions are documented (with a description, list of inputs, and expected output)
  • Placeholder code is flagged / future TODOs are captured in comments
  • Project documentation has been updated if adding/changing functionality.

@github-actions github-actions Bot added the area/ci Workflows, build, release scripts label Apr 18, 2026
@hussain-s hussain-s marked this pull request as ready for review April 18, 2026 21:50
@andreahlert andreahlert requested a review from Copilot April 19, 2026 11:03
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds release-email generation support to the existing Apache release helper script, providing templated vote/result/announcement emails aligned with Apache Incubator guidance.

Changes:

  • Added vote-email, result-email, and announce-email subcommands to scripts/apache_release.py with Jinja2-based rendering.
  • Introduced Jinja templates under scripts/templates/ for vote/result/announcement emails.
  • Added unit tests covering CLI parsing and template rendering for the new email commands.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
scripts/apache_release.py Adds template rendering, changelog-summary generation, clipboard copy support, and new email subcommands.
scripts/templates/vote_email.j2 New vote email template.
scripts/templates/result_email.j2 New result email template.
scripts/templates/announce_email.j2 New announcement email template.
tests/test_apache_release_email.py New tests for parser handling + rendering output.
scripts/README.md Documents the new email-generation commands.
.gitignore Adds uv.lock.
Comments suppressed due to low confidence (1)

scripts/apache_release.py:398

  • required_tools = command_requirements.get(...) returns the actual list stored in command_requirements. Later, required_tools.append("java") mutates that shared list, which can make subsequent validations in the same process incorrectly require Java for that command. Use a copy (e.g., list(...)) before appending to avoid side effects.
    required_tools = command_requirements.get(args.command, [])

    # Check for RAT if needed
    if hasattr(args, "check_licenses") or hasattr(args, "check_licenses_report"):
        if getattr(args, "check_licenses", False) or getattr(args, "check_licenses_report", False):
            required_tools.append("java")
            if not getattr(args, "rat_jar", None):

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/apache_release.py Outdated
Comment thread scripts/apache_release.py Outdated
Comment thread scripts/templates/result_email.j2 Outdated
Comment thread scripts/templates/vote_email.j2
Comment thread scripts/templates/result_email.j2
Comment thread scripts/templates/announce_email.j2
@hussain-s hussain-s force-pushed the feat/issue-719-release-email-tooling branch from 95cb22c to acbb9e1 Compare April 19, 2026 19:30
Comment thread scripts/apache_release.py Outdated
Comment thread scripts/apache_release.py Outdated
Copy link
Copy Markdown
Contributor

@skrawcz skrawcz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you run the pre-commit check and fix those up please -- see dev guide for installing it. otherwise let's just assume jinja2 is required -- please add that as an optional dependency to pyproject.toml so someone can install what's required to run the release?

@andreahlert
Copy link
Copy Markdown
Collaborator

Code review

Found 1 issue:

  1. --binding-yes defaults to 3, so running result-email without specifying vote counts silently generates an email stating "Therefore, the release candidate has passed." A release manager could accidentally send a misleading result email before collecting any votes. Should be required=True instead of default=3.

burr/scripts/apache_release.py

Lines 1318 to 1325 in acbb9e1

result_email_parser.add_argument("--rc", dest="rc_num", required=True, help="RC number")
result_email_parser.add_argument(
"--binding-yes", type=int, default=3, help="Number of binding +1 votes"
)
result_email_parser.add_argument(
"--non-binding-yes", type=int, default=0, help="Number of non-binding +1 votes"
)
result_email_parser.add_argument("--abstain", type=int, default=0, help="Number of 0 votes")

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@hussain-s hussain-s force-pushed the feat/issue-719-release-email-tooling branch from acbb9e1 to a8941b2 Compare April 21, 2026 05:17
Comment thread scripts/apache_release.py Outdated
vote_thread_url: Optional[str] = None,
) -> dict[str, str]:
"""Build rendering context for the result email template."""
release_passed = binding_yes >= 3 and binding_yes > no_votes
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no_votes mixes binding and non-binding -1 votes, but Apache voting rules only allow binding -1 to block a release. Concrete failure case: 3 binding +1, 2 binding -1, 3 non-binding -1 — no_votes=5, 3 > 5 is False, script outputs "not passed", but the binding tally (3 vs 2) actually passes under Apache rules.

Suggested fix — split into two flags and compare only binding -1:

# argparse (~line 1319) — replace --no-votes with:
result_email_parser.add_argument("--binding-no", type=int, default=0, help="Number of binding -1 votes")
result_email_parser.add_argument("--non-binding-no", type=int, default=0, help="Number of non-binding -1 votes")
# _build_result_email_context — update signature and logic:
def _build_result_email_context(version, rc_num, binding_yes, non_binding_yes, abstain, binding_no, non_binding_no, vote_thread_url=None):
    release_passed = binding_yes >= 3 and binding_yes > binding_no

The template tally line (-1: {{ no_votes }}) would need updating to show binding and non-binding -1 separately too.

🤖 Generated with Claude Code

@github-actions github-actions Bot added area/examples Relates to /examples pr/needs-rebase Conflicts with main labels Apr 28, 2026
@github-actions github-actions Bot removed the pr/needs-rebase Conflicts with main label Apr 28, 2026
@andreahlert andreahlert added the kind/improvement Improving something that already exists label Apr 29, 2026
Copy link
Copy Markdown
Collaborator

@andreahlert andreahlert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks @hussain-s

@elijahbenizzy elijahbenizzy enabled auto-merge (squash) May 1, 2026 16:47
@hussain-s hussain-s requested a review from skrawcz May 3, 2026 18:15
@github-actions github-actions Bot added the pr/stale No activity for 14+ days after review label May 18, 2026
@github-actions
Copy link
Copy Markdown

This PR has been inactive for 14 days after receiving review feedback.
Converting to draft.

Please mark it as ready for review when you have addressed the comments.
If no activity occurs within 90 days, it will be closed automatically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ci Workflows, build, release scripts area/examples Relates to /examples kind/improvement Improving something that already exists pr/stale No activity for 14+ days after review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants