1
0

feat: add support for multiple immutable release tag URLs in a repo

Adds detection and version tracking for URLs like:
- releases/download/{tag}/{asset}
- releases/tag/{tag}

This enables monorepo workflows where multiple mods share a repository
but use immutable tags (e.g., mod-name__latest) instead of the automatic
releases/latest endpoint.

Uses asset creation timestamps to generate sequential versions in
YYYYMMDD_HHMMSS format, ensuring each mod gets independent version
tracking rather than sharing the repository's latest release version.

Maintains full backward compatibility with existing URL patterns.
This commit is contained in:
Gabriel Freitas
2025-06-18 13:02:41 -03:00
parent 96811ac2bf
commit 2777af675b
2 changed files with 55 additions and 5 deletions

View File

@@ -29,12 +29,20 @@ def extract_repo_info(repo_url):
VersionSource = Enum("VersionSource", [
("RELEASE_TAG", "release"),
("HEAD", "commit"),
("SPECIFIC_TAG", "specific_tag"),
])
def get_version_string(source: Enum, owner, repo, start_timestamp, n = 1):
def get_version_string(source: Enum, owner, repo, start_timestamp, n = 1, tag_data=None):
"""Get the version string from a given GitHub repo."""
if source is VersionSource.RELEASE_TAG:
url = f'https://api.github.com/repos/{owner}/{repo}/releases/latest'
elif source is VersionSource.SPECIFIC_TAG:
if not tag_data:
print(f"ERROR: SPECIFIC_TAG source requires tag_name")
return None
tag_name = tag_data['name']
url = f'https://api.github.com/repos/{owner}/{repo}/releases/tags/{tag_name}'
else:
if not source is VersionSource.HEAD:
print(f"UNIMPLEMENTED(VersionSource): `{source}`,\nfalling back to `HEAD`")
@@ -62,6 +70,29 @@ def get_version_string(source: Enum, owner, repo, start_timestamp, n = 1):
# Return name of latest tag
return data.get('tag_name')
elif source is VersionSource.SPECIFIC_TAG:
assets = data.get('assets', [])
if not assets:
print(f"⚠️ No assets found in release {tag_name}")
return None
latest_created_at = ""
latest_asset = None
for asset in assets:
created_at = asset.get('created_at', '')
if created_at > latest_created_at:
latest_created_at = created_at
latest_asset = asset.name
# Convert 2099-12-31T01:02:03Z to 20991231_010203
parts = latest_created_at.replace('Z', '').split('T')
date_part = parts[0].replace('-', '') # 20991231
time_part = parts[1].replace(':', '') # 010203
version = f"{date_part}_{time_part}" # 20991231_010203
tag_data['file'] = latest_asset
return version
if data and len(data) > 0:
# Return shortened commit hash (first 7 characters)
return data[0]['sha'][:7]
@@ -98,7 +129,7 @@ def get_version_string(source: Enum, owner, repo, start_timestamp, n = 1):
print(f"Waiting {wait_time} seconds until next attempt...")
time.sleep(wait_time)
n += 1
return get_version_string(source, owner, repo, start_timestamp, n) # Retry
return get_version_string(source, owner, repo, start_timestamp, n, tag_data=tag_data) # Retry
else:
print(f"Next attempt in {wait_time} seconds, but Action run time would exceed 1800 seconds - Stopping...")
sys.exit(1)
@@ -165,7 +196,22 @@ def process_mod(start_timestamp, name, meta_file):
print("Download URL links to HEAD, checking latest commit...")
source = VersionSource.HEAD
new_version = get_version_string(VersionSource.HEAD, owner, repo, start_timestamp)
elif (("/releases/download/" in download_url and "/releases/latest/" not in download_url) or
("/releases/tag/" in download_url and "/releases/tag/latest" not in download_url)):
print("Download URL links to specific tag, checking that tag...")
source = VersionSource.SPECIFIC_TAG
tag_data = {}
if "/releases/download/" in download_url:
# Pattern: /releases/download/{tag}/{file} - tag is second-to-last
tag_data['name'] = download_url.split('/')[-2]
else:
# Pattern: /releases/tag/{tag} - tag is last
tag_data['name'] = download_url.split('/')[-1]
new_version = get_version_string(
source, owner, repo, start_timestamp, tag_data=tag_data
)
else:
print("Checking releases for latest version tag...")
source = VersionSource.RELEASE_TAG
@@ -192,6 +238,8 @@ def process_mod(start_timestamp, name, meta_file):
meta['version'] = new_version
if "/archive/refs/tags/" in download_url:
meta['downloadURL'] = f"{repo_url}/archive/refs/tags/{meta['version']}.zip"
elif source == VersionSource.SPECIFIC_TAG:
meta['download_url'] = f"{repo_url}/releases/download/{tag_data['name']}/{tag_data['file']}"
with open(meta_file, 'w', encoding='utf-8') as f:
# Preserve formatting with indentation
@@ -241,4 +289,3 @@ if __name__ == "__main__":
# Exit with status code 0 even if no updates were made
sys.exit(0)