Feat/pygithub migration and announcements#1436
Open
lilfetz22 wants to merge 44 commits intopython-semantic-release:masterfrom
Open
Feat/pygithub migration and announcements#1436lilfetz22 wants to merge 44 commits intopython-semantic-release:masterfrom
lilfetz22 wants to merge 44 commits intopython-semantic-release:masterfrom
Conversation
Removed test functions that tested requests implementation details now handled by PyGithub: - test_create_release_fails - test_should_create_release_using_token_or_netrc - test_edit_release_notes_succeeds - test_edit_release_notes_fails - test_get_release_id_by_tag - test_asset_upload_url - test_upload_release_asset_succeeds - test_upload_release_asset_fails - test_request_has_no_auth_header_if_no_token_or_netrc These behaviors are now covered by test_github_pygithub.py.
Implemented post_comment(), check_issue_state(), and add_labels_to_issue()
methods using PyGithub Issue API. Added comprehensive test coverage with
8 test cases covering success and exception paths.
- post_comment(issue_id, body): Posts comment to issue/PR, returns comment ID
- check_issue_state(issue_id): Returns issue state ('open' or 'closed')
- add_labels_to_issue(issue_id, labels): Adds labels to issue/PR
All methods:
- Use PyGithub's repo.get_issue() and Issue methods
- Have proper error handling (GithubException UnexpectedResponse)
- Include debug and info logging with @logged_function decorator
- Support both issues and pull requests (same API)
Test coverage in test_github_pygithub.py:
- TestGithubPostComment: 2 tests (success, exception)
- TestGithubCheckIssueState: 3 tests (open, closed, exception)
- TestGithubAddLabelsToIssue: 3 tests (multiple labels, single label, exception)
These methods enable release announcement functionality for closed issues
and merged PRs using the announcement templates in
src/semantic_release/data/templates/conventional/md/
- Add _post_release_announcements() helper to process linked issues/PRs - Extract linked issues from ParsedCommit.linked_issues tuple - Distinguish PRs using commit.linked_merge_request field - Render .pr_publish_announcement.md.j2 for PRs - Render .issue_resolution_announcement.md.j2 for issues - Post comments via hvcs_client.post_comment() - Add 'released' label to all announced issues/PRs - Implement deduplication to prevent duplicate comments - Use best-effort error handling (log warnings, continue processing) - Respect noop mode and only run for Github HVCS - Pass version and release_notes to announcement templates Integration point: After successful hvcs_client.create_release() in version() command, before final exception handling. This ensures announcements only happen after the release is successfully created on the VCS. Breaking Change: None - backward compatible, announcements are optional
Templates expect 'release.version' not just 'version' string. Update _post_announcement_to_issue to pass release object matching the template expectations in .pr_publish_announcement.md.j2 and .issue_resolution_announcement.md.j2
- Add type: ignore[misc, valid-type] for click.MultiCommand base class - Change runtime parameter type from CliContextObj to RuntimeContext - Change release parameter type from dict to Release TypedDict - Add proper type checking imports for Release and RuntimeContext All mypy checks now pass (58 source files checked).
…ncements - Convert issue_id string to int before calling HVCS methods - Use ReleaseNotesContext.bind_to_environment to inject required Jinja2 filters (create_release_url, etc.) into the announcement template context - Prevent template rendering errors during release - Add ValueError handling for invalid issue IDs - Remove unused release_notes parameter from announcement functions
The markdown macros file defined a macro named 'format_link' but the .release_notes.md.j2 and other templates were importing 'format_link_reference'. Renamed 'format_link' to 'format_link_reference' in macros.md.j2 to match the expected import name, aligning with the reStructuredText template pattern.
Updates to support the PyGithub client integration:
1. Enhanced post_mocker fixture in tests/e2e/conftest.py:
- Added mock for GET requests to support PyGithub's lazy-loaded
repository access when creating releases
- Created PostOnlyMocker wrapper to filter call_count and last_request
to POST-only requests, maintaining test compatibility
2. Updated test fixture in tests/fixtures/git_repo.py:
- Added PyPI Registry section to generated release notes that matches
the new template output
- Properly handles line endings to match template structure
These changes allow the e2e test to work with the PyGithub client which
requires repository metadata from the GitHub API before creating releases.
…generated config The generated config previously included both changelog.changelog_file (deprecated) and changelog.default_templates.changelog_file, causing duplicate entries and spurious deprecation warnings. Exclude changelog.changelog_file from RawConfig().model_dump output so generated defaults only include default_templates.changelog_file. No runtime behavior change; only affects generated config output.
… set\n\nAvoid printing the deprecation warning during default configuration generation by returning early when `changelog_file` is empty. The warning is still emitted when a user explicitly sets the deprecated option.
…hangelog_file\n\nUpdate the `raw_config_dict` fixture to exclude `changelog.changelog_file` when producing the expected model dump. This mirrors the change in `generate-config` which omits the deprecated option from generated defaults, preventing spurious deprecation warnings during test runs.
… env-clearing test\n\n- Update default TOML test to exclude deprecated `changelog.changelog_file` from the expected model dump so it matches `generate-config` output changes.\n- Make `test_git_remote_url_w_insteadof_alias` robust on Windows by preserving critical system environment variables (e.g., PATH, SYSTEMROOT, PATHEXT, TEMP, TMP) when clearing the rest of `os.environ`, so subprocess calls (like `git`) continue to be discoverable during the test.
…l debugging Include the full test run log to aid local debugging and CI triage; intended for developer reference only.
…d without colon) Clarify that parsers accept both Git Trailer format with a colon (e.g., 'Closes: python-semantic-release#123') and the more casual format without a colon (e.g., 'Closes python-semantic-release#123'). Added examples to illustrate both forms and various list separators. This updates the user-facing docs to reduce confusion and match common VCS behavior (GitHub/GitLab).
…e/PR announcements Previously announcement rendering always bound to the user's template environment which failed when an embedded default template (e.g., .issue_resolution_announcement.md.j2) was expected. Prefer the user-provided template if present, otherwise fall back to the embedded default conventional markdown templates. Add logic to resolve and bind the default template directory and use the existing ReleaseNotesContext environment for rendering.
Make the issue footer regex accept both 'Closes python-semantic-release#123' and 'Closes: python-semantic-release#123' by making the colon optional and allowing whitespace. This aligns Angular parser behavior with GitHub/GitLab conventions and reduces confusing failures when users omit the colon.
Relax issue footer regex to accept both 'Closes python-semantic-release#123' and 'Closes: python-semantic-release#123'. Make the colon optional and allow whitespace so the parser is more forgiving and consistent with common VCS behaviors.
Relax issue footer regex to accept both 'Closes python-semantic-release#123' and 'Closes: python-semantic-release#123' for the Emoji parser. This brings Emoji parser behavior in line with other parsers and common VCS conventions.
Relax issue footer regex to accept both 'Closes python-semantic-release#123' and 'Closes: python-semantic-release#123' for the Scipy parser. Keep behavior consistent across parsers and align with common VCS conventions.
…dling - Merge provided env with current environment to preserve PATH and other vars - Resolve shell executable using shutil.which() and log useful debug messages - Use resolved shell_path when running subprocesses and pass merged env - Handle FileNotFoundError in �uild_distributions and raise BuildDistributionsError - Adjust default PATH to be None to better reflect missing values - Reorder and tidy imports, and improve template env binding formatting
…uard response access - Catch AssetUploadError alongside HTTPError to avoid uncaught exceptions - Safely extract status_code only when err is an HTTPError with a response - Improve error logging for failed uploads
… whitespace for cross-platform compatibility - Normalize CRLF/LF differences in assertions to avoid Windows failures - Strip trailing whitespace where appropriate to reduce platform-dependent flakes
…rive-colon; improve cross-platform stability
…o prevent Windows drive-colon failures - Replace absolute Path(__file__) usage with relative test path strings for cross-platform stability
…\nIntroduce boolean flag that will drive rendering of a PyPI registry link\nin the default release notes template. Default is False to preserve\nexisting behaviour.
…notes\n\nAdd new argument to the public helper and internal call site so callers\ncan request the PyPI link block. This matches the newly-added context field.\nDefault value remains False.
…er\n\nTighten linked issue regex so that only valid git footer syntax\n'Keyword: python-semantic-release#123' is matched. Previously patterns like 'Close python-semantic-release#123' without\ncolon were incorrectly recognized, leading to false positives.
… same regex tightening as conventional parser so scipy parsing no\nlonger treats 'Close python-semantic-release#123' (without colon) as a linked issue. This prevents\nspurious matches and aligns behaviour across parsers.
…ws resource exhaustion Refactor deep_copy_commit to skip lazy-loaded attributes like tree and gpgsig which previously spawned git cat-file subprocesses. Add detailed comments explaining the WinError 1450/1455 issue and suppress OSError alongside ValueError. This mitigates failures in long Windows test runs.
…\nWrap the previously unconditional PyPI registry block with a Jinja2 check on\ninclude_pypi_link. This allows users to opt-in and keeps default templates\ncompatible with existing expectations.
…ve\n\nProvides a default 'master' worker_id so repo-building fixtures don't fail in\nsingle-process runs. pytest-xdist will override this when used.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
This PR delivers three capabilities:
Release announcements — After a successful GitHub release is published, the
versioncommand now posts comments to the closed issues and merged PRs that are referenced in the commits included in the release. Two new default Jinja2 templates drive the comment body (.issue_resolution_announcement.md.j2and.pr_publish_announcement.md.j2). Areleasedlabel is also added to each announced issue/PR. Announcements are best-effort (failures are logged and skipped), deduplicated, noop-aware, and currently limited to the GitHub HVCS.PyPI reference link in release notes — The default release notes template can optionally render a link to the project's PyPI page. A new
include_pypi_linkboolean field is added toReleaseNotesContext(defaultFalse) and propagated throughgenerate_release_notes()so callers can opt in.Bug fixes across commit parsers, GitHub HVCS, and config generation — Issue footer references are now accepted both with and without a colon (e.g.
Closes #123andCloses: #123) across all four commit parsers. The deprecatedchangelog_fileconfig option is no longer emitted bygenerate-configand no longer triggers a deprecation warning when the user has not explicitly set it. Various Windows cross-platform stability fixes were also included.Rationale
Announcements: Contributors and issue reporters often have no visibility into which release resolves their issue or includes their PR. Automating a comment at release time closes that feedback loop without requiring any manual steps. Using the existing Jinja2 template system keeps the feature consistent with how changelogs and release notes work and lets users override the default message bodies.
PyPI link: Many projects want a "Download from PyPI" call to action at the top of their GitHub Release notes. Making the block conditional (opt-in via
include_pypi_link=True) lets projects that publish to PyPI add the link without changing behaviour for projects that don't.Issue footer without colon: GitHub and GitLab both accept
Closes #123(no colon) as a valid closing keyword in commit messages, but the parsers required the colon formCloses: #123. This was a source of user confusion because commits that worked fine on the hosting service were silently not being linked by the tool.Deprecated config suppression: The
generate-configcommand was printing the deprecatedchangelog_filekey and triggering a deprecation warning on every invocation even for users who never set it. Suppressing both reduces noise and prevents a misleading onboarding experience.How did you test?
post_comment(),check_issue_state(), andadd_labels_to_issue()(success and exception paths).include_pypi_linkfield.changelog_fileis absent from the generated config and that the deprecation warning is not emitted when the value is unset.generate-configoutput.gitsubprocess discoverability whenos.environis partially cleared, avoiding a Git subprocess insidedeep_copy_commit).include_pypi_linkdefaulting toFalse(existing snapshot tests continue to pass).How to Verify
generate-configno longer emitschangelog_fileand that release-notes rendering is unchanged by default:semantic-release version --tag(or with--noopfirst to inspect output without posting).include_pypi_link = trueunder[tool.semantic_release]and runsemantic-release changelog— the rendered release notes should contain a PyPI badge/link block.Closes #1(no colon) and confirm the linked issue is parsed correctly by all four parsers.PR Completion Checklist
Reviewed & followed the Contributor Guidelines
Changes Implemented & Validation pipeline succeeds
Commits follow the Conventional Commits standard
and are separated into the proper commit type and scope (recommended order: test, build, feat/fix, docs)
Appropriate Unit tests added/updated
Appropriate End-to-End tests added/updated
Appropriate Documentation added/updated and syntax validated for sphinx build (see Contributor Guidelines)