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:
53
.github/scripts/update_mod_versions.py
vendored
53
.github/scripts/update_mod_versions.py
vendored
@@ -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)
|
||||
|
||||
|
||||
@@ -52,8 +52,11 @@ This file stores essential metadata in JSON format. **Make sure you adhere to th
|
||||
- **version**: The version number of the mod files available at `downloadURL`.
|
||||
- *folderName*: (*Optional*) The name for the mod's install folder. This must be **unique**, and cannot contain characters `<` `>` `:` `"` `/` `\` `|` `?` `*`
|
||||
- *automatic-version-check*: (*Optional* but **recommended**) Set to `true` to let the Index automatically update the `version` field.
|
||||
- Updates happen once every hour, by checking either your mod's latest Release **or** latest commit, depending on the `downloadURL`.
|
||||
- Enable this option **only** if your `downloadURL` points to an automatically updating source, using a link to [releases/latest](https://docs.github.com/en/repositories/releasing-projects-on-github/linking-to-releases) (recommended), or a link to the [latest commit (HEAD)](https://docs.github.com/en/repositories/working-with-files/using-files/downloading-source-code-archives#source-code-archive-urls).
|
||||
- Updates happen once every hour, by checking either your mod's latest Release, latest commit, or specific release tag, depending on the `downloadURL`.
|
||||
- Enable this option **only** if your `downloadURL` points to an automatically updating source:
|
||||
- **Latest release** (recommended): Using a link to [releases/latest](https://docs.github.com/en/repositories/releasing-projects-on-github/linking-to-releases)
|
||||
- **Latest commit**: Using a link to the [latest commit (HEAD)](https://docs.github.com/en/repositories/working-with-files/using-files/downloading-source-code-archives#source-code-archive-urls)
|
||||
- **Permanent release tag**: Using a link to a specific release tag where you upload new files: `https://github.com/author/repo/releases/tag/my-release-tag`. **(This will always use the latest uploaded file)**.
|
||||
|
||||
### 3. thumbnail.jpg (Optional)
|
||||
If included, this image will appear alongside your mod in the index. Maximum and recommended size is 1920x1080 pixels.
|
||||
|
||||
Reference in New Issue
Block a user