Skip to content

Commit

Permalink
Release version 0.0.0.dev300
Browse files Browse the repository at this point in the history
  • Loading branch information
AAriam committed Sep 29, 2024
1 parent 4b9729d commit 48fdc33
Show file tree
Hide file tree
Showing 17 changed files with 396 additions and 196 deletions.
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespaces = true
# ----------------------------------------- Project Metadata -------------------------------------
#
[project]
version = "0.0.0.dev299"
version = "0.0.0.dev300"
name = "ControlMan"
dependencies = [
"packaging >= 23.2, < 24",
Expand All @@ -27,9 +27,9 @@ dependencies = [
"jsonpath-ng == 1.6.1",
"ruamel.yaml == 0.17.40",
"PyLinks == 0.0.0.dev28",
"LoggerMan == 0.0.0.dev43",
"LoggerMan == 0.0.0.dev44",
"PySerials == 0.0.0.dev18",
"GitTidy == 0.0.0.dev36",
"GitTidy == 0.0.0.dev37",
"PkgData == 0.0.0.dev4",
"PyShellMan == 0.0.0.dev4",
"PySyntax == 0.0.0.dev3",
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ referencing == 0.35.1
jsonpath-ng == 1.6.1
ruamel.yaml == 0.17.40
PyLinks == 0.0.0.dev28
LoggerMan == 0.0.0.dev43
LoggerMan == 0.0.0.dev44
PySerials == 0.0.0.dev18
GitTidy == 0.0.0.dev36
GitTidy == 0.0.0.dev37
PkgData == 0.0.0.dev4
PyShellMan == 0.0.0.dev4
PySyntax == 0.0.0.dev3
Expand Down
2 changes: 1 addition & 1 deletion src/controlman/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def manager(
cc_path = repo.repo_path / control_center_path
if not cc_path.is_dir():
raise ValueError(f"Invalid control center path '{cc_path}'")
data_before = _ps.NestedDict({})
data_before = _ps.NestedDict()
else:
data_before = from_json_file(repo_path=repo.repo_path)
cc_path = repo.repo_path / data_before["control.path"]
Expand Down
2 changes: 1 addition & 1 deletion src/controlman/cache_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def log_msg_new_cache(reason: str | None = None, traceback: bool = False):
log_content = [msg]
if traceback:
log_content.append(_logger.traceback())
_logger.warning(log_title, *log_content)
_logger.warning(log_title, *log_content, stack_up=1)
return

log_title = "Cache Initialization"
Expand Down
74 changes: 42 additions & 32 deletions src/controlman/center_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import shutil as _shutil

from versionman.pep440_semver import PEP440SemVer as _PEP440SemVer
from loggerman import logger as _logger
import pylinks as _pylinks
import pyserials as _ps
from gittidy import Git as _Git
from loggerman import logger as _logger

from controlman import data_gen as _data_gen
from controlman.hook_manager import HookManager as _HookManager
Expand Down Expand Up @@ -60,57 +60,68 @@ def __init__(
def load(self) -> _ps.NestedDict:
if self._data_raw:
return self._data_raw
full_data = _data_loader.load(
control_center_path=self._path_cc,
cache_manager=self._cache_manager,
)
if self._hook_manager.has_hook(const.FUNCNAME_CC_HOOK_POST_LOAD):
full_data = self._hook_manager.generate(
with _logger.sectioning("Configuration File Load"):
full_data = _data_loader.load(
path_cc=self._path_cc,
cache_manager=self._cache_manager,
)
with _logger.sectioning("Post-Load User Hooks"):
self._hook_manager.generate(
const.FUNCNAME_CC_HOOK_POST_LOAD,
full_data,
)
_data_validator.validate(data=full_data, source="source", before_substitution=True)
with _logger.sectioning("Post-Load Data Validation"):
_data_validator.validate(data=full_data, source="source", before_substitution=True)
self._data_raw = _ps.NestedDict(full_data)
return self._data_raw

def generate_data(self) -> _ps.NestedDict:
if self._data:
return self._data
self.load()
data = _data_gen.generate(
git_manager=self._git,
cache_manager=self._cache_manager,
github_api=self._github_api,
data=self._data_raw,
data_before=self._data_before,
data_main=self._data_main,
future_versions=self._future_vers,
)
# Validate again to fill default values that depend on generated data
# Example: A key may be referencing `team.owner.email.url`, which has a default
# value based on `team.owner.email.id`. But since `team.owner` is generated
# dynamically, the default value for `team.owner.email.url` is not set in the initial validation.
_data_validator.validate(data=data(), source="source", before_substitution=True)
if self._hook_manager.has_hook(const.FUNCNAME_CC_HOOK_POST_DATA):
with _logger.sectioning("Dynamic Data Generation"):
data = _data_gen.generate(
git_manager=self._git,
cache_manager=self._cache_manager,
github_api=self._github_api,
data=self._data_raw,
data_before=self._data_before,
data_main=self._data_main,
future_versions=self._future_vers,
)
with _logger.sectioning("Post-Generation Data Validation"):
# Validate again to fill default values that depend on generated data
# Example: A key may be referencing `team.owner.email.url`, which has a default
# value based on `team.owner.email.id`. But since `team.owner` is generated
# dynamically, the default value for `team.owner.email.url` is not set in the initial validation.
_data_validator.validate(data=data(), source="source", before_substitution=True)
with _logger.sectioning("Post-Generation User Hooks"):
self._hook_manager.generate(
const.FUNCNAME_CC_HOOK_POST_DATA,
data,
)
self._cache_manager.save()
data.fill()
_data_validator.validate(data=data(), source="source")
self._cache_manager.save()
with _logger.sectioning("Template Resolution"):
data.fill()
_logger.success(
"Filled Data",
"All template variables have been successfully resolved.",
)
with _logger.sectioning("Final Data Validation"):
_data_validator.validate(data=data(), source="source")
self._data = data
return self._data

def generate_files(self) -> list[_GeneratedFile]:
if self._files:
return self._files
self.generate_data()
self._files = _file_gen.generate(
data=self._data,
data_before=self._data_before,
repo_path=self._path_root,
)
with _logger.sectioning("Dynamic File Generation"):
self._files = _file_gen.generate(
data=self._data,
data_before=self._data_before,
repo_path=self._path_root,
)
return self._files

def compare(self):
Expand All @@ -134,7 +145,6 @@ def report(self) -> _ControlCenterReporter:
dirs=self._dirs,
)

@_logger.sectioner("Apply Changes To Dynamic Repository File")
def apply_changes(self) -> None:
"""Apply changes to dynamic repository files."""

Expand Down
67 changes: 30 additions & 37 deletions src/controlman/data_gen/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pylinks
from loggerman import logger as _logger
import pyserials as _ps
import mdit as _mdit

from controlman import _file_util
from controlman.cache_manager import CacheManager
Expand Down Expand Up @@ -36,7 +37,6 @@ def __init__(
self._gh_api_repo = None
return

@_logger.sectioner("Generate Contents")
def generate(self) -> None:
self._repo()
self._team()
Expand All @@ -49,7 +49,6 @@ def generate(self) -> None:
self._urls_website()
return

@_logger.sectioner("Repository Data")
def _repo(self) -> None:
repo_address = self._git.get_remote_repo_name(
remote_name="origin",
Expand All @@ -58,22 +57,34 @@ def _repo(self) -> None:
fallback_purpose=False
)
if not repo_address:
raise _exception.data_gen.ControlManRepositoryError(
raise _exception.data_gen.RemoteGitHubRepoNotFoundError(
repo_path=self._git.repo_path,
problem="Failed to determine GitHub address. "
"The Git repository has no remote set for push to origin. "
f"Following remotes were found: {str(self._git.get_remotes())}",
remotes=self._git.get_remotes(),
)
username, repo_name = repo_address
self._gh_api_repo = self._gh_api.user(username).repo(repo_name)
_logger.info("GitHub API Call", f"Retrieve info for repository '{username}/{repo_name}'.")
repo_info = self._gh_api.user(username).repo(repo_name).info
log_info = _mdit.inline_container(
"Retrieved data for repository ",
_mdit.element.code_span(f'{username}/{repo_name}'),
"."
)
if "source" in repo_info:
repo_info = repo_info["source"]
_logger.info(
f"Fork Detected",
f"Repository is a fork and target is set to '{repo_info['source']['full_name']}'.",
log_info.extend(
"The repository is a fork and thus the target is set to ",
_mdit.element.code_span(repo_info["full_name"]),
)
repo_info_code_block = _mdit.element.code_block(
content=_ps.write.to_yaml_string(repo_info),
language="yaml",
caption="GitHub API Response",
)
_logger.info(
f"Repository Data",
log_info,
repo_info_code_block,
)
repo_info["created_at"] = _datetime.datetime.strptime(
repo_info["created_at"], "%Y-%m-%dT%H:%M:%SZ"
).strftime("%Y-%m-%d")
Expand All @@ -85,40 +96,36 @@ def _repo(self) -> None:
self._data["team.owner.github.id"] = repo_info["owner"]["login"]
return

@_logger.sectioner("Project People")
def _team(self) -> None:
for person_id in self._data["team"].keys():
self._data.fill(f"team.{person_id}")
self.fill_entity(self._data[f"team.{person_id}"])
return

@_logger.sectioner("Project Name")
def _name(self) -> None:
name = self._data.fill("name")
repo_name = self._data["repo.name"]
if not name:
name = self._data["name"] = repo_name.replace("-", " ")
_logger.info(f"Set `name`", f"Set to '{name}' from repository name")
_logger.info(
f"Project Name",
f"Set to '{name}' from repository name."
)
self._data["slug.name"] = pylinks.string.to_slug(name)
self._data["slug.repo_name"] = pylinks.string.to_slug(repo_name)
return

@_logger.sectioner("Keyword slugs")
def _keywords(self) -> None:
keywords = self._data.fill("keywords")
if not keywords:
_logger.info("No keywords specified.")
return
slugs = [pylinks.string.to_slug(keyword) for keyword in keywords if len(keyword) <= 50]
self._data["slug.keywords"] = slugs
_logger.info("Set `slug.keywords`", f"Set from `keywords`")
_logger.debug(f"Keyword slugs: {str(slugs)}")
return

@_logger.sectioner("Project License")
def _license(self):
data = self._data["license"]
if not data:
_logger.info("No license specified.")
return
license_id = self._data.fill("license.id")
license_db = _file_util.get_package_datafile("db/license/info.yaml")
Expand All @@ -133,7 +140,6 @@ def _license(self):
json_path="license",
data=self._data(),
)
_logger.info("License data is manually set.")
return
if "name" not in data:
data["name"] = license_info["name"]
Expand All @@ -145,11 +151,8 @@ def _license(self):
if "notice" not in data:
filename = license_id.removesuffix("-or-later")
data["notice"] = _file_util.get_package_datafile(f"db/license/notice/{filename}.txt")
_logger.info(f"License data set for license ID '{license_id}'.")
_logger.debug("License data:", str(license_info))
return

@_logger.sectioner("Project Copyright")
def _copyright(self):
data = self._data["copyright"]
if not data or "period" in data:
Expand All @@ -160,7 +163,6 @@ def _copyright(self):
data["start_year"] = start_year = _datetime.datetime.strptime(
self._data["repo.created_at"], "%Y-%m-%d"
).year
_logger.info(f"Project start year set from repository creation date: {start_year}")
else:
if start_year > current_year:
raise _exception.load.ControlManSchemaValidationError(
Expand All @@ -172,21 +174,20 @@ def _copyright(self):
json_path="copyright.start_year",
data=self._data(),
)
_logger.info(f"Project start year already set manually in metadata: {start_year}")
year_range = f"{start_year}{'' if start_year == current_year else f'–{current_year}'}"
data["period"] = year_range
return

@_logger.sectioner("GitHub Discussions Categories")
def _discussion_categories(self):
discussions_info = self._cache.get("repo", f"discussion_categories")
if discussions_info:
_logger.info(f"Set from cache.")
return
if not self._gh_api.authenticated:
_logger.notice("GitHub token not provided. Cannot get discussions categories.")
_logger.notice(
"GitHub Discussion Categories",
"GitHub token not provided. Cannot get discussions categories."
)
return
_logger.info("Get repository discussions from GitHub API")
discussions_info = self._gh_api_repo.discussion_categories()
self._cache.set("repo", f"discussions_categories", discussions_info)
discussion = self._data.setdefault("discussion.category", {})
Expand All @@ -196,7 +197,6 @@ def _discussion_categories(self):
category_obj["name"] = category["name"]
return

@_logger.sectioner("GitHub URLs")
def _urls_github(self) -> None:
self._data["repo.url.issues.new"] = {
issue_type["id"]: f"{self._data['repo.url.home']}/issues/new?template={idx + 1:02}_{issue_type['id']}.yaml"
Expand All @@ -208,7 +208,6 @@ def _urls_github(self) -> None:
}
return

@_logger.sectioner("Website URLs")
def _urls_website(self) -> None:
base_url = self._data.get("web.url.base")
if not base_url:
Expand Down Expand Up @@ -292,7 +291,6 @@ def make_name():
data["orcid"]["pubs"] = self._get_orcid_publications(orcid_id=data["orcid"]["user"])
return

@_logger.sectioner("Get GitHub User Data")
def _get_github_user(self, username: str) -> dict:

def add_social(name, user, url):
Expand All @@ -303,10 +301,8 @@ def add_social(name, user, url):
if user_info:
_logger.section_end()
return user_info
_logger.info(f"Get user info for '{username}' from GitHub API")
user = self._gh_api.user(username=username)
user_info = user.info
_logger.section(f"Get Social Accounts")
social_accounts_info = user.social_accounts
socials = {}
user_info["socials"] = socials
Expand All @@ -325,7 +321,6 @@ def add_social(name, user, url):
match.group(1),
f"https://{base_pattern}{match.group(1)}{match.group(2)}"
)
_logger.info(f"{provider.capitalize()} account", account['url'])
break
else:
if account["provider"] != "generic":
Expand All @@ -334,11 +329,9 @@ def add_social(name, user, url):
generics = socials.setdefault("generics", [])
generics.append(account["url"])
_logger.info(f"Unknown account", account['url'])
_logger.section_end()
self._cache.set("user", username, user_info)
return user_info

@_logger.sectioner("Get Publications")
def _get_orcid_publications(self, orcid_id: str) -> list[dict]:
dois = self._cache.get("orcid", orcid_id)
if not dois:
Expand Down
Loading

0 comments on commit 48fdc33

Please sign in to comment.