From 43e4d41be7f9bed14f5673e348f2dce0832ae8e2 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 14:52:11 -0700 Subject: [PATCH 01/23] Add docstrings for the constants module --- .../pr_to_update_go/constants.py | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/constants.py b/.github/actions/pr-to-update-go/pr_to_update_go/constants.py index b3d8770bae..44316db9a4 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/constants.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/constants.py @@ -10,14 +10,88 @@ # See the License for the specific language governing permissions and # limitations under the License. # +""" +The constants module holds some constants used by the PR maker. + +Environment variable names, and the meanings of the values of those variables: + + ENV_GIT_AUTHOR_NAME - The username of the author for commits + ENV_GITHUB_REPOSITORY - The "name" of the repository set by GHA (e.g. octocat/Hello-World) + ENV_GITHUB_REPOSITORY_OWNER - The repository owner's name set by GHA (e.g. octocat) + ENV_GITHUB_TOKEN - The token used to access the GitHub API - set by GHA + ENV_GO_VERSION_FILE - The repository-relative path to the file containing the Go version + ENV_ENV_FILE - The repository-relative path to an environment file containing + a line setting the variable GO_VERSION to the Go version + (e.g. GO_VERSION=3.2.1) + +Miscellaneous: + + GIT_AUTHOR_EMAIL_TEMPLATE - Template used to construct the Git Author's email address. + GO_REPO_NAME - The name of the official Go repository. + GO_VERSION_URL - A URL from which information about Go releases is fetched. + RELEASE_PAGE_URL - The URL of a webpage containing changelog notes about Go releases. +""" from typing import Final ENV_GIT_AUTHOR_NAME: Final = 'GIT_AUTHOR_NAME' +""" +The name of the environment variable set to username of the author for commits. +""" + ENV_GITHUB_REPOSITORY: Final = 'GITHUB_REPOSITORY' +""" +The name of the environment variable set to "name" of the repository set by GHA +(e.g. octocat/Hello-World). +""" + ENV_GITHUB_REPOSITORY_OWNER: Final = 'GITHUB_REPOSITORY_OWNER' +""" +The name of the environment variable set to repository owner's name set by GHA +(e.g. octocat). +""" + ENV_GITHUB_TOKEN: Final = 'GITHUB_TOKEN' +""" +The name of the environment variable set to token used to access the GitHub +API - set by GHA. +""" + ENV_GO_VERSION_FILE: Final = 'GO_VERSION_FILE' +""" +The name of the environment variable set to repository-relative path to the file +containing the Go version. +""" + +ENV_ENV_FILE: Final = 'ENV_FILE' +""" +The name of the environment variable set to repository-relative path to an +environment file containing a line setting the variable GO_VERSION to the Go +version (e.g. GO_VERSION=3.2.1). +""" + + GIT_AUTHOR_EMAIL_TEMPLATE: Final = '{git_author_name}@users.noreply.github.com' +"""Template used to construct the Git Author's email address.""" + GO_REPO_NAME: Final = 'golang/go' +"""The name of the official Go repository.""" + GO_VERSION_URL: Final = 'https://golang.org/dl/?mode=json' +"""A URL from which information about Go releases is fetched.""" + RELEASE_PAGE_URL: Final = 'https://golang.org/doc/devel/release.html' +"""The URL of a webpage containing changelog notes about Go releases.""" + + +__all__ = [ + "ENV_GIT_AUTHOR_NAME", + "ENV_GITHUB_REPOSITORY", + "ENV_GITHUB_REPOSITORY_OWNER", + "ENV_GITHUB_TOKEN", + "ENV_GO_VERSION_FILE", + "ENV_ENV_FILE", + "GIT_AUTHOR_EMAIL_TEMPLATE", + "GO_REPO_NAME", + "GO_VERSION_URL", + "RELEASE_PAGE_URL", +] From 8ed319f22013fc2de33ddf1bc956ca40061b3ee4 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 14:58:11 -0700 Subject: [PATCH 02/23] Fix linting issues in __main__ module --- .../pr_to_update_go/__main__.py | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/__main__.py b/.github/actions/pr-to-update-go/pr_to_update_go/__main__.py index e59e39572c..b23644c7ee 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/__main__.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/__main__.py @@ -10,6 +10,13 @@ # See the License for the specific language governing permissions and # limitations under the License. # +""" +A utility for automatically updating Go. For full usage information, refer to +the action's README.rst file. + +Options + --update-version-only Exit after updating GO_VERSION file. +""" import os import sys from argparse import ArgumentParser, Namespace @@ -21,17 +28,23 @@ def main() -> None: + """ + The entrypoint for running the PR-maker. + """ parser = ArgumentParser() - parser.add_argument('--update-version-only', type=bool, default=False, help='Exit after updating the GO_VERSION file') + parser.add_argument( + '--update-version-only', + action="store_true", + help='Exit after updating the GO_VERSION file' + ) args: Namespace = parser.parse_args() try: - github_token: str = os.environ[ENV_GITHUB_TOKEN] + github_token = os.environ[ENV_GITHUB_TOKEN] except KeyError: print(f'Environment variable {ENV_GITHUB_TOKEN} must be defined.') sys.exit(1) - gh = Github(login_or_token=github_token) - GoPRMaker(gh).run(args.update_version_only) - + gh_api = Github(login_or_token=github_token) + GoPRMaker(gh_api).run(args.update_version_only) main() From bfe7a365f9188f028ea121ae92920d6e7c4a0918 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 15:09:54 -0700 Subject: [PATCH 03/23] Fix importing internal PyGitHub variable --- .../pr_to_update_go/go_pr_maker.py | 74 ++++++++++++------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 0c91915221..6096db85ff 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -33,7 +33,6 @@ from github.ContentFile import ContentFile from github.GitCommit import GitCommit from github.GithubException import BadCredentialsException, GithubException, UnknownObjectException -from github.GithubObject import NotSet from github.GitRef import GitRef from github.GitTree import GitTree from github.InputGitAuthor import InputGitAuthor @@ -156,7 +155,7 @@ class GoPRMaker: gh_api: Github latest_go_version: str repo: Repository - author: InputGitAuthor + author: Optional[InputGitAuthor] def __init__(self, gh_api: Github): self.gh_api = gh_api @@ -167,7 +166,7 @@ def __init__(self, gh_api: Github): git_author_email = GIT_AUTHOR_EMAIL_TEMPLATE.format(git_author_name=git_author_name) self.author = InputGitAuthor(git_author_name, git_author_email) except KeyError: - self.author = NotSet + self.author = None print('Will commit using the default author') def branch_exists(self, branch: str) -> bool: @@ -302,29 +301,40 @@ def set_go_version(self, go_version: str, commit_message: str, print(f'Created branch {source_branch_name}') go_version_file = getenv(ENV_GO_VERSION_FILE) - kwargs = { - "branch": source_branch_name, - "committer": NotSet, - "content": f"{go_version}\n", - "path": go_version_file, - "message": commit_message, - "sha": self.file_contents(go_version_file, source_branch_name).sha - } - try: - git_author_name = getenv(ENV_GIT_AUTHOR_NAME) - git_author_email = GIT_AUTHOR_EMAIL_TEMPLATE.format(git_author_name=git_author_name) - author: InputGitAuthor = InputGitAuthor(name=git_author_name, email=git_author_email) - kwargs["author"] = author - except KeyError: + content = f"{go_version}\n" + sha = self.file_contents(go_version_file, source_branch_name).sha + if self.author: + self.repo.update_file( + author=self.author, + branch=source_branch_name, + content=content, + path=go_version_file, + message=commit_message, + sha=sha + ) + else: print('Committing using the default author') + self.repo.update_file( + branch=source_branch_name, + content=content, + path=go_version_file, + message=commit_message, + sha=sha + ) - self.repo.update_file(**kwargs) print(f'Updated {go_version_file} on {self.repo.name}') - env_path = os.path.join(os.path.dirname(go_version_file), ".env") - kwargs["path"] = env_path - kwargs["content"] = f"GO_VERSION={go_version}\n" - kwargs["sha"] = self.file_contents(env_path, source_branch_name).sha - commit: Commit = self.repo.update_file(**kwargs)["commit"] + env_path = os.path.join(os.path.dirname(getenv(ENV_ENV_FILE)), ".env") + content = f"GO_VERSION={go_version}\n" + sha = self.file_contents(env_path, source_branch_name).sha + commit = self.repo.update_file( + branch=source_branch_name, + content=content, + path=env_path, + message=commit_message, + sha=sha + )["commit"] + if not isinstance(commit, Commit): + raise TypeError("'commit' property of file update response was not a Commit") print(f"Updated {env_path} on {self.repo.name}") return commit @@ -356,9 +366,21 @@ def update_golang_org_x(self, previous_commit: Commit) -> Optional[GitCommit]: tree: GitTree = self.repo.create_git_tree(tree_elements, base_tree) commit_message: str = f'Update golang.org/x/ dependencies for go{self.latest_go_version}' previous_git_commit: GitCommit = self.repo.get_git_commit(previous_commit.sha) - git_commit: GitCommit = self.repo.create_git_commit(message=commit_message, tree=tree, - parents=[previous_git_commit], - author=self.author, committer=self.author) + git_commit: GitCommit + if self.author: + git_commit = self.repo.create_git_commit( + message=commit_message, + tree=tree, + parents=[previous_git_commit], + author=self.author, + committer=self.author + ) + else: + git_commit = self.repo.create_git_commit( + message=commit_message, + tree=tree, + parents=[previous_git_commit] + ) print('Updated golang.org/x/ dependencies') return git_commit From e66d5bff9e876add45bc4ac7c0265331d690a5ec Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 15:10:36 -0700 Subject: [PATCH 04/23] Fix accessing private member of a class --- .../pr-to-update-go/pr_to_update_go/go_pr_maker.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 6096db85ff..86095fa606 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -41,7 +41,6 @@ from github.MainClass import Github from github.PullRequest import PullRequest from github.Repository import Repository -from github.Requester import Requester from pr_to_update_go.constants import ENV_GITHUB_TOKEN, GO_VERSION_URL, ENV_GITHUB_REPOSITORY, \ ENV_GITHUB_REPOSITORY_OWNER, GO_REPO_NAME, RELEASE_PAGE_URL, ENV_GO_VERSION_FILE, \ @@ -192,13 +191,8 @@ def update_branch(self, branch_name: str, sha: str) -> None: Note that only fast-forward updates are possible, as this doesn't "force" push. """ - requester: Requester = self.repo._requester - patch_parameters = { - 'sha': sha, - } - requester.requestJsonAndCheck( - 'PATCH', self.repo.url + f'/git/refs/heads/{branch_name}', input=patch_parameters - ) + ref = self.repo.get_git_ref(f"heads/{branch_name}") + ref.edit(sha) def run(self, update_version_only: bool = False) -> None: """ From a4676b9e40f8cf2ab8c0be8d15d311cc5040720b Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 15:10:48 -0700 Subject: [PATCH 05/23] Remove unused import --- .github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 86095fa606..ea0f49c030 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -24,7 +24,7 @@ import re import subprocess import sys -from typing import Optional, TypedDict, Any, Final +from typing import Optional, TypedDict, Any import requests From 2084ed42fadac70f8f45cfb9df28f07ca484814b Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 15:11:43 -0700 Subject: [PATCH 06/23] Make milestone url non-optional May need to revert this, not sure it'll work --- .../pr-to-update-go/pr_to_update_go/go_pr_maker.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index ea0f49c030..0c157efada 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -240,13 +240,13 @@ def get_repo(self, repo_name: str) -> Repository: raise PermissionError(f"Credentials from token '{ENV_GITHUB_TOKEN}' were bad") from e return repo - def get_go_milestone(self, go_version: str) -> Optional[str]: + def get_go_milestone(self, go_version: str) -> str: """ Gets a URL for the GitHub milestone that tracks the release of the passed Go version. If the passed version is not found to have a milestone associated with - it, an exception is raised. + it, a LookupError exception is raised. """ go_repo: Repository = self.get_repo(GO_REPO_NAME) milestones = go_repo.get_milestones(state='all', sort='due_on', direction='desc') @@ -254,8 +254,8 @@ def get_go_milestone(self, go_version: str) -> Optional[str]: for milestone in milestones: # type: Milestone if milestone.title == milestone_title: print(f'Found Go milestone {milestone.title}') - return milestone.raw_data.get('html_url') - raise Exception(f'Could not find a milestone named {milestone_title}.') + return milestone.url + raise LookupError(f'could not find a milestone named {milestone_title}') def file_contents(self, file: str, branch: str = "master") -> ContentFile: """ @@ -393,9 +393,6 @@ def create_pr(self, latest_go_version: str, commit_message: str, owner: str, return milestone_url = self.get_go_milestone(latest_go_version) - if milestone_url is None: - #TODO subclass this - raise LookupError(f"no milestone found for '{latest_go_version}'") pr_body = get_pr_body(latest_go_version, milestone_url) pull_request: PullRequest = self.repo.create_pull( title=commit_message, From 8cac94d0125cd57070dc26426337407bd842a46c Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 15:12:11 -0700 Subject: [PATCH 07/23] Wrap long line, un-sentence-ify Exception text --- .../pr_to_update_go/go_pr_maker.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 0c157efada..1d10499211 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -42,9 +42,18 @@ from github.PullRequest import PullRequest from github.Repository import Repository -from pr_to_update_go.constants import ENV_GITHUB_TOKEN, GO_VERSION_URL, ENV_GITHUB_REPOSITORY, \ - ENV_GITHUB_REPOSITORY_OWNER, GO_REPO_NAME, RELEASE_PAGE_URL, ENV_GO_VERSION_FILE, \ - ENV_GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL_TEMPLATE +from pr_to_update_go.constants import ( + ENV_ENV_FILE, + ENV_GITHUB_TOKEN, + GO_VERSION_URL, + ENV_GITHUB_REPOSITORY, + ENV_GITHUB_REPOSITORY_OWNER, + GO_REPO_NAME, + RELEASE_PAGE_URL, + ENV_GO_VERSION_FILE, + ENV_GIT_AUTHOR_NAME, + GIT_AUTHOR_EMAIL_TEMPLATE +) class GoVersion(TypedDict): """ @@ -141,7 +150,7 @@ def get_latest_major_upgrade(from_go_version: str) -> str: if major_version == get_major_version(fetched_go_version): break else: - raise Exception(f'No supported {major_version} Go versions exist.') + raise Exception(f'no supported {major_version} Go versions exist') print(f'Latest version of Go {major_version} is {fetched_go_version}') return fetched_go_version From 74cf861e769a9bd944a7ca459c78eba8476539b3 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 15:12:25 -0700 Subject: [PATCH 08/23] Cover unit test case with doctest --- .github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 1d10499211..03be27a07a 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -87,6 +87,8 @@ def get_major_version(from_go_version: str) -> str: >>> get_major_version("1.23.45-6rc7") '1.23' + >>> get_major_version("1.2.3") + '1.2' >>> get_major_version("not a release version") '' """ From cb22f0f407265da9bc5a9be69fb317dbb23ab27d Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 15:22:08 -0700 Subject: [PATCH 09/23] Fix the get_major_version test --- .github/actions/pr-to-update-go/tests/test_go_pr_maker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py b/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py index 1e0c378074..f7cddd8ad5 100644 --- a/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py +++ b/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py @@ -12,14 +12,14 @@ # from unittest import TestCase -from pr_to_update_go.go_pr_maker import GoPRMaker +from pr_to_update_go.go_pr_maker import get_major_version, GoPRMaker class TestGoPRMaker(TestCase): def test_get_major_version(self) -> None: version: str = '1.2.3' expected_major_version: str = '1.2' - actual_major_version: str = GoPRMaker.get_major_version(version) + actual_major_version: str = get_major_version(version) self.assertEqual(expected_major_version, actual_major_version) return From 3210f5ec2ae70d7b3ed32d61a0d25e045c3701ff Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 15:22:52 -0700 Subject: [PATCH 10/23] Add docstrings --- .../pr-to-update-go/tests/test_go_pr_maker.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py b/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py index f7cddd8ad5..8926fb6e08 100644 --- a/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py +++ b/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py @@ -10,13 +10,28 @@ # See the License for the specific language governing permissions and # limitations under the License. # +""" +The unit testing module for the pr_to_update_go package. + +Note that this module merely reiterates the docstring tests - and only covers a +proper subset of the test cases covered by said docstring tests. +""" + from unittest import TestCase from pr_to_update_go.go_pr_maker import get_major_version, GoPRMaker class TestGoPRMaker(TestCase): + """ + Tests the go_pr_maker module. + + Note that this reiterates the docstring tests - and only covers a proper + subset of those test cases. + """ + def test_get_major_version(self) -> None: + """Tests the get_major_version function.""" version: str = '1.2.3' expected_major_version: str = '1.2' actual_major_version: str = get_major_version(version) @@ -24,6 +39,7 @@ def test_get_major_version(self) -> None: return def test_get_release_notes(self) -> None: + """Tests the get_release_notes function.""" go_version: str = '4.15.6' expected_release_notes: str = f'

go4.15.6 The expected release notes

' release_notes_with_whitespace: str = f"""

From 1d1ee74676c971c088ef40ab5a261cd6e1ecfc33 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 15:23:22 -0700 Subject: [PATCH 11/23] Remove unnecessary 'f' modifier --- .github/actions/pr-to-update-go/tests/test_go_pr_maker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py b/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py index 8926fb6e08..ad2c128c0c 100644 --- a/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py +++ b/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py @@ -41,7 +41,6 @@ def test_get_major_version(self) -> None: def test_get_release_notes(self) -> None: """Tests the get_release_notes function.""" go_version: str = '4.15.6' - expected_release_notes: str = f'

go4.15.6 The expected release notes

' release_notes_with_whitespace: str = f"""

go{go_version} The expected release notes

""" @@ -49,4 +48,5 @@ def test_get_release_notes(self) -> None: {release_notes_with_whitespace} text

after

4.15.7""" actual_release_notes: str = GoPRMaker.get_release_notes(go_version, content) + expected_release_notes: str = '

go4.15.6 The expected release notes

' self.assertEqual(expected_release_notes, actual_release_notes) From 12c5865dde076f5e7d0eecf55b737afc962c2ac4 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 15:46:33 -0700 Subject: [PATCH 12/23] Fix passing unnecessary explicit option-argument --- .github/workflows/pr-to-update-go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-to-update-go.yml b/.github/workflows/pr-to-update-go.yml index 156f9fe3e1..b09567120d 100644 --- a/.github/workflows/pr-to-update-go.yml +++ b/.github/workflows/pr-to-update-go.yml @@ -41,7 +41,7 @@ jobs: run: pip install .github/actions/pr-to-update-go - name: Update Go version if: ${{ steps.checkout.outcome == 'success' }} - run: python3 -m pr_to_update_go --update-version-only=true + run: python3 -m pr_to_update_go --update-version-only env: GIT_AUTHOR_NAME: asfgit GITHUB_TOKEN: ${{ github.token }} From eae669e311bda7f5895e08dbcdef5562c925aeaa Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 15:49:48 -0700 Subject: [PATCH 13/23] Fix required ENV_FILE environment variable is unset --- .github/workflows/pr-to-update-go.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pr-to-update-go.yml b/.github/workflows/pr-to-update-go.yml index b09567120d..ec63b3b44d 100644 --- a/.github/workflows/pr-to-update-go.yml +++ b/.github/workflows/pr-to-update-go.yml @@ -46,6 +46,7 @@ jobs: GIT_AUTHOR_NAME: asfgit GITHUB_TOKEN: ${{ github.token }} GO_VERSION_FILE: GO_VERSION + ENV_FILE: .env - name: Check Go version run: echo "::set-output name=value::$(cat GO_VERSION)" id: go-version @@ -60,3 +61,4 @@ jobs: GIT_AUTHOR_NAME: asfgit GITHUB_TOKEN: ${{ github.token }} GO_VERSION_FILE: GO_VERSION + ENV_FILE: .env From 3ae8b87af5d0199a831696c9cc6506fb2cad6549 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 16:04:48 -0700 Subject: [PATCH 14/23] Add running the doctests when module is executed --- .github/actions/pr-to-update-go/README.rst | 6 ++++++ .../actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/.github/actions/pr-to-update-go/README.rst b/.github/actions/pr-to-update-go/README.rst index c90240409b..6814472ad9 100644 --- a/.github/actions/pr-to-update-go/README.rst +++ b/.github/actions/pr-to-update-go/README.rst @@ -72,3 +72,9 @@ To run the unit tests: .. code-block:: shell python3 -m unittest discover ./tests + +To run the doctests: + +.. code-block:: shell + + python3 ./pr_to_update_go/go_pr_maker.py diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 03be27a07a..67e4fa1b4a 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -418,3 +418,7 @@ def create_pr(self, latest_go_version: str, commit_message: str, owner: str, except UnknownObjectException: print('Unable to find a label named "go version"', file=sys.stderr) print(f'Created pull request {pull_request.html_url}') + +if __name__ == "__main__": + import doctest + doctest.testmod() From c0c0c1e86b1831e24cec4298264a7c6160f847d2 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 16:07:12 -0700 Subject: [PATCH 15/23] Separate release note parsing from fetching and add tests The separation makes it testable --- .../pr_to_update_go/go_pr_maker.py | 55 +++++++++++++++---- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 67e4fa1b4a..02c94d976d 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -73,7 +73,7 @@ def get_pr_body(go_version: str, milestone_url: str) -> str: pr_template = file.read() go_major_version = get_major_version(go_version) - release_notes = get_release_notes(go_version) + release_notes = _get_release_notes(go_version) pr_body = pr_template.format(GO_VERSION=go_version, GO_MAJOR_VERSION=go_major_version, RELEASE_NOTES=release_notes, MILESTONE_URL=milestone_url) print('Templated PR body') @@ -112,22 +112,53 @@ def getenv(var: str) -> str: get_repo_name = lambda: getenv(ENV_GITHUB_REPOSITORY) get_repo_owner = lambda: getenv(ENV_GITHUB_REPOSITORY_OWNER) -def get_release_notes(go_version: str) -> str: +def parse_release_notes(version: str, content: str) -> str: + """ + Parses Go version release notes. + + >>> raw = '''test + ...

Big Title

+ ... + ...

+ ... go4.15.5 text before + ...

+ ...

+ ... go4.15.6 The expected release notes + ...

+ ...

+ ... go4.15.7 text after + ...

+ ... + ... ''' + >>> parse_release_notes("4.15.6", raw) + '

go4.15.6 The expected release notes

' + >>> raw = '''test + ... go4.15.6 is mentioned earlier + ... go4.15.6 before on the same line as the opening tag

+ ... go4.15.6 the actual notes. + ...

go4.15.6 later on the same line as the closing tag + ... go4.15.6 in a later context + ... ''' + >>> parse_release_notes("4.15.6", raw) + '

go4.15.6 the actual notes.

' + """ + go_version_pattern = version.replace('.', r"\.") + release_notes_pattern = re.compile( + r"

\s*\n\s*go"+go_version_pattern+r".*?

", + re.MULTILINE | re.DOTALL + ) + matches = release_notes_pattern.search(content) + if not matches: + raise Exception(f'could not find release notes for Go {version}') + return " ".join(matches.group(0).split()) + +def _get_release_notes(go_version: str) -> str: """ Gets the release notes for the given Go version. """ release_history_response = requests.get(RELEASE_PAGE_URL) release_history_response.raise_for_status() - release_notes_content = release_history_response.content.decode() - go_version_pattern = go_version.replace('.', '\\.') - release_notes_pattern: str = f'

\\s*\\n\\s*go{go_version_pattern}.*?

' - release_notes_matches = re.search(release_notes_pattern, release_notes_content, - re.MULTILINE | re.DOTALL) - if release_notes_matches is None: - raise Exception(f'Could not find release notes on {RELEASE_PAGE_URL}') - release_notes = re.sub(r'[\s\t]+', ' ', release_notes_matches.group(0)) - return release_notes - + return parse_release_notes(go_version, release_history_response .content.decode()) def get_latest_major_upgrade(from_go_version: str) -> str: """ From b0f10fd1afcd5449539b0ff8c8e31c2188c312bf Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 16:08:45 -0700 Subject: [PATCH 16/23] Fix release notes-parsing unit test --- .../pr-to-update-go/tests/test_go_pr_maker.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py b/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py index ad2c128c0c..1c6d1ee452 100644 --- a/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py +++ b/.github/actions/pr-to-update-go/tests/test_go_pr_maker.py @@ -19,7 +19,7 @@ from unittest import TestCase -from pr_to_update_go.go_pr_maker import get_major_version, GoPRMaker +from pr_to_update_go.go_pr_maker import get_major_version, parse_release_notes class TestGoPRMaker(TestCase): @@ -40,13 +40,13 @@ def test_get_major_version(self) -> None: def test_get_release_notes(self) -> None: """Tests the get_release_notes function.""" - go_version: str = '4.15.6' - release_notes_with_whitespace: str = f"""

+ go_version = '4.15.6' + expected_release_notes = '

go4.15.6 The expected release notes

' + release_notes_with_whitespace = f"""

go{go_version} The expected release notes

""" - content: str = f"""go4.15.5 text before + content = f"""go4.15.5 text before {release_notes_with_whitespace} text

after

4.15.7""" - actual_release_notes: str = GoPRMaker.get_release_notes(go_version, content) - expected_release_notes: str = '

go4.15.6 The expected release notes

' + actual_release_notes = parse_release_notes(go_version, content) self.assertEqual(expected_release_notes, actual_release_notes) From ac0f1f9d491f4b040a40dbbbdaaefad62aad3fc4 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 16:30:28 -0700 Subject: [PATCH 17/23] Separate fetching latest Go version from parsing response for testing --- .../pr_to_update_go/go_pr_maker.py | 69 ++++++++++++++----- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 02c94d976d..99beedf43c 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -160,7 +160,54 @@ def _get_release_notes(go_version: str) -> str: release_history_response.raise_for_status() return parse_release_notes(go_version, release_history_response .content.decode()) -def get_latest_major_upgrade(from_go_version: str) -> str: +def find_latest_major_upgrade(major_version: str, versions: list[GoVersion]) -> str: + """ + Finds the latest version in `versions` with the given "major" version. + + Note that this expects and relies on the ordering of the passed `versions` + being in descending order (as returned by the Go website API). + >>> versions=[ + ... { + ... "stable": True, + ... "version": "1.3.0", + ... "files": [] + ... }, + ... { + ... "stable": False, + ... "version": "1.2.5", + ... "files": [] + ... }, + ... { + ... "stable": True, + ... "version": "1.2.4", + ... "files": [] + ... }, + ... { + ... "stable": True, + ... "version": "one.two.three", + ... "files": [] + ... }, + ... { + ... "stable": True, + ... "version": "1.2.3", + ... "files": [] + ... }] + >>> find_latest_major_upgrade("1.2", versions) + '1.2.4' + """ + for version in versions: + if not version["stable"]: + continue + match = re.search(r"[\d.]+", version["version"]) + if not match: + continue + fetched_go_version = match.group(0) + if major_version == get_major_version(fetched_go_version): + return fetched_go_version + + raise Exception(f'no supported {major_version} Go versions exist') + +def _get_latest_major_upgrade(from_go_version: str) -> str: """ Gets the version of the latest Go release that is the same "major" version as the passed current (or "from") Go version. @@ -168,26 +215,14 @@ def get_latest_major_upgrade(from_go_version: str) -> str: If no stable version is found that is the same "major" version as the given current version, an exception is raised. """ + response = requests.get(GO_VERSION_URL) + response.raise_for_status() + versions: list[GoVersion] = json.loads(response.content) major_version = get_major_version(from_go_version) - go_version_response = requests.get(GO_VERSION_URL) - go_version_response.raise_for_status() - go_version_content: list[GoVersion] = json.loads(go_version_response.content) - fetched_go_version: str = '' - for go_version in go_version_content: - if not go_version["stable"]: - continue - match = re.search(r"[\d.]+", go_version["version"]) - if not match: - continue - fetched_go_version = match.group(0) - if major_version == get_major_version(fetched_go_version): - break - else: - raise Exception(f'no supported {major_version} Go versions exist') + fetched_go_version = find_latest_major_upgrade(major_version, versions) print(f'Latest version of Go {major_version} is {fetched_go_version}') return fetched_go_version - class GoPRMaker: """ A class to generate pull requests for the purpose of updating the Go version From 64f365f45cf894a0a5a8aae01bb0748772057bd8 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 16:30:44 -0700 Subject: [PATCH 18/23] Unexport things that don't need to be exported --- .../pr_to_update_go/go_pr_maker.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 99beedf43c..ac2f336af2 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -64,7 +64,7 @@ class GoVersion(TypedDict): stable: bool version: str -def get_pr_body(go_version: str, milestone_url: str) -> str: +def _get_pr_body(go_version: str, milestone_url: str) -> str: """ Generates the body of a Pull Request given a Go release version and a URL that points to information about what changes were in said release. @@ -109,9 +109,6 @@ def getenv(var: str) -> str: """ return os.environ[var] -get_repo_name = lambda: getenv(ENV_GITHUB_REPOSITORY) -get_repo_owner = lambda: getenv(ENV_GITHUB_REPOSITORY_OWNER) - def parse_release_notes(version: str, content: str) -> str: """ Parses Go version release notes. @@ -235,7 +232,7 @@ class GoPRMaker: def __init__(self, gh_api: Github): self.gh_api = gh_api - self.repo = self.get_repo(get_repo_name()) + self.repo = self.get_repo(getenv(ENV_GITHUB_REPOSITORY)) try: git_author_name = getenv(ENV_GIT_AUTHOR_NAME) @@ -277,7 +274,7 @@ def run(self, update_version_only: bool = False) -> None: necessary to create the PR that will update the repository's Go version. """ repo_go_version = self.get_repo_go_version() - self.latest_go_version = get_latest_major_upgrade(repo_go_version) + self.latest_go_version = _get_latest_major_upgrade(repo_go_version) commit_message: str = f'Update Go version to {self.latest_go_version}' source_branch_name: str = f'go-{self.latest_go_version}' @@ -304,8 +301,13 @@ def run(self, update_version_only: bool = False) -> None: sha: str = update_golang_org_x_commit.sha self.update_branch(source_branch_name, sha) - self.create_pr(self.latest_go_version, commit_message, get_repo_owner(), source_branch_name, - target_branch) + self.create_pr( + self.latest_go_version, + commit_message, + getenv(ENV_GITHUB_REPOSITORY_OWNER), + source_branch_name, + target_branch + ) def get_repo(self, repo_name: str) -> Repository: """ @@ -470,7 +472,7 @@ def create_pr(self, latest_go_version: str, commit_message: str, owner: str, return milestone_url = self.get_go_milestone(latest_go_version) - pr_body = get_pr_body(latest_go_version, milestone_url) + pr_body = _get_pr_body(latest_go_version, milestone_url) pull_request: PullRequest = self.repo.create_pull( title=commit_message, body=pr_body, From 3e86967b73282c90f5941e56551e96d2d4e90c39 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 16:43:21 -0700 Subject: [PATCH 19/23] Remove trivially inferrable types --- .../pr_to_update_go/go_pr_maker.py | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index ac2f336af2..90483b2464 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -28,18 +28,14 @@ import requests -from github.Branch import Branch from github.Commit import Commit from github.ContentFile import ContentFile from github.GitCommit import GitCommit from github.GithubException import BadCredentialsException, GithubException, UnknownObjectException from github.GitRef import GitRef -from github.GitTree import GitTree from github.InputGitAuthor import InputGitAuthor from github.InputGitTreeElement import InputGitTreeElement -from github.Label import Label from github.MainClass import Github -from github.PullRequest import PullRequest from github.Repository import Repository from pr_to_update_go.constants import ( @@ -275,10 +271,10 @@ def run(self, update_version_only: bool = False) -> None: """ repo_go_version = self.get_repo_go_version() self.latest_go_version = _get_latest_major_upgrade(repo_go_version) - commit_message: str = f'Update Go version to {self.latest_go_version}' + commit_message = f'Update Go version to {self.latest_go_version}' - source_branch_name: str = f'go-{self.latest_go_version}' - target_branch: str = 'master' + source_branch_name = f'go-{self.latest_go_version}' + target_branch = 'master' if repo_go_version == self.latest_go_version: print(f'Go version is up-to-date on {target_branch}, nothing to do.') return @@ -296,10 +292,9 @@ def run(self, update_version_only: bool = False) -> None: print(f'Branch {source_branch_name} has been created, exiting...') return - update_golang_org_x_commit: Optional[GitCommit] = self.update_golang_org_x(commit) - if isinstance(update_golang_org_x_commit, GitCommit): - sha: str = update_golang_org_x_commit.sha - self.update_branch(source_branch_name, sha) + update_golang_org_x_commit = self.update_golang_org_x(commit) + if update_golang_org_x_commit: + self.update_branch(source_branch_name, update_golang_org_x_commit.sha) self.create_pr( self.latest_go_version, @@ -327,7 +322,7 @@ def get_go_milestone(self, go_version: str) -> str: If the passed version is not found to have a milestone associated with it, a LookupError exception is raised. """ - go_repo: Repository = self.get_repo(GO_REPO_NAME) + go_repo = self.get_repo(GO_REPO_NAME) milestones = go_repo.get_milestones(state='all', sort='due_on', direction='desc') milestone_title = f'Go{go_version}' for milestone in milestones: # type: Milestone @@ -367,7 +362,7 @@ def set_go_version(self, go_version: str, commit_message: str, This includes updating the GO_VERSION and .env files at the repository's root. """ - master: Branch = self.repo.get_branch('master') + master = self.repo.get_branch('master') sha = master.commit.sha ref = f'refs/heads/{source_branch_name}' self.repo.create_git_ref(ref, sha) @@ -419,7 +414,7 @@ def update_golang_org_x(self, previous_commit: Commit) -> Optional[GitCommit]: subprocess.run(['git', 'fetch', 'origin'], check=True) subprocess.run(['git', 'checkout', previous_commit.sha], check=True) subprocess.run([os.path.join(os.path.dirname(__file__), 'update_golang_org_x.sh')], check=True) - files_to_check: list[str] = ['go.mod', 'go.sum', os.path.join('vendor', 'modules.txt')] + files_to_check = ['go.mod', 'go.sum', os.path.join('vendor', 'modules.txt')] tree_elements: list[InputGitTreeElement] = [] for file in files_to_check: diff_process = subprocess.run(['git', 'diff', '--exit-code', '--', file], check=False) @@ -435,10 +430,10 @@ def update_golang_org_x(self, previous_commit: Commit) -> Optional[GitCommit]: return None tree_hash = subprocess.check_output( ['git', 'log', '-1', '--pretty=%T', previous_commit.sha]).decode().strip() - base_tree: GitTree = self.repo.get_git_tree(sha=tree_hash) - tree: GitTree = self.repo.create_git_tree(tree_elements, base_tree) + base_tree = self.repo.get_git_tree(sha=tree_hash) + tree = self.repo.create_git_tree(tree_elements, base_tree) commit_message: str = f'Update golang.org/x/ dependencies for go{self.latest_go_version}' - previous_git_commit: GitCommit = self.repo.get_git_commit(previous_commit.sha) + previous_git_commit = self.repo.get_git_commit(previous_commit.sha) git_commit: GitCommit if self.author: git_commit = self.repo.create_git_commit( @@ -473,7 +468,7 @@ def create_pr(self, latest_go_version: str, commit_message: str, owner: str, milestone_url = self.get_go_milestone(latest_go_version) pr_body = _get_pr_body(latest_go_version, milestone_url) - pull_request: PullRequest = self.repo.create_pull( + pull_request = self.repo.create_pull( title=commit_message, body=pr_body, head=f'{owner}:{source_branch_name}', @@ -481,7 +476,7 @@ def create_pr(self, latest_go_version: str, commit_message: str, owner: str, maintainer_can_modify=True, ) try: - go_version_label: Label = self.repo.get_label('go version') + go_version_label = self.repo.get_label('go version') pull_request.add_to_labels(go_version_label) except UnknownObjectException: print('Unable to find a label named "go version"', file=sys.stderr) From bbd3878dceddddfbba86339fc4db22f0d96f5b90 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 16:48:48 -0700 Subject: [PATCH 20/23] Fix not stripping whitespace from repo go version --- .github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 90483b2464..57d397a228 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -351,7 +351,7 @@ def get_repo_go_version(self, branch: str = 'master') -> str: Gets the current Go version used at the head of the given branch (or not given to use "master" by default) for the repository. """ - return self.file_contents(getenv(ENV_GO_VERSION_FILE), branch).decoded_content.decode() + return self.file_contents(getenv(ENV_GO_VERSION_FILE), branch).decoded_content.decode().strip() def set_go_version(self, go_version: str, commit_message: str, source_branch_name: str) -> Commit: From c614163f4e3450229b0c958d68a2721469e47987 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 2 Mar 2022 17:09:27 -0700 Subject: [PATCH 21/23] remove extraneous path separator --- .github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 57d397a228..043a8eb88d 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -65,7 +65,7 @@ def _get_pr_body(go_version: str, milestone_url: str) -> str: Generates the body of a Pull Request given a Go release version and a URL that points to information about what changes were in said release. """ - with open(os.path.join(os.path.dirname(__file__), '/pr_template.md'), encoding="UTF-8") as file: + with open(os.path.join(os.path.dirname(__file__), 'pr_template.md'), encoding="UTF-8") as file: pr_template = file.read() go_major_version = get_major_version(go_version) From 5453d9b889f2ae6df25c7913e15622491b9dcbf6 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 3 Mar 2022 08:16:42 -0700 Subject: [PATCH 22/23] Remove unimported type decoration --- .github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 043a8eb88d..3c975b0b57 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -325,7 +325,7 @@ def get_go_milestone(self, go_version: str) -> str: go_repo = self.get_repo(GO_REPO_NAME) milestones = go_repo.get_milestones(state='all', sort='due_on', direction='desc') milestone_title = f'Go{go_version}' - for milestone in milestones: # type: Milestone + for milestone in milestones: if milestone.title == milestone_title: print(f'Found Go milestone {milestone.title}') return milestone.url From fa512a8f3d5cc1756aeccf5db205867ae6267d63 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 3 Mar 2022 08:26:44 -0700 Subject: [PATCH 23/23] Fix using incorrect Milestone URL. --- .../actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py index 3c975b0b57..acb358dadb 100644 --- a/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py +++ b/.github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py @@ -328,7 +328,11 @@ def get_go_milestone(self, go_version: str) -> str: for milestone in milestones: if milestone.title == milestone_title: print(f'Found Go milestone {milestone.title}') - return milestone.url + # Technically it would probably be best to use the 'html_url' + # returned by the GH API, but accessing that through PyGithub + # involves using poorly-documented properties of that library, + # as well as sacrificing type-safety. + return f"https://github.com/{GO_REPO_NAME}/milestone/{milestone.number}" raise LookupError(f'could not find a milestone named {milestone_title}') def file_contents(self, file: str, branch: str = "master") -> ContentFile: