Merge pull request #2023 from Salamandar/rework_autoupdater
Rework autoupdater - part 3
This commit is contained in:
commit
d31f1a2775
1 changed files with 35 additions and 24 deletions
|
@ -21,6 +21,7 @@ import github
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from rest_api import GithubAPI, GitlabAPI, GiteaForgejoAPI, RefType # noqa: E402,E501 pylint: disable=import-error,wrong-import-position
|
from rest_api import GithubAPI, GitlabAPI, GiteaForgejoAPI, RefType # noqa: E402,E501 pylint: disable=import-error,wrong-import-position
|
||||||
|
import appslib.logging_sender # noqa: E402 pylint: disable=import-error,wrong-import-position
|
||||||
from appslib.utils import REPO_APPS_ROOT, get_catalog # noqa: E402 pylint: disable=import-error,wrong-import-position
|
from appslib.utils import REPO_APPS_ROOT, get_catalog # noqa: E402 pylint: disable=import-error,wrong-import-position
|
||||||
from app_caches import app_cache_folder # noqa: E402 pylint: disable=import-error,wrong-import-position
|
from app_caches import app_cache_folder # noqa: E402 pylint: disable=import-error,wrong-import-position
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ def get_github() -> tuple[tuple[str, str] | None, github.Github | None, github.I
|
||||||
return None, None, None
|
return None, None, None
|
||||||
|
|
||||||
|
|
||||||
def apps_to_run_auto_update_for():
|
def apps_to_run_auto_update_for() -> list[str]:
|
||||||
apps_flagged_as_working_and_on_yunohost_apps_org = [
|
apps_flagged_as_working_and_on_yunohost_apps_org = [
|
||||||
app
|
app
|
||||||
for app, infos in get_catalog().items()
|
for app, infos in get_catalog().items()
|
||||||
|
@ -67,12 +68,16 @@ def apps_to_run_auto_update_for():
|
||||||
|
|
||||||
relevant_apps = []
|
relevant_apps = []
|
||||||
for app in apps_flagged_as_working_and_on_yunohost_apps_org:
|
for app in apps_flagged_as_working_and_on_yunohost_apps_org:
|
||||||
|
try:
|
||||||
manifest_toml = app_cache_folder(app) / "manifest.toml"
|
manifest_toml = app_cache_folder(app) / "manifest.toml"
|
||||||
if manifest_toml.exists():
|
if manifest_toml.exists():
|
||||||
manifest = toml.load(manifest_toml.open("r", encoding="utf-8"))
|
manifest = toml.load(manifest_toml.open("r", encoding="utf-8"))
|
||||||
sources = manifest.get("resources", {}).get("sources", {})
|
sources = manifest.get("resources", {}).get("sources", {})
|
||||||
if any("autoupdate" in source for source in sources.values()):
|
if any("autoupdate" in source for source in sources.values()):
|
||||||
relevant_apps.append(app)
|
relevant_apps.append(app)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error while loading {app}'s manifest: {e}")
|
||||||
|
raise e
|
||||||
return relevant_apps
|
return relevant_apps
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,7 +103,7 @@ class LocalOrRemoteRepo:
|
||||||
github = get_github()[1]
|
github = get_github()[1]
|
||||||
assert github, "Could not get github authentication!"
|
assert github, "Could not get github authentication!"
|
||||||
self.repo = github.get_repo(f"Yunohost-Apps/{app}_ynh")
|
self.repo = github.get_repo(f"Yunohost-Apps/{app}_ynh")
|
||||||
self.pr_branch = None
|
self.pr_branch: str | None = None
|
||||||
# Determine base branch, either `testing` or default branch
|
# Determine base branch, either `testing` or default branch
|
||||||
try:
|
try:
|
||||||
self.base_branch = self.repo.get_branch("testing").name
|
self.base_branch = self.repo.get_branch("testing").name
|
||||||
|
@ -145,15 +150,14 @@ class LocalOrRemoteRepo:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def create_pr(self, branch: str, title: str, message: str) -> str | None:
|
def create_pr(self, branch: str, title: str, message: str) -> str | None:
|
||||||
if self.local:
|
|
||||||
logging.warning("Can't create pull requests for local repositories")
|
|
||||||
return
|
|
||||||
if self.remote:
|
if self.remote:
|
||||||
# Open the PR
|
# Open the PR
|
||||||
pr = self.repo.create_pull(
|
pr = self.repo.create_pull(
|
||||||
title=title, body=message, head=branch, base=self.base_branch
|
title=title, body=message, head=branch, base=self.base_branch
|
||||||
)
|
)
|
||||||
return pr.url
|
return pr.url
|
||||||
|
logging.warning("Can't create pull requests for local repositories")
|
||||||
|
return None
|
||||||
|
|
||||||
def get_pr(self, branch: str) -> str:
|
def get_pr(self, branch: str) -> str:
|
||||||
return next(pull.html_url for pull in self.repo.get_pulls(head=branch))
|
return next(pull.html_url for pull in self.repo.get_pulls(head=branch))
|
||||||
|
@ -174,7 +178,8 @@ class AppAutoUpdater:
|
||||||
|
|
||||||
self.main_upstream = self.manifest.get("upstream", {}).get("code")
|
self.main_upstream = self.manifest.get("upstream", {}).get("code")
|
||||||
|
|
||||||
def run(self, edit: bool = False, commit: bool = False, pr: bool = False) -> bool | tuple[str | None, str | None, str | None]:
|
def run(self, edit: bool = False, commit: bool = False, pr: bool = False
|
||||||
|
) -> bool | tuple[str | None, str | None, str | None]:
|
||||||
has_updates = False
|
has_updates = False
|
||||||
main_version = None
|
main_version = None
|
||||||
pr_url = None
|
pr_url = None
|
||||||
|
@ -315,10 +320,10 @@ class AppAutoUpdater:
|
||||||
|
|
||||||
if isinstance(assets, str) and infos["url"] == assets:
|
if isinstance(assets, str) and infos["url"] == assets:
|
||||||
print(f"URL for asset {name} is up to date")
|
print(f"URL for asset {name} is up to date")
|
||||||
return
|
return None
|
||||||
if isinstance(assets, dict) and assets == {k: infos[k]["url"] for k in assets.keys()}:
|
if isinstance(assets, dict) and assets == {k: infos[k]["url"] for k in assets.keys()}:
|
||||||
print(f"URLs for asset {name} are up to date")
|
print(f"URLs for asset {name} are up to date")
|
||||||
return
|
return None
|
||||||
print(f"Update needed for {name}")
|
print(f"Update needed for {name}")
|
||||||
return new_version, assets, more_info
|
return new_version, assets, more_info
|
||||||
|
|
||||||
|
@ -338,6 +343,7 @@ class AppAutoUpdater:
|
||||||
upstream = (infos.get("autoupdate", {}).get("upstream", self.main_upstream).strip("/"))
|
upstream = (infos.get("autoupdate", {}).get("upstream", self.main_upstream).strip("/"))
|
||||||
_, remote_type, revision_type = strategy.split("_")
|
_, remote_type, revision_type = strategy.split("_")
|
||||||
|
|
||||||
|
api: GithubAPI | GitlabAPI | GiteaForgejoAPI
|
||||||
if remote_type == "github":
|
if remote_type == "github":
|
||||||
assert (
|
assert (
|
||||||
upstream and upstream.startswith("https://github.com/")
|
upstream and upstream.startswith("https://github.com/")
|
||||||
|
@ -408,6 +414,7 @@ class AppAutoUpdater:
|
||||||
version_format = infos.get("autoupdate", {}).get("force_version", "%Y.%m.%d")
|
version_format = infos.get("autoupdate", {}).get("force_version", "%Y.%m.%d")
|
||||||
latest_version = latest_commit_date.strftime(version_format)
|
latest_version = latest_commit_date.strftime(version_format)
|
||||||
return latest_version, latest_tarball, ""
|
return latest_version, latest_tarball, ""
|
||||||
|
return None
|
||||||
|
|
||||||
def replace_version_and_asset_in_manifest(self, content: str, new_version: str, new_assets_urls: str | dict,
|
def replace_version_and_asset_in_manifest(self, content: str, new_version: str, new_assets_urls: str | dict,
|
||||||
current_assets: dict, is_main: bool):
|
current_assets: dict, is_main: bool):
|
||||||
|
@ -457,15 +464,15 @@ def paste_on_haste(data):
|
||||||
class StdoutSwitch:
|
class StdoutSwitch:
|
||||||
|
|
||||||
class DummyFile:
|
class DummyFile:
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.result = ""
|
self.result = ""
|
||||||
|
|
||||||
def write(self, x):
|
def write(self, x: str) -> None:
|
||||||
self.result += x
|
self.result += x
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.save_stdout = sys.stdout
|
self.save_stdout = sys.stdout
|
||||||
sys.stdout = self.DummyFile()
|
sys.stdout = self.DummyFile() # type: ignore
|
||||||
|
|
||||||
def reset(self) -> str:
|
def reset(self) -> str:
|
||||||
result = ""
|
result = ""
|
||||||
|
@ -483,13 +490,14 @@ def run_autoupdate_for_multiprocessing(data) -> tuple[bool, str, Any] | None:
|
||||||
stdoutswitch = StdoutSwitch()
|
stdoutswitch = StdoutSwitch()
|
||||||
try:
|
try:
|
||||||
result = AppAutoUpdater(app).run(edit=edit, commit=commit, pr=pr)
|
result = AppAutoUpdater(app).run(edit=edit, commit=commit, pr=pr)
|
||||||
if result is not False:
|
if result is False:
|
||||||
|
return None
|
||||||
return True, app, result
|
return True, app, result
|
||||||
except Exception:
|
except Exception:
|
||||||
result = stdoutswitch.reset()
|
log_str = stdoutswitch.reset()
|
||||||
import traceback
|
import traceback
|
||||||
t = traceback.format_exc()
|
t = traceback.format_exc()
|
||||||
return False, app, f"{result}\n{t}"
|
return False, app, f"{log_str}\n{t}"
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
@ -503,10 +511,14 @@ def main() -> None:
|
||||||
parser.add_argument("-j", "--processes", type=int, default=multiprocessing.cpu_count())
|
parser.add_argument("-j", "--processes", type=int, default=multiprocessing.cpu_count())
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
appslib.logging_sender.enable()
|
||||||
|
|
||||||
if args.commit and not args.edit:
|
if args.commit and not args.edit:
|
||||||
parser.error("--commit requires --edit")
|
logging.error("--commit requires --edit")
|
||||||
|
sys.exit(1)
|
||||||
if args.pr and not args.commit:
|
if args.pr and not args.commit:
|
||||||
parser.error("--pr requires --commit")
|
logging.error("--pr requires --commit")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# Handle apps or no apps
|
# Handle apps or no apps
|
||||||
apps = list(args.apps) if args.apps else apps_to_run_auto_update_for()
|
apps = list(args.apps) if args.apps else apps_to_run_auto_update_for()
|
||||||
|
@ -532,7 +544,6 @@ def main() -> None:
|
||||||
for app, info in apps_updated.items():
|
for app, info in apps_updated.items():
|
||||||
result_message += f"\n- {app}"
|
result_message += f"\n- {app}"
|
||||||
if isinstance(info, tuple):
|
if isinstance(info, tuple):
|
||||||
print(info)
|
|
||||||
result_message += f" ({info[0]} -> {info[1]})"
|
result_message += f" ({info[0]} -> {info[1]})"
|
||||||
if info[2] is not None:
|
if info[2] is not None:
|
||||||
result_message += f" see {info[2]}"
|
result_message += f" see {info[2]}"
|
||||||
|
|
Loading…
Reference in a new issue