mirror of
https://github.com/SeedSigner/seedsigner.git
synced 2026-09-14 04:45:08 +00:00
Simplify SeedSigner OS builder path
This commit is contained in:
+149
-130
@@ -40,52 +40,70 @@ class Version(Singleton):
|
||||
around in the main code) and so that the version data is only determined once per
|
||||
runtime.
|
||||
|
||||
On SeedSigner OS:
|
||||
* Version data is written to `src/seedsigner/version.json` during the build
|
||||
process via tools/write_versionfile.py.
|
||||
* version_name: copied from the command used to build the SeedSigner OS image:
|
||||
--app-branch (the target git branch OR tag) or
|
||||
--app-commit-id (target commit hash)
|
||||
* version_fork: the git repo owner/fork name (e.g. "SeedSigner") targeted by the
|
||||
build process.
|
||||
* version_timestamp: the last git commit time for the target branch, tag, or
|
||||
commit hash.
|
||||
* commit_hash: the short commit hash for the specified build target.
|
||||
SeedSigner OS lifecycle:
|
||||
* The SeedSigner OS build process runs the tools/write_versionfile.py script to
|
||||
generate version.json.
|
||||
* The version.json file is included in the SeedSigner OS image.
|
||||
|
||||
The version data is fetched differently depending on the environment:
|
||||
|
||||
In SeedSigner OS:
|
||||
* Version data is read exclusively from version.json at runtime.
|
||||
|
||||
In the SeedSigner OS builder:
|
||||
- Note: the build process relies on `git` being installed so we leverage it here.
|
||||
* version_name:
|
||||
* read dynamically from `git` shell calls to retrieve, in order:
|
||||
* Current git branch name
|
||||
* Current git tag name
|
||||
* Current git short commit hash
|
||||
* version_fork:
|
||||
* the git repo owner parsed out of the remote url.
|
||||
* https://github.com/SeedSigner/seedsigner.git -> "SeedSigner"
|
||||
* Read dynamically from shell `git` call to check the remote "origin" URL.
|
||||
* short_commit_hash:
|
||||
* the commit hash for the current branch / tag / detached HEAD.
|
||||
* Read dynamically from shell `git` call.
|
||||
* version_timestamp:
|
||||
* the last git commit time for the current branch / tag / detached HEAD.
|
||||
* Read dynamically from shell `git` call.
|
||||
|
||||
In local dev:
|
||||
* version_name: read dynamically from a few possible sources. In order:
|
||||
* SEEDSIGNER_VERSION_NAME env var, if available.
|
||||
* Shell `git` calls (e.g. `git branch --show-current`).
|
||||
* Directly parsing the .git/HEAD file and possibly .git/refs/tags.
|
||||
* Note: we avoid reading from the version.json file as it may be out of date
|
||||
and could lead to confusion.
|
||||
* version_fork: read dynamically from:
|
||||
* Shell `git` call to check the remote "origin" URL.
|
||||
* Parse the .git/config for the remote "origin" URL.
|
||||
- Similar process as for the SeedSigner OS builder, but with additional fallbacks and
|
||||
a different method for determining version_timestamp.
|
||||
- If a local version.json is present, it will be ignored; it may be out of date and
|
||||
could lead to confusion.
|
||||
* version_name:
|
||||
* `git` shell calls + directly parsing the .git/HEAD file and .git/refs/tags
|
||||
when necessary.
|
||||
* version_fork:
|
||||
* `git` shell call + parse the .git/config for the remote "origin" URL.
|
||||
* commit_hash:
|
||||
* Shell `git` call + parse the .git/HEAD file and
|
||||
.git/refs/heads/<branch_name> when necessary.
|
||||
* version_timestamp: determined by scanning the src/ directory for the most
|
||||
recently modified python file.
|
||||
* commit_hash: read dynamically from:
|
||||
* Shell `git` call.
|
||||
* Parse the .git/HEAD file and possibly .git/refs/heads/<branch_name>.
|
||||
|
||||
In Github Actions CI:
|
||||
* version_name: read from GITHUB_REF_NAME or GITHUB_SHA env vars.
|
||||
* version_fork: TODO
|
||||
* version_timestamp: TODO
|
||||
* commit_hash: TODO
|
||||
* version_name: read from GITHUB_REF_NAME env var.
|
||||
* version_fork: read from GITHUB_REPOSITORY_OWNER env var.
|
||||
* version_timestamp: Shell `git` call to get the last commit time for the current
|
||||
branch/tag/commit.
|
||||
* commit_hash: read from GITHUB_SHA env var.
|
||||
|
||||
This class defines the limited methods that are meant to be publicly accessible
|
||||
across the SeedSigner codebase.
|
||||
|
||||
The misc utility functions in `VersionUtils` were explicitly isolated because they
|
||||
should NOT be used elsewhere in the codebase.
|
||||
The utility functions in `VersionUtils` were explicitly isolated because they should
|
||||
NOT be used elsewhere in the codebase.
|
||||
TODO: Should `VersionUtils` be an internal class within `Version` to further signal
|
||||
that it is not to be used externally?
|
||||
TODO: Also pull git log history and display it in its own View?
|
||||
"""
|
||||
_version_name: str = None
|
||||
_version_fork: str = None
|
||||
_version_timestamp: datetime = None
|
||||
_short_commit_hash: str = None
|
||||
_version_timestamp: datetime = None
|
||||
|
||||
|
||||
@classmethod
|
||||
@@ -114,27 +132,31 @@ class Version(Singleton):
|
||||
return cls.get_instance()._version_fork
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_version_timestamp(cls) -> datetime | None:
|
||||
return cls.get_instance()._version_timestamp
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_short_commit_hash(cls) -> str | None:
|
||||
return cls.get_instance()._short_commit_hash
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_version_timestamp(cls) -> datetime | None:
|
||||
return cls.get_instance()._version_timestamp
|
||||
|
||||
|
||||
@classmethod
|
||||
@not_allowed_in_seedsigner_os
|
||||
def override_data(cls, version_name, version_fork, version_timestamp, short_commit_hash):
|
||||
def override_data(cls, **kwargs):
|
||||
"""
|
||||
Only used by the screenshot generator.
|
||||
"""
|
||||
instance = cls.get_instance()
|
||||
instance._version_name = version_name
|
||||
instance._version_fork = version_fork
|
||||
instance._version_timestamp = version_timestamp
|
||||
instance._short_commit_hash = short_commit_hash
|
||||
if VersionUtils.VERSIONFILE_ATTR__NAME in kwargs:
|
||||
instance._version_name = kwargs[VersionUtils.VERSIONFILE_ATTR__NAME]
|
||||
if VersionUtils.VERSIONFILE_ATTR__FORK in kwargs:
|
||||
instance._version_fork = kwargs[VersionUtils.VERSIONFILE_ATTR__FORK]
|
||||
if VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH in kwargs:
|
||||
instance._short_commit_hash = kwargs[VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH]
|
||||
if VersionUtils.VERSIONFILE_ATTR__TIMESTAMP in kwargs:
|
||||
instance._version_timestamp = kwargs[VersionUtils.VERSIONFILE_ATTR__TIMESTAMP]
|
||||
|
||||
|
||||
@classmethod
|
||||
@@ -143,11 +165,12 @@ class Version(Singleton):
|
||||
return {
|
||||
VersionUtils.VERSIONFILE_ATTR__NAME: instance._version_name,
|
||||
VersionUtils.VERSIONFILE_ATTR__FORK: instance._version_fork,
|
||||
VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH: instance._short_commit_hash,
|
||||
VersionUtils.VERSIONFILE_ATTR__TIMESTAMP: instance._version_timestamp.isoformat() if instance._version_timestamp else None,
|
||||
VersionUtils.VERSIONFILE_ATTR__COMMIT_HASH: instance._short_commit_hash,
|
||||
}
|
||||
|
||||
|
||||
|
||||
class VersionUtils:
|
||||
""" *********************************************************************************
|
||||
Not meant to be used elsewhere in the SeedSigner codebase (aside from
|
||||
@@ -168,7 +191,7 @@ class VersionUtils:
|
||||
* One external http GET to github to get the most recent release tag.
|
||||
********************************************************************************* """
|
||||
|
||||
ENV_VAR__SEEDSIGNER_OS_BUILDER__VERSION_NAME = "SEEDSIGNER_VERSION_NAME"
|
||||
ENV_VAR__IS_SEEDSIGNER_OS_BUILDER = "SEEDSIGNER_OS_BUILDER"
|
||||
ENV_VAR__GITHUB_ACTIONS__IS_CI = "CI"
|
||||
ENV_VAR__GITHUB_ACTIONS__REF_NAME = "GITHUB_REF_NAME"
|
||||
ENV_VAR__GITHUB_ACTIONS__SHA = "GITHUB_SHA"
|
||||
@@ -177,8 +200,8 @@ class VersionUtils:
|
||||
VERSIONFILE__FILENAME = "version.json"
|
||||
VERSIONFILE_ATTR__NAME = "name"
|
||||
VERSIONFILE_ATTR__FORK = "fork"
|
||||
VERSIONFILE_ATTR__SHORT_COMMIT_HASH = "short_commit_hash"
|
||||
VERSIONFILE_ATTR__TIMESTAMP = "timestamp"
|
||||
VERSIONFILE_ATTR__COMMIT_HASH = "commit_hash"
|
||||
|
||||
|
||||
""" *************************************************************************************
|
||||
@@ -211,18 +234,10 @@ class VersionUtils:
|
||||
else:
|
||||
raise Exception("Could not determine version from Github Actions env vars.")
|
||||
|
||||
elif VersionUtils._is_seedsigner_os_builder_env():
|
||||
# In the SeedSigner OS build environment, get the version name from env var.
|
||||
# Note: This get_version_name call will never fail because the env var that
|
||||
# provides the version name is what defines whether we're in the SeedSigner OS
|
||||
# builder in the first place.
|
||||
version_name = VersionUtils._get_version_name_from_seedsigner_os_builder_env_var()
|
||||
return VersionUtils._prefix_version_name(version_name)
|
||||
|
||||
else:
|
||||
# In local dev, we try the following methods in order:
|
||||
# In the SeedSigner OS builder we know that we'll have the `git` shell
|
||||
# commands available. We add extra fallbacks for local dev.
|
||||
for get_version_name_method in [
|
||||
VersionUtils._get_version_name_from_seedsigner_os_builder_env_var,
|
||||
VersionUtils._get_version_name_from_git_shell,
|
||||
VersionUtils._get_version_name_from_git_HEAD,
|
||||
]:
|
||||
@@ -252,12 +267,9 @@ class VersionUtils:
|
||||
# In Github Actions CI, try to get the version name from env vars
|
||||
return VersionUtils._get_version_fork_from_github_actions_env_vars()
|
||||
|
||||
elif VersionUtils._is_seedsigner_os_builder_env():
|
||||
# In the SeedSigner OS build environment `git` shell call should be available
|
||||
return VersionUtils._get_version_fork_from_git_shell()
|
||||
|
||||
else:
|
||||
# In local dev we try to access the current git state via:
|
||||
# In the SeedSigner OS builder we know that we'll have the `git` shell
|
||||
# commands available. We add extra fallbacks for local dev.
|
||||
for get_version_fork_method in [
|
||||
VersionUtils._get_version_fork_from_git_shell,
|
||||
VersionUtils._get_version_fork_from_git_config,
|
||||
@@ -268,6 +280,45 @@ class VersionUtils:
|
||||
return None
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_short_commit_hash(cls) -> str | None:
|
||||
"""
|
||||
Returns the short commit hash string.
|
||||
|
||||
Will be None if the local dev system has no git state available or if it only has
|
||||
the .git/HEAD but is currently on a branch (not a tag or specific commit).
|
||||
"""
|
||||
if Settings.HOSTNAME == Settings.SEEDSIGNER_OS:
|
||||
return VersionUtils._get_short_commit_hash_from_version_file()
|
||||
|
||||
full_commit_hash = None
|
||||
if VersionUtils.is_github_actions_ci():
|
||||
# In Github Actions CI the "SHA" env var should always be available
|
||||
full_commit_hash = VersionUtils._get_full_commit_hash_from_github_actions_env_vars()
|
||||
|
||||
else:
|
||||
# In the SeedSigner OS builder we know that we'll have the `git` shell
|
||||
# commands available. We add extra fallbacks for local dev.
|
||||
for get_full_commit_hash_method in [
|
||||
VersionUtils._get_full_commit_hash_from_git_shell,
|
||||
VersionUtils._get_full_commit_hash_from_git_HEAD,
|
||||
]:
|
||||
full_commit_hash = get_full_commit_hash_method()
|
||||
if full_commit_hash is not None:
|
||||
break
|
||||
|
||||
if full_commit_hash is None:
|
||||
# `git` shell calls didn't work and HEAD might be on a branch, so dig
|
||||
# deeper into the .git files to look up the commit hash via the branch
|
||||
# name.
|
||||
branch_name, expect_full_commit_hash_to_be_none = VersionUtils._read_git_HEAD_file()
|
||||
if branch_name:
|
||||
full_commit_hash = VersionUtils._get_full_commit_hash_from_git_refs_heads(branch_name)
|
||||
|
||||
if full_commit_hash is not None:
|
||||
return full_commit_hash[:7]
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_version_timestamp(cls) -> datetime:
|
||||
"""
|
||||
@@ -290,7 +341,10 @@ class VersionUtils:
|
||||
return VersionUtils._get_version_timestamp_from_git_shell()
|
||||
|
||||
elif VersionUtils._is_seedsigner_os_builder_env():
|
||||
# In the SeedSigner OS build environment `git` shell call should be available
|
||||
# In the SeedSigner OS builder we know that we'll have the `git` shell
|
||||
# commands available.
|
||||
# Note: This is the only piece of version data that behaves differently
|
||||
# between the SeedSigner OS builder and local dev.
|
||||
return VersionUtils._get_version_timestamp_from_git_shell()
|
||||
|
||||
else:
|
||||
@@ -299,48 +353,10 @@ class VersionUtils:
|
||||
return VersionUtils._get_last_modified_timestamp_from_src_files()
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_short_commit_hash(cls) -> str | None:
|
||||
"""
|
||||
Returns the short commit hash string.
|
||||
|
||||
Will be None if the local dev system has no git state available or if it only has
|
||||
the .git/HEAD but is currently on a branch (not a tag or specific commit).
|
||||
"""
|
||||
if Settings.HOSTNAME == Settings.SEEDSIGNER_OS:
|
||||
return VersionUtils._get_short_commit_hash_from_version_file()
|
||||
|
||||
full_commit_hash = None
|
||||
if VersionUtils.is_github_actions_ci():
|
||||
# In Github Actions CI the "SHA" env var should always be available
|
||||
full_commit_hash = VersionUtils._get_full_commit_hash_from_github_actions_env_vars()
|
||||
|
||||
elif VersionUtils._is_seedsigner_os_builder_env():
|
||||
# In the SeedSigner OS build environment `git` shell call should be available
|
||||
full_commit_hash = VersionUtils._get_full_commit_hash_from_git_shell()
|
||||
|
||||
else:
|
||||
# In local dev we try to access the current git state via:
|
||||
for get_full_commit_hash_method in [
|
||||
VersionUtils._get_full_commit_hash_from_git_shell,
|
||||
VersionUtils._get_full_commit_hash_from_git_HEAD,
|
||||
]:
|
||||
full_commit_hash = get_full_commit_hash_method()
|
||||
if full_commit_hash is not None:
|
||||
break
|
||||
|
||||
if full_commit_hash is None:
|
||||
# `git` shell calls didn't work and HEAD might be on a branch, so dig
|
||||
# deeper into the .git files to look up the commit hash via the branch
|
||||
# name.
|
||||
branch_name, expect_full_commit_hash_to_be_none = VersionUtils._read_git_HEAD_file()
|
||||
if branch_name:
|
||||
full_commit_hash = VersionUtils._get_full_commit_hash_from_git_refs_heads(branch_name)
|
||||
|
||||
if full_commit_hash is not None:
|
||||
return full_commit_hash[:7]
|
||||
|
||||
|
||||
""" *************************************************************************************
|
||||
Misc internal utility functions.
|
||||
************************************************************************************* """
|
||||
@classmethod
|
||||
def _prefix_version_name(cls, version_name: str) -> str:
|
||||
"""
|
||||
@@ -353,6 +369,7 @@ class VersionUtils:
|
||||
return version_name
|
||||
|
||||
|
||||
|
||||
""" *************************************************************************************
|
||||
Reading data from the version.json file.
|
||||
************************************************************************************* """
|
||||
@@ -398,6 +415,16 @@ class VersionUtils:
|
||||
return version_data.get(cls.VERSIONFILE_ATTR__FORK)
|
||||
|
||||
|
||||
@classmethod
|
||||
def _get_short_commit_hash_from_version_file(cls) -> str | None:
|
||||
"""
|
||||
Attempts to read the version.json and return the version commit hash.
|
||||
"""
|
||||
version_data = cls._read_version_file()
|
||||
if version_data:
|
||||
return version_data.get(cls.VERSIONFILE_ATTR__SHORT_COMMIT_HASH)
|
||||
|
||||
|
||||
@classmethod
|
||||
def _get_version_timestamp_from_version_file(cls) -> str | None:
|
||||
"""
|
||||
@@ -408,16 +435,6 @@ class VersionUtils:
|
||||
return version_data.get(cls.VERSIONFILE_ATTR__TIMESTAMP)
|
||||
|
||||
|
||||
@classmethod
|
||||
def _get_short_commit_hash_from_version_file(cls) -> str | None:
|
||||
"""
|
||||
Attempts to read the version.json and return the version commit hash.
|
||||
"""
|
||||
version_data = cls._read_version_file()
|
||||
if version_data:
|
||||
return version_data.get(cls.VERSIONFILE_ATTR__COMMIT_HASH)
|
||||
|
||||
|
||||
|
||||
""" *************************************************************************************
|
||||
Utilities used in the SeedSigner OS build environment and writing the version.json file.
|
||||
@@ -425,20 +442,10 @@ class VersionUtils:
|
||||
@classmethod
|
||||
def _is_seedsigner_os_builder_env(cls) -> bool:
|
||||
"""
|
||||
Simple check to see if we're running in the SeedSigner OS build environment.
|
||||
The `ENV_VAR__IS_SEEDSIGNER_OS_BUILDER` env var is set during the SeedSigner OS
|
||||
build process.
|
||||
"""
|
||||
return os.getenv(cls.ENV_VAR__SEEDSIGNER_OS_BUILDER__VERSION_NAME) is not None
|
||||
|
||||
|
||||
@classmethod
|
||||
def _get_version_name_from_seedsigner_os_builder_env_var(cls) -> str | None:
|
||||
"""
|
||||
Primarily used during the SeedSigner OS build process to set the version name via env var.
|
||||
|
||||
This env var can also be set manually in local dev when needed.
|
||||
e.g. SEEDSIGNER_VERSION_NAME=some_name python main.py
|
||||
"""
|
||||
return os.getenv(cls.ENV_VAR__SEEDSIGNER_OS_BUILDER__VERSION_NAME)
|
||||
return os.getenv(cls.ENV_VAR__IS_SEEDSIGNER_OS_BUILDER) is not None
|
||||
|
||||
|
||||
|
||||
@@ -478,14 +485,14 @@ class VersionUtils:
|
||||
************************************************************************************* """
|
||||
@classmethod
|
||||
@not_allowed_in_seedsigner_os
|
||||
def _get_version_name_from_git_shell_branch(cls) -> str | None:
|
||||
def _get_branch_name_from_git_shell(cls) -> str | None:
|
||||
branch_name = os.popen("git branch --show-current 2> /dev/null").read()
|
||||
return branch_name.strip() if branch_name else None
|
||||
|
||||
|
||||
@classmethod
|
||||
@not_allowed_in_seedsigner_os
|
||||
def _get_version_name_from_git_shell_tag(cls) -> str | None:
|
||||
def _get_tag_name_from_git_shell(cls) -> str | None:
|
||||
# Only return a value if the current commit exactly corresponds with a tag.
|
||||
# (`--points-at` defaults to the current HEAD)
|
||||
tag_name = os.popen(f"git tag --points-at 2> /dev/null").read()
|
||||
@@ -496,22 +503,34 @@ class VersionUtils:
|
||||
@not_allowed_in_seedsigner_os
|
||||
def _get_full_commit_hash_from_git_shell(cls) -> str | None:
|
||||
"""
|
||||
Attempts to get the current git commit hash via shell `git` commands.
|
||||
Attempts to get the current full commit hash via shell `git` commands.
|
||||
"""
|
||||
commit_hash = os.popen("git rev-parse HEAD").read()
|
||||
return commit_hash.strip() if commit_hash else None
|
||||
|
||||
|
||||
@classmethod
|
||||
@not_allowed_in_seedsigner_os
|
||||
def _get_short_commit_hash_from_git_shell(cls) -> str | None:
|
||||
"""
|
||||
Attempts to get the current short commit hash via shell `git` commands.
|
||||
"""
|
||||
commit_hash = cls._get_full_commit_hash_from_git_shell()
|
||||
return commit_hash[:7] if commit_hash else None
|
||||
|
||||
|
||||
@classmethod
|
||||
@not_allowed_in_seedsigner_os
|
||||
def _get_version_name_from_git_shell(cls) -> str | None:
|
||||
"""
|
||||
Attempts to get the version name via shell `git` commands.
|
||||
|
||||
Note: If we have to fall back to the commit hash, we use the short version.
|
||||
"""
|
||||
return (
|
||||
cls._get_version_name_from_git_shell_branch() or
|
||||
cls._get_version_name_from_git_shell_tag() or
|
||||
cls._get_full_commit_hash_from_git_shell()
|
||||
cls._get_branch_name_from_git_shell() or
|
||||
cls._get_tag_name_from_git_shell() or
|
||||
cls._get_short_commit_hash_from_git_shell()
|
||||
)
|
||||
|
||||
|
||||
@@ -747,7 +766,7 @@ class VersionUtils:
|
||||
# Shouldn't be possible
|
||||
raise Exception("No python source files found in src/ directory")
|
||||
|
||||
return datetime.fromtimestamp(last_modified)
|
||||
return datetime.fromtimestamp(last_modified).astimezone(timezone.utc).replace(tzinfo=None)
|
||||
|
||||
except Exception as e:
|
||||
# Catch and log any unexpected errors but this isn't a mission-critical
|
||||
|
||||
@@ -197,16 +197,19 @@ def generate_screenshots(locale):
|
||||
value=SettingsConstants.OPTION__ENABLED
|
||||
)
|
||||
|
||||
# Initialize the Version data to the most recent release
|
||||
(version_name, version_timestamp) = VersionUtils._fetch_latest_seedsigner_release_tag()
|
||||
if not version_name or not version_timestamp:
|
||||
raise Exception("Could not fetch latest release version from GitHub")
|
||||
Version.override_data(
|
||||
version_name=version_name,
|
||||
version_fork="SeedSigner", # main repo; screenshot should hide fork and commit hash
|
||||
version_timestamp=version_timestamp,
|
||||
short_commit_hash="abcd1234" # dummy value should be ignored
|
||||
)
|
||||
def reset_version_most_recent_release():
|
||||
# Initialize the Version data to the most recent release
|
||||
(version_name, version_timestamp) = VersionUtils._fetch_latest_seedsigner_release_tag()
|
||||
if not version_name or not version_timestamp:
|
||||
raise Exception("Could not fetch latest release version from GitHub")
|
||||
new_values = {
|
||||
VersionUtils.VERSIONFILE_ATTR__NAME: version_name,
|
||||
VersionUtils.VERSIONFILE_ATTR__FORK: "SeedSigner", # main repo; screenshot should hide fork and commit hash
|
||||
VersionUtils.VERSIONFILE_ATTR__TIMESTAMP: version_timestamp,
|
||||
VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH: "abcd1234" # dummy value should be ignored
|
||||
}
|
||||
Version.override_data(**new_values)
|
||||
reset_version_most_recent_release()
|
||||
|
||||
# Automatically populate all Settings options Views
|
||||
settings_views_list = []
|
||||
@@ -314,14 +317,19 @@ def generate_screenshots(locale):
|
||||
|
||||
def reset_version_to_local_git_state_cb():
|
||||
# Normally, directly manipulating the singleton's internal instance is not
|
||||
# allowed, but the screnshot generator is an atypical use case.
|
||||
# allowed, but the screnshot generator is a special exception.
|
||||
Version._instance = None
|
||||
|
||||
|
||||
def reset_version_to_most_recent_release_cb():
|
||||
reset_version_most_recent_release()
|
||||
|
||||
|
||||
screenshot_sections = {
|
||||
"Main Menu Views": [
|
||||
ScreenshotConfig(OpeningSplashView, dict(force_partner_logos=True)),
|
||||
ScreenshotConfig(OpeningSplashView, dict(force_partner_logos=False), screenshot_name="OpeningSplashView_no_partner_logos"),
|
||||
ScreenshotConfig(OpeningSplashView, dict(force_partner_logos=True), run_before=reset_version_to_local_git_state_cb, screenshot_name="OpeningSplashView_current_git_state"),
|
||||
ScreenshotConfig(MainMenuView),
|
||||
ScreenshotConfig(MainMenuView, screenshot_name='MainMenuView_SDCardStateChangeToast_removed', toast_thread=SDCardStateChangeToastManagerThread(action=MicroSD.ACTION__REMOVED, activation_delay=0, duration=0)),
|
||||
ScreenshotConfig(MainMenuView, screenshot_name='MainMenuView_SDCardStateChangeToast_inserted', toast_thread=SDCardStateChangeToastManagerThread(action=MicroSD.ACTION__INSERTED, activation_delay=0, duration=0)),
|
||||
@@ -447,7 +455,7 @@ def generate_screenshots(locale):
|
||||
"Settings Views": settings_views_list + [
|
||||
ScreenshotConfig(settings_views.IOTestView),
|
||||
ScreenshotConfig(settings_views.DonateView),
|
||||
ScreenshotConfig(settings_views.VersionView),
|
||||
ScreenshotConfig(settings_views.VersionView, run_before=reset_version_to_most_recent_release_cb),
|
||||
ScreenshotConfig(settings_views.VersionView, run_before=reset_version_to_local_git_state_cb, screenshot_name="VersionView_current_git_state"),
|
||||
ScreenshotConfig(settings_views.SettingsIngestSettingsQRView, dict(data=settingsqr_data_persistent), screenshot_name="SettingsIngestSettingsQRView_persistent"),
|
||||
ScreenshotConfig(settings_views.SettingsIngestSettingsQRView, dict(data=settingsqr_data_not_persistent), screenshot_name="SettingsIngestSettingsQRView_not_persistent"),
|
||||
|
||||
+193
-129
@@ -29,8 +29,8 @@ TEST__FULL_COMMIT_HASH = "c5efda306c60877191013a6093d92cd0bfcccec8"
|
||||
TEST__VERSION_DICT = {
|
||||
VersionUtils.VERSIONFILE_ATTR__NAME: VersionUtils._prefix_version_name(TEST__VERSION_NAME),
|
||||
VersionUtils.VERSIONFILE_ATTR__FORK: TEST__VERSION_FORK,
|
||||
VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH: TEST__SHORT_COMMIT_HASH,
|
||||
VersionUtils.VERSIONFILE_ATTR__TIMESTAMP: TEST__VERSION_TIMESTAMP.isoformat(),
|
||||
VersionUtils.VERSIONFILE_ATTR__COMMIT_HASH: TEST__SHORT_COMMIT_HASH,
|
||||
}
|
||||
|
||||
# Mimic result of reading from version.json
|
||||
@@ -68,7 +68,7 @@ class VersionBaseTest(BaseTest):
|
||||
assumptions when running locally and when actually running in CI. Any test that
|
||||
needs to simulate being in CI can override this env var as needed.
|
||||
"""
|
||||
with mock.patch.dict(os.environ, {VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "false"}):
|
||||
with patch.dict(os.environ, {VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "false"}):
|
||||
yield
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ class TestVersionUtils_BasicCalls(VersionBaseTest):
|
||||
# If we don't provide the SeedSigner OS or Github Actions CI env vars, mock out
|
||||
# the `git` shell commands via `mock_popen`, and mock out all .git/ file parsing,
|
||||
# then the method should return the fallback warning note as the version name.
|
||||
with mock.patch("builtins.open", side_effect=FileNotFoundError):
|
||||
with patch("builtins.open", side_effect=FileNotFoundError):
|
||||
result = VersionUtils.get_version_name()
|
||||
assert "not detected" in result
|
||||
|
||||
@@ -206,7 +206,7 @@ class TestVersionUtils_BasicCalls(VersionBaseTest):
|
||||
# If we don't provide the SeedSigner OS or Github Actions CI env vars, mock out
|
||||
# the `git` shell commands via `mock_popen`, and mock out all .git/ file parsing,
|
||||
# then the method should return None.
|
||||
with mock.patch("builtins.open", side_effect=FileNotFoundError):
|
||||
with patch("builtins.open", side_effect=FileNotFoundError):
|
||||
VersionUtils.get_version_fork() is None
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ class TestVersionUtils_BasicCalls(VersionBaseTest):
|
||||
# If we don't provide the SeedSigner OS or Github Actions CI env vars, mock out
|
||||
# the `git` shell commands via `mock_popen`, and mock out all .git/ file parsing,
|
||||
# then the method should return None.
|
||||
with mock.patch("builtins.open", side_effect=FileNotFoundError):
|
||||
with patch("builtins.open", side_effect=FileNotFoundError):
|
||||
VersionUtils.get_short_commit_hash() is None
|
||||
|
||||
|
||||
@@ -238,21 +238,20 @@ class TestVersionUtils_VersionFile(VersionBaseTest):
|
||||
with patch("seedsigner.models.settings.Settings.HOSTNAME", Settings.SEEDSIGNER_OS):
|
||||
assert VersionUtils.get_version_name() == VersionUtils._prefix_version_name(TEST__VERSION_NAME)
|
||||
assert VersionUtils.get_version_fork() == TEST__VERSION_FORK
|
||||
assert VersionUtils.get_version_timestamp() == TEST__VERSION_TIMESTAMP
|
||||
assert VersionUtils.get_short_commit_hash() == TEST__SHORT_COMMIT_HASH
|
||||
assert VersionUtils.get_version_timestamp() == TEST__VERSION_TIMESTAMP
|
||||
|
||||
# Expect errors if keys are missing from version.json
|
||||
with mock.patch("builtins.open", mock.mock_open(read_data="{'some_key':'some_value'}")):
|
||||
with patch("builtins.open", mock.mock_open(read_data="{'some_key':'some_value'}")):
|
||||
with pytest.raises(Exception):
|
||||
VersionUtils.get_version_name()
|
||||
|
||||
# This time it's the timestamp that's missing
|
||||
with mock.patch("builtins.open", mock.mock_open(read_data=str({VersionUtils.VERSIONFILE_ATTR__NAME: TEST__VERSION_NAME}).replace("'", '"'))):
|
||||
with patch("builtins.open", mock.mock_open(read_data=str({VersionUtils.VERSIONFILE_ATTR__NAME: TEST__VERSION_NAME}).replace("'", '"'))):
|
||||
with pytest.raises(Exception):
|
||||
VersionUtils.get_version_timestamp()
|
||||
|
||||
|
||||
|
||||
def test__read_version_file(self):
|
||||
"""
|
||||
Low-level test for reading the version.json file.
|
||||
@@ -265,8 +264,8 @@ class TestVersionUtils_VersionFile(VersionBaseTest):
|
||||
assert version_data is not None
|
||||
assert version_data[VersionUtils.VERSIONFILE_ATTR__NAME] == VersionUtils._prefix_version_name(TEST__VERSION_NAME)
|
||||
assert version_data[VersionUtils.VERSIONFILE_ATTR__FORK] == TEST__VERSION_FORK
|
||||
assert version_data[VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH] == TEST__SHORT_COMMIT_HASH
|
||||
assert version_data[VersionUtils.VERSIONFILE_ATTR__TIMESTAMP] == TEST__VERSION_TIMESTAMP.isoformat()
|
||||
assert version_data[VersionUtils.VERSIONFILE_ATTR__COMMIT_HASH] == TEST__SHORT_COMMIT_HASH
|
||||
|
||||
|
||||
def test__read_version_file__missing(self):
|
||||
@@ -277,23 +276,14 @@ class TestVersionUtils_VersionFile(VersionBaseTest):
|
||||
# The upstream dependent calls should also return None
|
||||
assert VersionUtils._get_version_name_from_version_file() is None
|
||||
assert VersionUtils._get_version_fork_from_version_file() is None
|
||||
assert VersionUtils._get_version_timestamp_from_version_file() is None
|
||||
assert VersionUtils._get_short_commit_hash_from_version_file() is None
|
||||
assert VersionUtils._get_version_timestamp_from_version_file() is None
|
||||
|
||||
# Gracefully handle other unexpected exceptions
|
||||
with patch("builtins.open", side_effect=Exception("Unexpected error")):
|
||||
assert VersionUtils._read_version_file() is None
|
||||
|
||||
|
||||
def test__get_version_name_from_seedsigner_os_builder_env_var(self):
|
||||
assert os.environ.get(VersionUtils.ENV_VAR__SEEDSIGNER_OS_BUILDER__VERSION_NAME) is None
|
||||
assert VersionUtils._get_version_name_from_seedsigner_os_builder_env_var() is None
|
||||
|
||||
with mock.patch.dict(os.environ, {VersionUtils.ENV_VAR__SEEDSIGNER_OS_BUILDER__VERSION_NAME: TEST__VERSION_NAME}):
|
||||
result = VersionUtils._get_version_name_from_seedsigner_os_builder_env_var()
|
||||
assert result == TEST__VERSION_NAME
|
||||
|
||||
|
||||
|
||||
class TestVersionUtils_GithubActions(VersionBaseTest):
|
||||
def test_github_actions_env_vars(self):
|
||||
@@ -305,9 +295,9 @@ class TestVersionUtils_GithubActions(VersionBaseTest):
|
||||
pulled from the appropriate env vars.
|
||||
"""
|
||||
# CI uses some limited `git` shell calls; mock out the associated calls.
|
||||
with mock.patch("seedsigner.helpers.version.VersionUtils._get_version_timestamp_from_git_shell", return_value=TEST__VERSION_TIMESTAMP):
|
||||
with patch("seedsigner.helpers.version.VersionUtils._get_version_timestamp_from_git_shell", return_value=TEST__VERSION_TIMESTAMP):
|
||||
# When running CI on a branch
|
||||
with mock.patch.dict(os.environ, {
|
||||
with patch.dict(os.environ, {
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "true",
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__REF_NAME: TEST__VERSION_BRANCH,
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__SHA: TEST__FULL_COMMIT_HASH,
|
||||
@@ -319,7 +309,7 @@ class TestVersionUtils_GithubActions(VersionBaseTest):
|
||||
assert VersionUtils.get_version_timestamp() == TEST__VERSION_TIMESTAMP
|
||||
|
||||
# When running CI on a semantic tag
|
||||
with mock.patch.dict(os.environ, {
|
||||
with patch.dict(os.environ, {
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "true",
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__REF_NAME: TEST__SEMANTIC_TAG,
|
||||
}):
|
||||
@@ -327,7 +317,7 @@ class TestVersionUtils_GithubActions(VersionBaseTest):
|
||||
assert VersionUtils.get_version_name() == f"v{TEST__SEMANTIC_TAG}"
|
||||
|
||||
# When running CI on a generic tag
|
||||
with mock.patch.dict(os.environ, {
|
||||
with patch.dict(os.environ, {
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "true",
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__REF_NAME: TEST__VERSION_TAG,
|
||||
}):
|
||||
@@ -337,7 +327,7 @@ class TestVersionUtils_GithubActions(VersionBaseTest):
|
||||
# When running CI on a commit (detached HEAD) with no REF_NAME, the
|
||||
# version_name should be the short commit hash.
|
||||
# TODO: I don't think this scenario ever happens.
|
||||
with mock.patch.dict(os.environ, {
|
||||
with patch.dict(os.environ, {
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "true",
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__REF_NAME: "",
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__SHA: TEST__FULL_COMMIT_HASH,
|
||||
@@ -348,7 +338,7 @@ class TestVersionUtils_GithubActions(VersionBaseTest):
|
||||
# raise error.
|
||||
# Note: This scenario definitely would never happen. Just trying to get to
|
||||
# 100% test coverage.
|
||||
with mock.patch.dict(os.environ, {
|
||||
with patch.dict(os.environ, {
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "true",
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__REF_NAME: "",
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__SHA: "",
|
||||
@@ -365,13 +355,13 @@ class TestVersionUtils_GithubActions(VersionBaseTest):
|
||||
Note: Have to mock a value for ALL scenario variations here because this test will
|
||||
actually run in Github Actions so the env var will already be present!
|
||||
"""
|
||||
with mock.patch.dict(os.environ, {VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "true"}):
|
||||
with patch.dict(os.environ, {VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "true"}):
|
||||
assert VersionUtils.is_github_actions_ci() is True
|
||||
|
||||
with mock.patch.dict(os.environ, {VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "false"}):
|
||||
with patch.dict(os.environ, {VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "false"}):
|
||||
assert VersionUtils.is_github_actions_ci() is False
|
||||
|
||||
with mock.patch.dict(os.environ, {VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "1"}):
|
||||
with patch.dict(os.environ, {VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "1"}):
|
||||
assert VersionUtils.is_github_actions_ci() is False
|
||||
|
||||
|
||||
@@ -381,7 +371,7 @@ class TestVersionUtils_GithubActions(VersionBaseTest):
|
||||
env vars when set.
|
||||
"""
|
||||
# Need to signal that we're in a GitHub Actions CI environment
|
||||
with mock.patch.dict(os.environ, {
|
||||
with patch.dict(os.environ, {
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__IS_CI: "true",
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__REF_NAME: "",
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__SHA: "",
|
||||
@@ -389,12 +379,12 @@ class TestVersionUtils_GithubActions(VersionBaseTest):
|
||||
assert VersionUtils._get_version_name_from_github_actions_env_vars() is None
|
||||
|
||||
# REF_NAME should be passed straight through
|
||||
with mock.patch.dict(os.environ, {VersionUtils.ENV_VAR__GITHUB_ACTIONS__REF_NAME: TEST__VERSION_NAME}):
|
||||
with patch.dict(os.environ, {VersionUtils.ENV_VAR__GITHUB_ACTIONS__REF_NAME: TEST__VERSION_NAME}):
|
||||
result = VersionUtils._get_version_name_from_github_actions_env_vars()
|
||||
assert result == TEST__VERSION_NAME
|
||||
|
||||
# Unlikely scenario: no REF_NAME but SHA is set; should return short commit hash
|
||||
with mock.patch.dict(os.environ, {
|
||||
with patch.dict(os.environ, {
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__REF_NAME: "",
|
||||
VersionUtils.ENV_VAR__GITHUB_ACTIONS__SHA: TEST__FULL_COMMIT_HASH,
|
||||
}):
|
||||
@@ -410,30 +400,40 @@ class TestVersionUtils_SeedSignerOSBuilder(VersionBaseTest):
|
||||
since all the downstream helper methods are tested in detail elsewhere.
|
||||
"""
|
||||
# Simulate running in the SeedSigner OS build environment
|
||||
with mock.patch.dict(os.environ, {VersionUtils.ENV_VAR__SEEDSIGNER_OS_BUILDER__VERSION_NAME: TEST__VERSION_NAME}):
|
||||
with patch.dict(os.environ, {VersionUtils.ENV_VAR__IS_SEEDSIGNER_OS_BUILDER: "1"}):
|
||||
# SeedSigner OS builder uses some limited `git` shell calls; mock out the
|
||||
# associated calls.
|
||||
with mock.patch.multiple(
|
||||
with patch.multiple(
|
||||
"seedsigner.helpers.version.VersionUtils",
|
||||
_get_version_timestamp_from_git_shell=Mock(return_value=TEST__VERSION_TIMESTAMP),
|
||||
_get_version_name_from_git_shell=Mock(return_value=TEST__VERSION_NAME),
|
||||
_get_version_fork_from_git_shell=Mock(return_value=TEST__VERSION_FORK),
|
||||
_get_full_commit_hash_from_git_shell=Mock(return_value=TEST__FULL_COMMIT_HASH),
|
||||
_get_version_timestamp_from_git_shell=Mock(return_value=TEST__VERSION_TIMESTAMP),
|
||||
):
|
||||
assert VersionUtils.get_version_name() == VersionUtils._prefix_version_name(TEST__VERSION_NAME)
|
||||
assert VersionUtils.get_version_fork() == TEST__VERSION_FORK
|
||||
assert VersionUtils.get_short_commit_hash() == TEST__SHORT_COMMIT_HASH
|
||||
assert VersionUtils.get_version_timestamp() == TEST__VERSION_TIMESTAMP
|
||||
# Meanwhile, mock out the timestamp from source files and ensure it's NOT used
|
||||
with patch.object(
|
||||
VersionUtils,
|
||||
"_get_last_modified_timestamp_from_src_files",
|
||||
Mock(return_value=datetime.now())
|
||||
):
|
||||
assert VersionUtils.get_version_name() == VersionUtils._prefix_version_name(TEST__VERSION_NAME)
|
||||
assert VersionUtils.get_version_fork() == TEST__VERSION_FORK
|
||||
assert VersionUtils.get_short_commit_hash() == TEST__SHORT_COMMIT_HASH
|
||||
assert VersionUtils.get_version_timestamp() == TEST__VERSION_TIMESTAMP
|
||||
|
||||
# Verify that the source file timestamp method was NOT called
|
||||
VersionUtils._get_last_modified_timestamp_from_src_files.assert_not_called()
|
||||
|
||||
|
||||
def test_is_seedsigner_os_builder_env(self):
|
||||
"""
|
||||
is_seedsigner_os_builder_env should return True only when the
|
||||
ENV_VAR__SEEDSIGNER_OS_BUILDER__VERSION_NAME env var is set.
|
||||
ENV_VAR__IS_SEEDSIGNER_OS_BUILDER env var is set.
|
||||
"""
|
||||
with mock.patch.dict(os.environ, {}, clear=True):
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert VersionUtils._is_seedsigner_os_builder_env() is False
|
||||
|
||||
with mock.patch.dict(os.environ, {VersionUtils.ENV_VAR__SEEDSIGNER_OS_BUILDER__VERSION_NAME: TEST__VERSION_NAME}):
|
||||
with patch.dict(os.environ, {VersionUtils.ENV_VAR__IS_SEEDSIGNER_OS_BUILDER: "1"}):
|
||||
assert VersionUtils._is_seedsigner_os_builder_env() is True
|
||||
|
||||
|
||||
@@ -450,17 +450,29 @@ class TestVersionUtils_GitShell(VersionBaseTest):
|
||||
Note that in local dev we use the last modified timestamp from the source files
|
||||
rather than from git.
|
||||
"""
|
||||
with mock.patch.multiple(
|
||||
with patch.multiple(
|
||||
"seedsigner.helpers.version.VersionUtils",
|
||||
_get_version_name_from_git_shell=Mock(return_value=TEST__VERSION_BRANCH),
|
||||
_get_version_fork_from_git_shell=Mock(return_value=TEST__VERSION_FORK),
|
||||
_get_last_modified_timestamp_from_src_files=Mock(return_value=TEST__VERSION_TIMESTAMP),
|
||||
_get_full_commit_hash_from_git_shell=Mock(return_value=TEST__SHORT_COMMIT_HASH),
|
||||
_get_last_modified_timestamp_from_src_files=Mock(return_value=TEST__VERSION_TIMESTAMP),
|
||||
):
|
||||
assert VersionUtils.get_version_name() == TEST__VERSION_BRANCH
|
||||
assert VersionUtils.get_version_fork() == TEST__VERSION_FORK
|
||||
assert VersionUtils.get_version_timestamp() == TEST__VERSION_TIMESTAMP
|
||||
assert VersionUtils.get_short_commit_hash() == TEST__SHORT_COMMIT_HASH
|
||||
# Mock out the git shell call that retrieves the timestamp.
|
||||
with patch(
|
||||
"seedsigner.helpers.version.VersionUtils._get_version_timestamp_from_git_shell",
|
||||
return_value=None
|
||||
) as mock_timestamp_from_git_shell:
|
||||
# Verify that we're using the local dev code path
|
||||
assert VersionUtils.is_github_actions_ci() is False
|
||||
assert VersionUtils._is_seedsigner_os_builder_env() is False
|
||||
|
||||
assert VersionUtils.get_version_name() == TEST__VERSION_BRANCH
|
||||
assert VersionUtils.get_version_fork() == TEST__VERSION_FORK
|
||||
assert VersionUtils.get_short_commit_hash() == TEST__SHORT_COMMIT_HASH
|
||||
assert VersionUtils.get_version_timestamp() == TEST__VERSION_TIMESTAMP
|
||||
|
||||
# Verify that the git shell timestamp method was NOT called
|
||||
mock_timestamp_from_git_shell.assert_not_called()
|
||||
|
||||
|
||||
def test__get_version_name_from_git_shell(self):
|
||||
@@ -474,34 +486,36 @@ class TestVersionUtils_GitShell(VersionBaseTest):
|
||||
assert result is None
|
||||
|
||||
# If we're on a branch, should return the branch name
|
||||
with mock.patch.multiple(
|
||||
with patch.multiple(
|
||||
"seedsigner.helpers.version.VersionUtils",
|
||||
_get_version_name_from_git_shell_branch=Mock(return_value=TEST__VERSION_BRANCH),
|
||||
_get_version_name_from_git_shell_tag=Mock(return_value=TEST__VERSION_TAG),
|
||||
_get_branch_name_from_git_shell=Mock(return_value=TEST__VERSION_BRANCH),
|
||||
_get_tag_name_from_git_shell=Mock(return_value=TEST__VERSION_TAG),
|
||||
_get_full_commit_hash_from_git_shell=Mock(return_value=TEST__FULL_COMMIT_HASH),
|
||||
):
|
||||
result = VersionUtils._get_version_name_from_git_shell()
|
||||
assert result == TEST__VERSION_BRANCH
|
||||
|
||||
# If we're on a tag, the detached HEAD state wipes out the branch name
|
||||
with mock.patch.multiple(
|
||||
with patch.multiple(
|
||||
"seedsigner.helpers.version.VersionUtils",
|
||||
_get_version_name_from_git_shell_branch=Mock(return_value=None),
|
||||
_get_version_name_from_git_shell_tag=Mock(return_value=TEST__VERSION_TAG),
|
||||
_get_branch_name_from_git_shell=Mock(return_value=None),
|
||||
_get_tag_name_from_git_shell=Mock(return_value=TEST__VERSION_TAG),
|
||||
_get_full_commit_hash_from_git_shell=Mock(return_value=TEST__FULL_COMMIT_HASH),
|
||||
):
|
||||
result = VersionUtils._get_version_name_from_git_shell()
|
||||
assert result == TEST__VERSION_TAG
|
||||
|
||||
# Similarly, if we're detached at a specific commit hash
|
||||
with mock.patch.multiple(
|
||||
# Similarly, if we're detached at a specific commit hash.
|
||||
# Note: when falling back to the commit hash, we're expecting the SHORT commit
|
||||
# hash.
|
||||
with patch.multiple(
|
||||
"seedsigner.helpers.version.VersionUtils",
|
||||
_get_version_name_from_git_shell_branch=Mock(return_value=None),
|
||||
_get_version_name_from_git_shell_tag=Mock(return_value=None),
|
||||
_get_branch_name_from_git_shell=Mock(return_value=None),
|
||||
_get_tag_name_from_git_shell=Mock(return_value=None),
|
||||
_get_full_commit_hash_from_git_shell=Mock(return_value=TEST__FULL_COMMIT_HASH),
|
||||
):
|
||||
result = VersionUtils._get_version_name_from_git_shell()
|
||||
assert result == TEST__FULL_COMMIT_HASH
|
||||
assert result == TEST__SHORT_COMMIT_HASH
|
||||
|
||||
|
||||
def test__get_version_fork_from_git_shell(self, mock_popen: Mock):
|
||||
@@ -509,12 +523,32 @@ class TestVersionUtils_GitShell(VersionBaseTest):
|
||||
Test that _get_version_fork_from_git_shell returns the expected repo owner from
|
||||
the remote url.
|
||||
"""
|
||||
remote_url = "https://github.com/SeedSigner/seedsigner.git"
|
||||
expected_fork = "SeedSigner"
|
||||
for owner in ["SeedSigner", "seedsigner", "some-user"]:
|
||||
remote_url = f"https://github.com/{owner}/seedsigner.git"
|
||||
|
||||
mock_popen.return_value.read.return_value = remote_url
|
||||
result = VersionUtils._get_version_fork_from_git_shell()
|
||||
assert result == expected_fork
|
||||
mock_popen.return_value.read.return_value = remote_url
|
||||
result = VersionUtils._get_version_fork_from_git_shell()
|
||||
assert result == owner
|
||||
|
||||
|
||||
def test__get_full_commit_hash_from_git_shell(self, mock_popen: Mock):
|
||||
"""
|
||||
Test that _get_full_commit_hash_from_git_shell returns the expected full commit hash.
|
||||
"""
|
||||
mock_popen.return_value.read.return_value = TEST__FULL_COMMIT_HASH
|
||||
|
||||
result = VersionUtils._get_full_commit_hash_from_git_shell()
|
||||
assert result == TEST__FULL_COMMIT_HASH
|
||||
|
||||
|
||||
def test__get_short_commit_hash_from_git_shell(self, mock_popen: Mock):
|
||||
"""
|
||||
Test that _get_short_commit_hash_from_git_shell returns the expected short commit hash.
|
||||
"""
|
||||
mock_popen.return_value.read.return_value = TEST__FULL_COMMIT_HASH
|
||||
|
||||
result = VersionUtils._get_short_commit_hash_from_git_shell()
|
||||
assert result == TEST__SHORT_COMMIT_HASH
|
||||
|
||||
|
||||
def test__get_version_timestamp_from_git_shell(self, mock_popen: Mock):
|
||||
@@ -540,16 +574,6 @@ class TestVersionUtils_GitShell(VersionBaseTest):
|
||||
assert VersionUtils._get_version_timestamp_from_git_shell() == expected_datetime
|
||||
|
||||
|
||||
def test__get_full_commit_hash_from_git_shell(self, mock_popen: Mock):
|
||||
"""
|
||||
Test that _get_full_commit_hash_from_git_shell returns the expected short commit hash.
|
||||
"""
|
||||
mock_popen.return_value.read.return_value = TEST__SHORT_COMMIT_HASH
|
||||
|
||||
result = VersionUtils._get_full_commit_hash_from_git_shell()
|
||||
assert result == TEST__SHORT_COMMIT_HASH
|
||||
|
||||
|
||||
|
||||
class TestVersionUtils_DotGitFiles(VersionBaseTest):
|
||||
def test_local_dev_with_dot_git_dir_parsing(self, mock_popen: Mock):
|
||||
@@ -567,37 +591,50 @@ class TestVersionUtils_DotGitFiles(VersionBaseTest):
|
||||
"""
|
||||
# If we're on a branch, getting the commit hash requires the
|
||||
# .git/refs/heads/<branch> file.
|
||||
with mock.patch.multiple(
|
||||
with patch.multiple(
|
||||
"seedsigner.helpers.version.VersionUtils",
|
||||
_read_git_HEAD_file=Mock(return_value=(TEST__VERSION_BRANCH, None)),
|
||||
_get_full_commit_hash_from_git_refs_heads=Mock(return_value=TEST__FULL_COMMIT_HASH),
|
||||
_get_version_fork_from_git_config=Mock(return_value=TEST__VERSION_FORK),
|
||||
_get_last_modified_timestamp_from_src_files=Mock(return_value=TEST__VERSION_TIMESTAMP),
|
||||
):
|
||||
assert VersionUtils.get_version_name() == TEST__VERSION_BRANCH
|
||||
assert VersionUtils.get_version_fork() == TEST__VERSION_FORK
|
||||
assert VersionUtils.get_version_timestamp() == TEST__VERSION_TIMESTAMP
|
||||
assert VersionUtils.get_short_commit_hash() == TEST__SHORT_COMMIT_HASH
|
||||
# Mock out the git shell call that retrieves the timestamp.
|
||||
with patch(
|
||||
"seedsigner.helpers.version.VersionUtils._get_version_timestamp_from_git_shell",
|
||||
return_value=None
|
||||
) as mock_timestamp_from_git_shell:
|
||||
# Verify that we're using the local dev code path
|
||||
assert VersionUtils.is_github_actions_ci() is False
|
||||
assert VersionUtils._is_seedsigner_os_builder_env() is False
|
||||
|
||||
# If we're on a tag (detached HEAD), getting the commit hash requires
|
||||
# checking the refs/tags for a matching tag.
|
||||
with mock.patch.multiple(
|
||||
"seedsigner.helpers.version.VersionUtils",
|
||||
_read_git_HEAD_file=Mock(return_value=(None, TEST__FULL_COMMIT_HASH)),
|
||||
_get_matching_tag_from_git_refs_tags=Mock(return_value=TEST__VERSION_TAG),
|
||||
):
|
||||
assert VersionUtils.get_version_name() == TEST__VERSION_TAG
|
||||
assert VersionUtils.get_short_commit_hash() == TEST__SHORT_COMMIT_HASH
|
||||
assert VersionUtils.get_version_name() == TEST__VERSION_BRANCH
|
||||
assert VersionUtils.get_version_fork() == TEST__VERSION_FORK
|
||||
assert VersionUtils.get_version_timestamp() == TEST__VERSION_TIMESTAMP
|
||||
assert VersionUtils.get_short_commit_hash() == TEST__SHORT_COMMIT_HASH
|
||||
|
||||
# If we're on a commit hash (detached HEAD) with no matching tag, the
|
||||
# version name should be the short commit hash.
|
||||
with mock.patch.multiple(
|
||||
"seedsigner.helpers.version.VersionUtils",
|
||||
_read_git_HEAD_file=Mock(return_value=(None, TEST__FULL_COMMIT_HASH)),
|
||||
_get_matching_tag_from_git_refs_tags=Mock(return_value=None),
|
||||
):
|
||||
assert VersionUtils.get_version_name() == TEST__SHORT_COMMIT_HASH
|
||||
assert VersionUtils.get_short_commit_hash() == TEST__SHORT_COMMIT_HASH
|
||||
# If we're on a tag (detached HEAD), getting the commit hash requires
|
||||
# checking the refs/tags for a matching tag.
|
||||
with patch.multiple(
|
||||
"seedsigner.helpers.version.VersionUtils",
|
||||
_read_git_HEAD_file=Mock(return_value=(None, TEST__FULL_COMMIT_HASH)),
|
||||
_get_matching_tag_from_git_refs_tags=Mock(return_value=TEST__VERSION_TAG),
|
||||
):
|
||||
assert VersionUtils.get_version_name() == TEST__VERSION_TAG
|
||||
assert VersionUtils.get_short_commit_hash() == TEST__SHORT_COMMIT_HASH
|
||||
|
||||
# If we're on a commit hash (detached HEAD) with no matching tag, the
|
||||
# version name should be the short commit hash.
|
||||
with patch.multiple(
|
||||
"seedsigner.helpers.version.VersionUtils",
|
||||
_read_git_HEAD_file=Mock(return_value=(None, TEST__FULL_COMMIT_HASH)),
|
||||
_get_matching_tag_from_git_refs_tags=Mock(return_value=None),
|
||||
):
|
||||
assert VersionUtils.get_version_name() == TEST__SHORT_COMMIT_HASH
|
||||
assert VersionUtils.get_short_commit_hash() == TEST__SHORT_COMMIT_HASH
|
||||
|
||||
# Verify that through all of this that the git shell timestamp method was
|
||||
# NOT called.
|
||||
mock_timestamp_from_git_shell.assert_not_called()
|
||||
|
||||
|
||||
def test__get_dot_git_dir(self):
|
||||
@@ -677,17 +714,17 @@ class TestVersionUtils_DotGitFiles(VersionBaseTest):
|
||||
|
||||
# We already tested _read_git_HEAD_file() above, so just mock scenarios here.
|
||||
# On a branch:
|
||||
with mock.patch.object(VersionUtils, '_read_git_HEAD_file', return_value=(TEST__VERSION_BRANCH, None)):
|
||||
with patch.object(VersionUtils, '_read_git_HEAD_file', return_value=(TEST__VERSION_BRANCH, None)):
|
||||
assert VersionUtils._get_version_name_from_git_HEAD() == TEST__VERSION_BRANCH
|
||||
|
||||
# Detached HEAD at commit hash, with matching tag
|
||||
with mock.patch.object(VersionUtils, '_read_git_HEAD_file', return_value=(None, TEST__FULL_COMMIT_HASH)):
|
||||
with mock.patch.object(VersionUtils, '_get_matching_tag_from_git_refs_tags', return_value=TEST__VERSION_NAME):
|
||||
with patch.object(VersionUtils, '_read_git_HEAD_file', return_value=(None, TEST__FULL_COMMIT_HASH)):
|
||||
with patch.object(VersionUtils, '_get_matching_tag_from_git_refs_tags', return_value=TEST__VERSION_NAME):
|
||||
assert VersionUtils._get_version_name_from_git_HEAD() == TEST__VERSION_NAME
|
||||
|
||||
# Detached HEAD at commit hash, no matching tag; returns the short commit hash
|
||||
with mock.patch.object(VersionUtils, '_read_git_HEAD_file', return_value=(None, TEST__FULL_COMMIT_HASH)):
|
||||
with mock.patch.object(VersionUtils, '_get_matching_tag_from_git_refs_tags', return_value=None):
|
||||
with patch.object(VersionUtils, '_read_git_HEAD_file', return_value=(None, TEST__FULL_COMMIT_HASH)):
|
||||
with patch.object(VersionUtils, '_get_matching_tag_from_git_refs_tags', return_value=None):
|
||||
assert VersionUtils._get_version_name_from_git_HEAD() == TEST__SHORT_COMMIT_HASH
|
||||
|
||||
|
||||
@@ -695,7 +732,7 @@ class TestVersionUtils_DotGitFiles(VersionBaseTest):
|
||||
# _get_commit_hash_from_git_HEAD is a trivial convenience function that relies on
|
||||
# _read_git_HEAD_file which we've already tested. Just verify the expected outputs
|
||||
# here.
|
||||
with mock.patch.object(VersionUtils, '_read_git_HEAD_file', return_value=(None, TEST__SHORT_COMMIT_HASH)):
|
||||
with patch.object(VersionUtils, '_read_git_HEAD_file', return_value=(None, TEST__SHORT_COMMIT_HASH)):
|
||||
assert VersionUtils._get_full_commit_hash_from_git_HEAD() == TEST__SHORT_COMMIT_HASH
|
||||
|
||||
|
||||
@@ -759,7 +796,7 @@ class TestVersionUtils_DotGitFiles(VersionBaseTest):
|
||||
[next_section]
|
||||
next_key = next_value
|
||||
"""
|
||||
with mock.patch("builtins.open", mock.mock_open(read_data=git_config)):
|
||||
with patch("builtins.open", mock.mock_open(read_data=git_config)):
|
||||
assert VersionUtils._get_version_fork_from_git_config() == expected_fork
|
||||
|
||||
# Missing origin section should return None
|
||||
@@ -769,7 +806,7 @@ class TestVersionUtils_DotGitFiles(VersionBaseTest):
|
||||
[next_section]
|
||||
next_key = next_value
|
||||
"""
|
||||
with mock.patch("builtins.open", mock.mock_open(read_data=git_config_no_origin)):
|
||||
with patch("builtins.open", mock.mock_open(read_data=git_config_no_origin)):
|
||||
assert VersionUtils._get_version_fork_from_git_config() is None
|
||||
|
||||
# Handle malformed origin section (can't find url) should return None
|
||||
@@ -779,11 +816,11 @@ class TestVersionUtils_DotGitFiles(VersionBaseTest):
|
||||
[next_section]
|
||||
next_key = next_value
|
||||
"""
|
||||
with mock.patch("builtins.open", mock.mock_open(read_data=git_config_malformed_origin)):
|
||||
with patch("builtins.open", mock.mock_open(read_data=git_config_malformed_origin)):
|
||||
assert VersionUtils._get_version_fork_from_git_config() is None
|
||||
|
||||
# If the git config file is missing, should return None
|
||||
with mock.patch("builtins.open", side_effect=FileNotFoundError):
|
||||
with patch("builtins.open", side_effect=FileNotFoundError):
|
||||
assert VersionUtils._get_version_fork_from_git_config() is None
|
||||
|
||||
|
||||
@@ -802,12 +839,13 @@ class TestVersionUtils_DotGitFiles(VersionBaseTest):
|
||||
assert timestamp < datetime.now() + timedelta(days=30)
|
||||
|
||||
# Now mock out os.path.getmtime to force all files to have a known timestamp
|
||||
expected_timestamp = datetime(2025, 12, 23, 0, 0, 0)
|
||||
with mock.patch("os.path.getmtime", return_value=expected_timestamp.timestamp()):
|
||||
assert VersionUtils._get_last_modified_timestamp_from_src_files() == expected_timestamp
|
||||
local_timestamp = datetime(2025, 12, 23, 0, 0, 0)
|
||||
with patch("os.path.getmtime", return_value=local_timestamp.timestamp()):
|
||||
# Note that the result will be converted to UTC with no tzinfo
|
||||
assert VersionUtils._get_last_modified_timestamp_from_src_files() == local_timestamp.astimezone(timezone.utc).replace(tzinfo=None)
|
||||
|
||||
# Mock out os.walk() to simulate no .py files found
|
||||
with mock.patch("os.walk", return_value=[]):
|
||||
with patch("os.walk", return_value=[]):
|
||||
assert VersionUtils._get_last_modified_timestamp_from_src_files() is None
|
||||
|
||||
|
||||
@@ -833,7 +871,7 @@ class TestVersionUtils_Misc(VersionBaseTest):
|
||||
fake_response.status = 200
|
||||
fake_response.read.return_value = json.dumps(latest_releases_response_dict).encode('utf-8')
|
||||
|
||||
with mock.patch("urllib.request.urlopen", return_value=fake_response):
|
||||
with patch("urllib.request.urlopen", return_value=fake_response):
|
||||
release_tag, release_timestamp = VersionUtils._fetch_latest_seedsigner_release_tag()
|
||||
|
||||
# mock_popen returns empty string, which mimics not having local git data to
|
||||
@@ -859,13 +897,13 @@ class TestVersionUtils_Misc(VersionBaseTest):
|
||||
# Should gracefully handle HTTP errors
|
||||
fake_error_response = Mock()
|
||||
fake_error_response.status = 404
|
||||
with mock.patch("urllib.request.urlopen", return_value=fake_error_response):
|
||||
with patch("urllib.request.urlopen", return_value=fake_error_response):
|
||||
release_tag, release_timestamp = VersionUtils._fetch_latest_seedsigner_release_tag()
|
||||
assert release_tag is None
|
||||
assert release_timestamp is None
|
||||
|
||||
# And other exceptions
|
||||
with mock.patch("urllib.request.urlopen", side_effect=Exception("Network error")):
|
||||
with patch("urllib.request.urlopen", side_effect=Exception("Network error")):
|
||||
release_tag, release_timestamp = VersionUtils._fetch_latest_seedsigner_release_tag()
|
||||
assert release_tag is None
|
||||
assert release_timestamp is None
|
||||
@@ -884,7 +922,7 @@ class TestVersion(VersionBaseTest):
|
||||
with patch("seedsigner.models.settings.Settings.HOSTNAME", Settings.SEEDSIGNER_OS):
|
||||
Version.get_version_name() == TEST__VERSION_DICT[VersionUtils.VERSIONFILE_ATTR__NAME]
|
||||
Version.get_version_fork() == TEST__VERSION_DICT[VersionUtils.VERSIONFILE_ATTR__FORK]
|
||||
Version.get_short_commit_hash() == TEST__VERSION_DICT[VersionUtils.VERSIONFILE_ATTR__COMMIT_HASH]
|
||||
Version.get_short_commit_hash() == TEST__VERSION_DICT[VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH]
|
||||
Version.get_version_timestamp() == TEST__VERSION_TIMESTAMP
|
||||
|
||||
|
||||
@@ -893,17 +931,12 @@ class TestVersion(VersionBaseTest):
|
||||
Test that we can override the version data via the Version.override_version_data()
|
||||
method.
|
||||
"""
|
||||
override_name = "v9.9.9-test"
|
||||
override_fork = "TestFork"
|
||||
override_commit_hash = "abcd123"
|
||||
override_timestamp = datetime(2030, 1, 1, 0, 0, 0)
|
||||
|
||||
# Initially the version data is pulled from the usual sources
|
||||
self.write_test_version_file()
|
||||
with patch("seedsigner.models.settings.Settings.HOSTNAME", Settings.SEEDSIGNER_OS):
|
||||
assert Version.get_version_name() == TEST__VERSION_DICT[VersionUtils.VERSIONFILE_ATTR__NAME]
|
||||
assert Version.get_version_fork() == TEST__VERSION_DICT[VersionUtils.VERSIONFILE_ATTR__FORK]
|
||||
assert Version.get_short_commit_hash() == TEST__VERSION_DICT[VersionUtils.VERSIONFILE_ATTR__COMMIT_HASH]
|
||||
assert Version.get_short_commit_hash() == TEST__VERSION_DICT[VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH]
|
||||
assert Version.get_version_timestamp() == TEST__VERSION_TIMESTAMP
|
||||
|
||||
# While we're in the mocked SeedSigner OS environment, verify that the
|
||||
@@ -911,19 +944,33 @@ class TestVersion(VersionBaseTest):
|
||||
with pytest.raises(NotAllowedInSeedSignerOS):
|
||||
Version.override_data()
|
||||
|
||||
override_name = "v9.9.9-test"
|
||||
override_fork = "TestFork"
|
||||
override_commit_hash = "abcd123"
|
||||
override_timestamp = datetime(2030, 1, 1, 0, 0, 0)
|
||||
override_dict = {
|
||||
VersionUtils.VERSIONFILE_ATTR__NAME: override_name,
|
||||
VersionUtils.VERSIONFILE_ATTR__FORK: override_fork,
|
||||
VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH: override_commit_hash,
|
||||
VersionUtils.VERSIONFILE_ATTR__TIMESTAMP: override_timestamp,
|
||||
}
|
||||
|
||||
# No longer in the mocked SeedSigner OS environment; should be allowed now.
|
||||
Version.override_data(
|
||||
version_name=override_name,
|
||||
version_fork=override_fork,
|
||||
short_commit_hash=override_commit_hash,
|
||||
version_timestamp=override_timestamp,
|
||||
)
|
||||
Version.override_data(**override_dict)
|
||||
|
||||
assert Version.get_version_name() == override_name
|
||||
assert Version.get_version_fork() == override_fork
|
||||
assert Version.get_short_commit_hash() == override_commit_hash
|
||||
assert Version.get_version_timestamp() == override_timestamp
|
||||
|
||||
# No overrides specified should result in no values changed.
|
||||
Version.override_data()
|
||||
assert Version.get_version_name() == override_name
|
||||
assert Version.get_version_fork() == override_fork
|
||||
assert Version.get_short_commit_hash() == override_commit_hash
|
||||
assert Version.get_version_timestamp() == override_timestamp
|
||||
|
||||
|
||||
|
||||
def test_to_dict(self):
|
||||
"""
|
||||
@@ -931,8 +978,25 @@ class TestVersion(VersionBaseTest):
|
||||
"""
|
||||
self.write_test_version_file()
|
||||
with patch("seedsigner.models.settings.Settings.HOSTNAME", Settings.SEEDSIGNER_OS):
|
||||
# In SeedSigner OS, the version data comes from the version file.
|
||||
assert Version.to_dict() == TEST__VERSION_DICT
|
||||
|
||||
extra_attr = "extra"
|
||||
different_dict = {
|
||||
VersionUtils.VERSIONFILE_ATTR__NAME: "v1.2.3-different",
|
||||
VersionUtils.VERSIONFILE_ATTR__FORK: "DifferentFork",
|
||||
VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH: "differenthash",
|
||||
VersionUtils.VERSIONFILE_ATTR__TIMESTAMP: datetime(2026, 1, 1, 0, 0, 0), # stored internally as a datetime
|
||||
extra_attr: "should be ignored",
|
||||
}
|
||||
Version.override_data(**different_dict)
|
||||
output_dict = Version.to_dict()
|
||||
assert output_dict[VersionUtils.VERSIONFILE_ATTR__NAME] == different_dict[VersionUtils.VERSIONFILE_ATTR__NAME]
|
||||
assert output_dict[VersionUtils.VERSIONFILE_ATTR__FORK] == different_dict[VersionUtils.VERSIONFILE_ATTR__FORK]
|
||||
assert output_dict[VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH] == different_dict[VersionUtils.VERSIONFILE_ATTR__SHORT_COMMIT_HASH]
|
||||
assert output_dict[VersionUtils.VERSIONFILE_ATTR__TIMESTAMP] == different_dict[VersionUtils.VERSIONFILE_ATTR__TIMESTAMP].isoformat() # returned as a string
|
||||
assert extra_attr not in output_dict
|
||||
|
||||
|
||||
|
||||
class TestNotAllowedInSeedSignerOSDecorator(BaseTest):
|
||||
@@ -949,14 +1013,14 @@ class TestNotAllowedInSeedSignerOSDecorator(BaseTest):
|
||||
if we run a decorated function while in SeedSigner OS.
|
||||
"""
|
||||
# Patch over the Settings.HOSTNAME value to simulate running in SeedSigner OS
|
||||
with mock.patch("seedsigner.models.settings.Settings.HOSTNAME", Settings.SEEDSIGNER_OS):
|
||||
with patch("seedsigner.models.settings.Settings.HOSTNAME", Settings.SEEDSIGNER_OS):
|
||||
with pytest.raises(NotAllowedInSeedSignerOS):
|
||||
self.dummy_function()
|
||||
|
||||
|
||||
def test_allowed_outside_seedsigner_os(self):
|
||||
# Now try with any other HOSTNAME
|
||||
with mock.patch("seedsigner.models.settings.Settings.HOSTNAME", "my_dev_machine"):
|
||||
with patch("seedsigner.models.settings.Settings.HOSTNAME", "my_dev_machine"):
|
||||
assert self.dummy_function() == self.SUCCESS
|
||||
|
||||
|
||||
|
||||
+20
-33
@@ -8,53 +8,40 @@ from seedsigner.helpers.version import Version, VersionUtils
|
||||
CLI utility to extract the current version data and write to
|
||||
`src/seedsigner/version.json`. Primarily used by the SeedSigner OS build process.
|
||||
|
||||
SeedSigner OS lifecycle:
|
||||
* Build process runs this script to generate version.json.
|
||||
* version.json is included in the SeedSigner OS image.
|
||||
* SeedSigner OS reads version.json at runtime.
|
||||
|
||||
Notes:
|
||||
* The SeedSigner OS build environment already relies on `git` being installed.
|
||||
* This script can also be run in local dev but `git` shell commands are required.
|
||||
* This script can also be run in local dev but note slight difference in how
|
||||
version_timestamp is gathered.
|
||||
* Tries to pull current version status via `git` shell commands, but has fallbacks
|
||||
to directly parse .git/ files.
|
||||
|
||||
Version data:
|
||||
* version_name:
|
||||
* Check for the SEEDSIGNER_VERSION_NAME env var (provided in SeedSigner OS build
|
||||
env).
|
||||
* Will be the branch, tag, or commit hash being built.
|
||||
* If running in local dev instead, this script will try to populate that env var
|
||||
using `git` shell commands:
|
||||
* Current git branch name
|
||||
* Current git tag name
|
||||
* Current git commit hash
|
||||
* version_name: Retrieves the current git status by checking, in order:
|
||||
* Current git branch name
|
||||
* Current git tag name
|
||||
* Current git commit hash
|
||||
|
||||
* version_fork:
|
||||
* Pulls the current repo owner from the `git remote` shell command.
|
||||
|
||||
* version_timestamp:
|
||||
* Pulls last git commit time from `git log`.
|
||||
* The current repo owner.
|
||||
|
||||
* short_commit_hash:
|
||||
* Pulls current git commit hash from `git` shell command.
|
||||
* Current git short commit hash.
|
||||
|
||||
* version_timestamp:
|
||||
* SeedSigner OS builder: Pulls last git commit time for the checked out
|
||||
branch/tag/commit.
|
||||
* Local dev: Scans the source python files for the most recent modified time.
|
||||
|
||||
"""
|
||||
if __name__ == "__main__":
|
||||
is_seedsigner_os_builder = VersionUtils._is_seedsigner_os_builder_env()
|
||||
|
||||
if not is_seedsigner_os_builder:
|
||||
# Pull version_name from the current git state via `git` shell commands
|
||||
version_name = VersionUtils._get_version_name_from_git_shell()
|
||||
|
||||
# Temporarily set the env var
|
||||
os.environ[VersionUtils.ENV_VAR__SEEDSIGNER_OS_BUILDER__VERSION_NAME] = version_name
|
||||
|
||||
# As soon as `Version` is instantiated, it will gather all the version data
|
||||
# according to the logic in `VersionUtils`.
|
||||
version_info = Version.get_instance().to_dict()
|
||||
|
||||
# Write the version.json file.
|
||||
version_file_path = VersionUtils._get_version_file_path()
|
||||
with open(version_file_path, "w") as f:
|
||||
json.dump(version_info, f, indent=4)
|
||||
|
||||
print(f"Wrote version info to: {version_file_path}")
|
||||
print(json.dumps(version_info, indent=4))
|
||||
|
||||
# Clean up the temp env var if needed
|
||||
if not is_seedsigner_os_builder:
|
||||
del os.environ[VersionUtils.ENV_VAR__SEEDSIGNER_OS_BUILDER__VERSION_NAME]
|
||||
|
||||
Reference in New Issue
Block a user