diff --git a/src/common/github.py b/src/common/github.py index 1c65e348..fb3db3a4 100644 --- a/src/common/github.py +++ b/src/common/github.py @@ -11,6 +11,12 @@ class Release: self.is_prerelease: bool = is_prerelease +class Tag: + def __init__(self, name: str, commit_at: str) -> None: + self.name: str = name + self.commit_date: str = commit_at + + def fetch_releases(repo_id: str) -> list[Release]: logging.info(f"fetching {repo_id} GitHub releases") (owner, repo) = repo_id.split('/') @@ -48,3 +54,41 @@ query($endCursor: String) { release_data['isPrerelease'])) return releases + +def fetch_tags(repo_id: str) -> list[Tag]: + logging.info(f"fetching {repo_id} tags") + (owner, repo) = repo_id.split('/') + child = subprocess.run("""gh api graphql --paginate -f query=' +query($endCursor: String) { + repository(name: "%s", owner: "%s") { + refs(refPrefix: "refs/tags/", first: 100, after: $endCursor) { + pageInfo { hasNextPage, endCursor } + edges { + node { + name + target { + ... on Tag { + tagger { + date + } + } + } + } + } + } + } +}'""" % (repo, owner), capture_output=True, timeout=300, check=True, shell=True) # noqa: UP031 + logging.info(f"fetched {repo_id} tags") + + responses = child.stdout.decode("utf-8").strip().replace('}{', '}\n{').split("\n") + pages = [json.loads(response) for response in responses] + + tags = [] + for page in pages: + for edge in page['data']['repository']['refs']['edges']: + tag_name = edge['node']['name'] + tags_date = edge['node']['target'].get('tagger', {}).get('date', None) + if tags_date: + tags.append(Tag(tag_name, tags_date)) + + return tags diff --git a/src/github_tags.py b/src/github_tags.py new file mode 100644 index 00000000..fce22a68 --- /dev/null +++ b/src/github_tags.py @@ -0,0 +1,23 @@ +import sys + +from common import dates, endoflife, github, releasedata + +"""Fetches versions from GitHub tags using the GraphQL API and the GitHub CLI. + +Note: GraphQL API and GitHub CLI are used because it's simpler: no need to manage pagination and authentication. +""" + +METHOD = "github_tags" + + +p_filter = sys.argv[1] if len(sys.argv) > 1 else None +m_filter = sys.argv[2] if len(sys.argv) > 2 else None +for config in endoflife.list_configs(p_filter, METHOD, m_filter): + with releasedata.ProductData(config.product) as product_data: + for tag in github.fetch_tags(config.url): + version_str = tag.name + version_match = config.first_match(version_str) + if version_match: + version = config.render(version_match) + date = dates.parse_datetime(tag.commit_date) + product_data.declare_version(version, date)