|
@@ -1,13 +1,15 @@
|
|
import os
|
|
import os
|
|
|
|
+import re
|
|
import shutil
|
|
import shutil
|
|
import subprocess
|
|
import subprocess
|
|
import sys
|
|
import sys
|
|
import timeit
|
|
import timeit
|
|
from copy import deepcopy
|
|
from copy import deepcopy
|
|
-from typing import Literal, NotRequired, TypedDict
|
|
|
|
|
|
+from typing import Literal, NotRequired, Optional, TypedDict
|
|
|
|
|
|
import requests
|
|
import requests
|
|
import yaml
|
|
import yaml
|
|
|
|
+from semver import Version
|
|
|
|
|
|
# Get TMP_DIR variable from environment
|
|
# Get TMP_DIR variable from environment
|
|
TMP_DIR = os.path.join(os.environ.get("TMP_DIR", "/tmp"), "ohmyzsh")
|
|
TMP_DIR = os.path.join(os.environ.get("TMP_DIR", "/tmp"), "ohmyzsh")
|
|
@@ -16,6 +18,35 @@ DEPS_YAML_FILE = ".github/dependencies.yml"
|
|
# Dry run flag
|
|
# Dry run flag
|
|
DRY_RUN = os.environ.get("DRY_RUN", "0") == "1"
|
|
DRY_RUN = os.environ.get("DRY_RUN", "0") == "1"
|
|
|
|
|
|
|
|
+# utils for tag comparison
|
|
|
|
+BASEVERSION = re.compile(
|
|
|
|
+ r"""[vV]?
|
|
|
|
+ (?P<major>(0|[1-9])\d*)
|
|
|
|
+ (\.
|
|
|
|
+ (?P<minor>(0|[1-9])\d*)
|
|
|
|
+ (\.
|
|
|
|
+ (?P<patch>(0|[1-9])\d*)
|
|
|
|
+ )?
|
|
|
|
+ )?
|
|
|
|
+ """,
|
|
|
|
+ re.VERBOSE,
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def coerce(version: str) -> Optional[Version]:
|
|
|
|
+ match = BASEVERSION.search(version)
|
|
|
|
+ if not match:
|
|
|
|
+ return None
|
|
|
|
+
|
|
|
|
+ # BASEVERSION looks for `MAJOR.minor.patch` in the string given
|
|
|
|
+ # it fills with None if any of them is missing (for example `2.1`)
|
|
|
|
+ ver = {
|
|
|
|
+ key: 0 if value is None else value for key, value in match.groupdict().items()
|
|
|
|
+ }
|
|
|
|
+ # Version takes `major`, `minor`, `patch` arguments
|
|
|
|
+ ver = Version(**ver) # pyright: ignore[reportArgumentType]
|
|
|
|
+ return ver
|
|
|
|
+
|
|
|
|
|
|
class CodeTimer:
|
|
class CodeTimer:
|
|
def __init__(self, name=None):
|
|
def __init__(self, name=None):
|
|
@@ -390,6 +421,11 @@ class GitHub:
|
|
|
|
|
|
# Send a GET request to the GitHub API
|
|
# Send a GET request to the GitHub API
|
|
response = requests.get(url)
|
|
response = requests.get(url)
|
|
|
|
+ current_version = coerce(current_tag)
|
|
|
|
+ if current_version is None:
|
|
|
|
+ raise ValueError(
|
|
|
|
+ f"Stored {current_version} from {repo} does not follow semver"
|
|
|
|
+ )
|
|
|
|
|
|
# If the request was successful
|
|
# If the request was successful
|
|
if response.status_code == 200:
|
|
if response.status_code == 200:
|
|
@@ -401,10 +437,27 @@ class GitHub:
|
|
"has_updates": False,
|
|
"has_updates": False,
|
|
}
|
|
}
|
|
|
|
|
|
- latest_ref = data[-1]
|
|
|
|
|
|
+ latest_ref = None
|
|
|
|
+ latest_version: Optional[Version] = None
|
|
|
|
+ for ref in data:
|
|
|
|
+ # we find the tag since GitHub returns it as plain git ref
|
|
|
|
+ tag_version = coerce(ref["ref"].replace("refs/tags/", ""))
|
|
|
|
+ if tag_version is None:
|
|
|
|
+ # we skip every tag that is not semver-complaint
|
|
|
|
+ continue
|
|
|
|
+ if latest_version is None or tag_version.compare(latest_version) > 0:
|
|
|
|
+ # if we have a "greater" semver version, set it as latest
|
|
|
|
+ latest_version = tag_version
|
|
|
|
+ latest_ref = ref
|
|
|
|
+
|
|
|
|
+ # raise if no valid semver tag is found
|
|
|
|
+ if latest_ref is None or latest_version is None:
|
|
|
|
+ raise ValueError(f"No tags following semver found in {repo}")
|
|
|
|
+
|
|
|
|
+ # we get the tag since GitHub returns it as plain git ref
|
|
latest_tag = latest_ref["ref"].replace("refs/tags/", "")
|
|
latest_tag = latest_ref["ref"].replace("refs/tags/", "")
|
|
|
|
|
|
- if latest_tag == current_tag:
|
|
|
|
|
|
+ if latest_version.compare(current_version) <= 0:
|
|
return {
|
|
return {
|
|
"has_updates": False,
|
|
"has_updates": False,
|
|
}
|
|
}
|
|
@@ -424,9 +477,6 @@ class GitHub:
|
|
|
|
|
|
@staticmethod
|
|
@staticmethod
|
|
def check_updates(repo, branch, version) -> UpdateStatusFalse | UpdateStatusTrue:
|
|
def check_updates(repo, branch, version) -> UpdateStatusFalse | UpdateStatusTrue:
|
|
- # TODO: add support for semver updating (based on tags)
|
|
|
|
- # Check if upstream github repo has a new version
|
|
|
|
- # GitHub API URL for comparing two commits
|
|
|
|
url = f"https://api.github.com/repos/{repo}/compare/{version}...{branch}"
|
|
url = f"https://api.github.com/repos/{repo}/compare/{version}...{branch}"
|
|
|
|
|
|
# Send a GET request to the GitHub API
|
|
# Send a GET request to the GitHub API
|