-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Basic implementation. Manually tested happy day scenario.
- Loading branch information
1 parent
d71a23c
commit 4ee582c
Showing
14 changed files
with
184 additions
and
1 deletion.
There are no files selected for viewing
Empty file.
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from version_tag_check.version_tag_check_action import VersionTagCheckAction | ||
|
||
if __name__ == '__main__': | ||
action = VersionTagCheckAction() | ||
action.run() |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
requests~=2.31.0 |
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import requests | ||
|
||
from version_tag_check.version import Version | ||
|
||
|
||
class GitHubRepository: | ||
def __init__(self, owner: str, repo: str, token: str): | ||
self.owner = owner | ||
self.repo = repo | ||
self.token = token | ||
self.headers = { | ||
'Authorization': f'Bearer {self.token}', | ||
'Accept': 'application/vnd.github.v3+json' | ||
} | ||
|
||
def get_all_tags(self) -> list: | ||
tags = [] | ||
page = 1 | ||
per_page = 100 | ||
while True: | ||
response = requests.get( | ||
f'https://api.github.com/repos/{self.owner}/{self.repo}/tags', | ||
headers=self.headers, | ||
params={'per_page': per_page, 'page': page} | ||
) | ||
if response.status_code != 200: | ||
raise Exception(f'Failed to fetch tags: {response.status_code} {response.text}') | ||
page_tags = response.json() | ||
if not page_tags: | ||
break | ||
for tag_info in page_tags: | ||
tag_name = tag_info['name'] | ||
try: | ||
version = Version(tag_name) | ||
tags.append(version) | ||
except ValueError: | ||
pass # Ignore tags that are not valid versions | ||
if len(page_tags) < per_page: | ||
break | ||
page += 1 | ||
return tags |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import re | ||
from functools import total_ordering | ||
|
||
@total_ordering | ||
class Version: | ||
VERSION_REGEX = r'^v(\d+)\.(\d+)\.(\d+)$' | ||
|
||
def __init__(self, version_str: str): | ||
self.version_str = version_str | ||
self.major = None | ||
self.minor = None | ||
self.patch = None | ||
self.parse() | ||
|
||
def parse(self): | ||
match = re.match(self.VERSION_REGEX, self.version_str) | ||
if not match: | ||
raise ValueError(f'Invalid version format: {self.version_str}') | ||
self.major, self.minor, self.patch = map(int, match.groups()) | ||
|
||
def is_valid_format(self) -> bool: | ||
return re.match(self.VERSION_REGEX, self.version_str) is not None | ||
|
||
def __eq__(self, other): | ||
return (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch) | ||
|
||
def __lt__(self, other): | ||
return (self.major, self.minor, self.patch) < (other.major, other.minor, other.patch) | ||
|
||
def __str__(self): | ||
return self.version_str |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import os | ||
import sys | ||
|
||
from version_tag_check.github_repository import GitHubRepository | ||
from version_tag_check.version import Version | ||
from version_tag_check.version_validator import VersionValidator | ||
|
||
|
||
class VersionTagCheckAction: | ||
def __init__(self): | ||
self.github_token = os.environ.get('INPUT_GITHUB_TOKEN') | ||
self.version_tag_str = os.environ.get('INPUT_VERSION_TAG') | ||
self.branch = os.environ.get('INPUT_BRANCH') | ||
self.fails_on_error = os.environ.get('INPUT_FAILS_ON_ERROR', 'true').lower() == 'true' | ||
self.github_repository = os.environ.get('INPUT_GITHUB_REPOSITORY') | ||
|
||
# TODO - extra method & add more validations | ||
if not self.github_token: | ||
print('GITHUB_TOKEN is not set.') | ||
sys.exit(1) | ||
if not self.github_repository: | ||
print('GITHUB_REPOSITORY is not set.') | ||
sys.exit(1) | ||
|
||
self.owner, self.repo = self.github_repository.split('/') | ||
|
||
def run(self): | ||
try: | ||
new_version = Version(self.version_tag_str) | ||
except ValueError as e: | ||
print(str(e)) | ||
self.handle_failure() | ||
return | ||
|
||
if not new_version.is_valid_format(): | ||
print('Tag does not match the required format "v[0-9]+.[0-9]+.[0-9]+"') | ||
self.handle_failure() | ||
return | ||
|
||
repository = GitHubRepository(self.owner, self.repo, self.github_token) | ||
existing_versions = repository.get_all_tags() | ||
|
||
validator = VersionValidator(new_version, existing_versions) | ||
if validator.is_valid_increment(): | ||
self.write_output('true') | ||
print('New tag is valid.') | ||
sys.exit(0) | ||
else: | ||
latest_version = validator.get_latest_version() | ||
print(f'New tag {self.version_tag_str} is not one version higher than the latest tag {latest_version}.') | ||
self.handle_failure() | ||
|
||
def write_output(self, valid_value): | ||
output_file = os.environ.get('GITHUB_OUTPUT') | ||
if output_file: | ||
with open(output_file, 'a') as fh: | ||
print(f'valid={valid_value}', file=fh) | ||
else: | ||
print('GITHUB_OUTPUT is not set.') | ||
|
||
def handle_failure(self): | ||
self.write_output('false') | ||
if self.fails_on_error: | ||
sys.exit(1) | ||
else: | ||
sys.exit(0) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from typing import Optional | ||
|
||
from version_tag_check.version import Version | ||
|
||
|
||
class VersionValidator: | ||
def __init__(self, new_version: Version, existing_versions: list): | ||
self.new_version = new_version | ||
self.existing_versions = existing_versions | ||
|
||
def get_latest_version(self) -> Optional[Version]: | ||
if not self.existing_versions: | ||
return None | ||
return max(self.existing_versions) | ||
|
||
def is_valid_increment(self) -> bool: | ||
latest_version = self.get_latest_version() | ||
if not latest_version: | ||
# Any version is valid if no previous versions exist | ||
return True | ||
|
||
lv = latest_version | ||
nv = self.new_version | ||
|
||
if nv.major == lv.major: | ||
if nv.minor == lv.minor: | ||
return nv.patch == lv.patch + 1 | ||
elif nv.minor == lv.minor + 1: | ||
return nv.patch == 0 | ||
else: | ||
return False | ||
elif nv.major == lv.major + 1: | ||
return nv.minor == 0 and nv.patch == 0 | ||
else: | ||
return False |