git_deploy: add support for stable updates

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Eric Callahan 2023-07-05 08:02:38 -04:00
parent 1a4480e74c
commit 3e875b583c
No known key found for this signature in database
GPG Key ID: 5A1EB336DFB4C71B
1 changed files with 78 additions and 65 deletions

View File

@ -19,7 +19,6 @@ from ...utils.versions import GitVersion
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any, Any,
Tuple,
Optional, Optional,
Dict, Dict,
List, List,
@ -402,20 +401,16 @@ class GitRepo:
self.current_commit = await self.rev_parse("HEAD") self.current_commit = await self.rev_parse("HEAD")
git_desc = await self.describe("--always --tags --long --dirty --abbrev=8") git_desc = await self.describe("--always --tags --long --dirty --abbrev=8")
cur_ver = GitVersion(git_desc.strip()) cur_ver = GitVersion(git_desc.strip())
if self.channel != Channel.DEV: upstream_ver = await self._get_upstream_version()
await self._get_beta_versions(cur_ver) await self._set_versions(cur_ver, upstream_ver)
else:
await self._get_dev_versions(cur_ver)
# Get Commits Behind # Get Commits Behind
self.commits_behind = [] self.commits_behind = []
cbh = await self.get_commits_behind() cbh = await self.get_commits_behind()
if cbh: if cbh:
tagged_commits = await self.get_tagged_commits() tagged_commits = await self.get_tagged_commits()
debug_msg = '\n'.join([f"{k}: {v}" for k, v in debug_msg = '\n'.join([f"{k}: {v}" for k, v in tagged_commits.items()])
tagged_commits.items()]) logging.debug(f"Git Repo {self.alias}: Tagged Commits\n{debug_msg}")
logging.debug(f"Git Repo {self.alias}: Tagged Commits\n"
f"{debug_msg}")
for i, commit in enumerate(cbh): for i, commit in enumerate(cbh):
tag = tagged_commits.get(commit['sha'], None) tag = tagged_commits.get(commit['sha'], None)
if i < 30 or tag is not None: if i < 30 or tag is not None:
@ -486,52 +481,74 @@ class GitRepo:
logging.debug(f"Move Request Failed: {resp.error}") logging.debug(f"Move Request Failed: {resp.error}")
return moved return moved
async def _get_dev_versions(self, current_version: GitVersion) -> None: async def _get_upstream_version(self) -> GitVersion:
self.upstream_commit = await self.rev_parse( if self.channel == Channel.DEV:
f"{self.git_remote}/{self.git_branch}" self.upstream_commit = await self.rev_parse(
) f"{self.git_remote}/{self.git_branch}"
upstream_ver_str = await self.describe( )
f"{self.git_remote}/{self.git_branch} --always --tags --long --abbrev=8" upstream_ver_str = await self.describe(
) f"{self.git_remote}/{self.git_branch} --always --tags --long --abbrev=8"
upstream_version = GitVersion(upstream_ver_str) )
# Get the latest tag as a fallback for shallow clones else:
commit, tag = await self._parse_latest_tag() tagged_commits = await self.get_tagged_commits()
# Check for shallow clones upstream_commit = upstream_ver_str = "?"
if current_version.is_fallback() and tag != "?": for sha, tag in tagged_commits.items():
count = await self.rev_list(f"{tag}..HEAD --count") ver = GitVersion(tag)
current_version = GitVersion(f"{tag}-{count}-g{current_version}-shallow") if not ver.is_valid_version():
if not upstream_version.is_valid_version() and tag != "?": continue
count = await self.rev_list(f"{tag}..{self.upstream_commit} --count") if (
upstream_version = GitVersion(f"{tag}-{count}") (self.channel == Channel.STABLE and ver.is_final_release()) or
(self.channel == Channel.BETA and not ver.is_alpha_release())
):
upstream_commit = sha
upstream_ver_str = tag
break
self.upstream_commit = upstream_commit
return GitVersion(upstream_ver_str)
async def _set_versions(
self, current_version: GitVersion, upstream_version: GitVersion
) -> None:
if not current_version.is_valid_version():
log_msg = (
f"Git repo {self.alias}: Failed to detect current version, got "
f"'{current_version}'. "
)
tag = upstream_version.infer_last_tag()
count = await self.rev_list("HEAD --count")
sha_part = ""
if current_version.is_fallback():
sha_part = f"-g{current_version}"
elif self.current_commit not in ("?", ""):
sha_part = f"-g{self.current_commit[:8]}"
current_version = GitVersion(f"{tag}-{count}{sha_part}-inferred")
log_msg += f"Falling back to inferred version: {current_version}"
logging.info(log_msg)
if self.channel == Channel.DEV:
if not upstream_version.is_valid_version():
log_msg = (
f"Git repo {self.alias}: Failed to detect upstream version, got "
f"'{upstream_version}'. "
)
tag = current_version.tag
if current_version.inferred:
count = await self.rev_list(f"{self.upstream_commit} --count")
else:
log_msg += "\nRemote has diverged, approximating dev count. "
count = await self.rev_list(f"{self.upstream_commit}..HEAD --count")
count = str(int(count) + current_version.dev_count)
upstream_version = GitVersion(f"{tag}-{count}-inferred")
log_msg += f"Falling back to inferred version: {upstream_version}"
logging.info(log_msg)
else:
if not upstream_version.is_valid_version():
self.upstream_commit = self.current_commit
upstream_version = current_version
elif upstream_version <= current_version:
self.upstream_commit = self.current_commit
self.current_version = current_version self.current_version = current_version
self.upstream_version = upstream_version self.upstream_version = upstream_version
async def _get_beta_versions(self, current_version: GitVersion) -> None:
upstream_commit, upstream_tag = await self._parse_latest_tag()
if current_version.is_fallback() and upstream_tag != "?":
count = await self.rev_list(f"{upstream_tag}..HEAD --count")
ver_string = f"{upstream_tag}-{count}-g{current_version}-shallow"
current_version = GitVersion(ver_string)
self.upstream_commit = upstream_commit
if self.current_version.tag == upstream_tag or upstream_tag == "?":
self.upstream_commit = self.current_commit
self.current_version = current_version
self.upstream_version = GitVersion(upstream_tag)
async def _parse_latest_tag(self) -> Tuple[str, str]:
commit = tag = "?"
try:
commit = await self.rev_list("--tags --max-count=1")
if not commit:
return "?", "?"
tag = await self.describe(f"--tags {commit}")
except asyncio.CancelledError:
raise
except Exception:
return "?", "?"
version = GitVersion(tag)
return commit, version.tag
async def wait_for_init(self) -> None: async def wait_for_init(self) -> None:
if self.init_evt is not None: if self.init_evt is not None:
await self.init_evt.wait() await self.init_evt.wait()
@ -591,18 +608,13 @@ class GitRepo:
async def check_diverged(self) -> bool: async def check_diverged(self) -> bool:
self._verify_repo(check_remote=True) self._verify_repo(check_remote=True)
if self.head_detached:
return False
async with self.git_operation_lock: async with self.git_operation_lock:
if self.head_detached: cmd = f"merge-base --is-ancestor HEAD {self.git_remote}/{self.git_branch}"
return False
cmd = (
"merge-base --is-ancestor HEAD "
f"{self.git_remote}/{self.git_branch}"
)
for _ in range(3): for _ in range(3):
try: try:
await self._run_git_cmd( await self._run_git_cmd(cmd, retries=1, corrupt_msg="error: ")
cmd, retries=1, corrupt_msg="error: "
)
except self.cmd_helper.scmd_error as err: except self.cmd_helper.scmd_error as err:
if err.return_code == 1: if err.return_code == 1:
return True return True
@ -847,13 +859,14 @@ class GitRepo:
commits_behind.append(dict(cbh)) # type: ignore commits_behind.append(dict(cbh)) # type: ignore
return commits_behind return commits_behind
async def get_tagged_commits(self) -> Dict[str, Any]: async def get_tagged_commits(self, count: int = 100) -> Dict[str, str]:
self._verify_repo() self._verify_repo()
async with self.git_operation_lock: async with self.git_operation_lock:
resp = await self._run_git_cmd( resp = await self._run_git_cmd(
"for-each-ref --count=10 --sort='-creatordate' " f"for-each-ref --count={count} --sort='-creatordate' "
f"--format={GIT_REF_FMT} 'refs/tags'") f"--contains=HEAD --format={GIT_REF_FMT} 'refs/tags'"
tagged_commits: Dict[str, Any] = {} )
tagged_commits: Dict[str, str] = {}
for line in resp.split('\n'): for line in resp.split('\n'):
parts = line.strip().split() parts = line.strip().split()
if len(parts) != 3 or parts[0] != "commit": if len(parts) != 3 or parts[0] != "commit":