ssb-project-cli 1.3.8__tar.gz → 1.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/PKG-INFO +1 -1
  2. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/pyproject.toml +10 -1
  3. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/app.py +35 -24
  4. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/build/build.py +45 -41
  5. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/build/poetry.py +50 -0
  6. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/build/temp_template_repo.py +1 -1
  7. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/create/create.py +3 -0
  8. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/create/github.py +3 -1
  9. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/create/local_repo.py +7 -2
  10. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/create/temp_git_repo.py +1 -1
  11. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/util.py +3 -3
  12. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/LICENSE +0 -0
  13. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/README.md +0 -0
  14. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/__init__.py +0 -0
  15. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/__main__.py +0 -0
  16. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/py.typed +0 -0
  17. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/__init__.py +0 -0
  18. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/build/__init__.py +0 -0
  19. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/build/environment.py +0 -0
  20. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/build/prompt.py +0 -0
  21. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/build_cmds.md +0 -0
  22. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/clean/__init__.py +0 -0
  23. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/clean/clean.py +0 -0
  24. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/create/__init__.py +0 -0
  25. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/create/prompt.py +0 -0
  26. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/create/repo_privacy.py +0 -0
  27. {ssb_project_cli-1.3.8 → ssb_project_cli-1.4.0}/src/ssb_project_cli/ssb_project/settings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ssb-project-cli
3
- Version: 1.3.8
3
+ Version: 1.4.0
4
4
  Summary: SSB Project CLI
5
5
  Home-page: https://github.com/statisticsnorway/ssb-project-cli
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "ssb-project-cli"
3
- version = "1.3.8"
3
+ version = "1.4.0"
4
4
  description = "SSB Project CLI"
5
5
  authors = ["Statistics Norway <stat-dev@ssb.no>"]
6
6
  license = "MIT"
@@ -94,6 +94,7 @@ tests = ["tests", "*/tests"]
94
94
  [tool.coverage.run]
95
95
  branch = true
96
96
  source = ["ssb_project_cli", "tests"]
97
+ relative_files = true
97
98
 
98
99
  [tool.coverage.report]
99
100
  show_missing = true
@@ -112,6 +113,14 @@ show_column_numbers = true
112
113
  show_error_codes = true
113
114
  show_error_context = true
114
115
 
116
+ [[tool.mypy.overrides]]
117
+ module = [
118
+ "attr.*",
119
+ "cruft.*",
120
+ "tomli_w.*",
121
+ ]
122
+ ignore_missing_imports = true
123
+
115
124
  [build-system]
116
125
  requires = ["poetry-core>=1.0.0"]
117
126
  build-backend = "poetry.core.masonry.api"
@@ -4,6 +4,7 @@ from pathlib import Path
4
4
 
5
5
  import typer
6
6
  from rich.console import Console
7
+ from typing_extensions import Annotated
7
8
 
8
9
  from ssb_project_cli.ssb_project.util import set_debug_logging
9
10
 
@@ -48,7 +49,7 @@ app = typer.Typer(
48
49
 
49
50
 
50
51
  @app.command()
51
- def create( # noqa: C901
52
+ def create( # noqa: C901, S107
52
53
  project_name: str = typer.Argument(..., help="Project name"), # noqa: B008
53
54
  description: str = typer.Argument( # noqa: B008
54
55
  "", help="A short description of your project"
@@ -56,29 +57,38 @@ def create( # noqa: C901
56
57
  repo_privacy: RepoPrivacy = typer.Argument( # noqa: B008
57
58
  RepoPrivacy.internal, help="Visibility of the Github repo"
58
59
  ),
59
- add_github: bool = typer.Option( # noqa: B008
60
- False,
61
- "--github",
62
- help="Create the repo on Github as well",
63
- ),
64
- github_token: str = typer.Option( # noqa: B008
65
- "",
66
- help="Your Github Personal Access Token, follow these instructions to create one: https://manual.dapla.ssb.no/git-github.html#personal-access-token-pat",
67
- ),
68
- verify_config: bool = typer.Option( # noqa: B008
69
- True,
70
- "--no-verify",
71
- help="Verify git configuration files. Use --no-verify to disable verification (defaults to True).",
72
- show_default=True,
73
- ),
74
- template_git_url: str = typer.Option( # noqa: B008
75
- STAT_TEMPLATE_REPO_URL,
76
- help="The Cookiecutter template URI.",
77
- ),
78
- checkout: t.Optional[str] = typer.Option( # noqa: B008
79
- None,
80
- help="The git reference to check against. Supports branches, tags and commit hashes.",
81
- ),
60
+ add_github: Annotated[
61
+ bool, typer.Option("--github", help="Create the repo on Github as well")
62
+ ] = False,
63
+ github_token: Annotated[
64
+ str,
65
+ typer.Option(
66
+ help="Your Github Personal Access Token, follow these instructions to create one: https://manual.dapla.ssb.no/git-github.html#personal-access-token-pat"
67
+ ),
68
+ ] = "",
69
+ verify_config: Annotated[
70
+ bool,
71
+ typer.Option(
72
+ "--no-verify",
73
+ help="Verify git configuration files. Use --no-verify to disable verification (defaults to True).",
74
+ ),
75
+ ] = True,
76
+ template_git_url: Annotated[
77
+ str, typer.Option(help="The Cookiecutter template URI.")
78
+ ] = STAT_TEMPLATE_REPO_URL,
79
+ checkout: Annotated[
80
+ t.Optional[str],
81
+ typer.Option(
82
+ help="The git reference to check against. Supports branches, tags and commit hashes.",
83
+ ),
84
+ ] = None,
85
+ no_kernel: Annotated[
86
+ bool,
87
+ typer.Option(
88
+ "--no-kernel",
89
+ help="Do not create a kernel after the project is created (defaults to False).",
90
+ ),
91
+ ] = False,
82
92
  ) -> None:
83
93
  """:sparkles: Create a project locally, and optionally on GitHub with the flag --github. The project will follow SSB's best practice for development."""
84
94
  if not checkout and template_git_url is STAT_TEMPLATE_REPO_URL:
@@ -96,6 +106,7 @@ def create( # noqa: C901
96
106
  template_git_url,
97
107
  checkout,
98
108
  verify_config,
109
+ no_kernel,
99
110
  )
100
111
 
101
112
 
@@ -9,14 +9,10 @@ from typing import List
9
9
 
10
10
  import kvakk_git_tools.validate_ssb_gitconfig # type: ignore
11
11
 
12
- from .environment import JUPYTER_IMAGE_SPEC, verify_local_config
13
- from .environment import PIP_INDEX_URL
14
- from .environment import running_onprem
12
+ from .environment import verify_local_config
15
13
  from .poetry import install_ipykernel
16
14
  from .poetry import poetry_install
17
- from .poetry import poetry_source_add
18
- from .poetry import poetry_source_includes_source_name
19
- from .poetry import poetry_source_remove
15
+ from .poetry import check_and_fix_onprem_source
20
16
  from rich import print
21
17
 
22
18
  from .prompt import confirm_fix_ssb_git_config
@@ -33,6 +29,7 @@ def build_project(
33
29
  template_repo_url: str,
34
30
  checkout: str | None,
35
31
  verify_config: bool = True,
32
+ no_kernel: bool = False,
36
33
  ) -> None:
37
34
  """Installs dependencies and kernel for a given project.
38
35
 
@@ -42,6 +39,7 @@ def build_project(
42
39
  template_repo_url: Template repository url
43
40
  checkout: The git reference to check against. Supports branches, tags and commit hashes.
44
41
  verify_config: Determines if gitconfig is verified.
42
+ no_kernel: Determines if a kernel shall be generated or not.
45
43
  """
46
44
  if path is None:
47
45
  project_directory = working_directory
@@ -57,45 +55,51 @@ def build_project(
57
55
  sys.exit()
58
56
 
59
57
  if verify_config:
60
- try:
61
- valid_global_git_config = kvakk_git_tools.validate_git_config()
62
- except FileExistsError:
63
- # If gitconfig does not exist the configuration is invalid
64
- valid_global_git_config = False
65
- valid_project_git_config = verify_local_config(
66
- template_repo_url,
67
- checkout,
68
- cwd=str(project_root),
58
+ validate_and_fix_git_config(
59
+ template_repo_url, checkout, project_name, project_root
69
60
  )
70
- if not valid_global_git_config or not valid_project_git_config:
71
- print(
72
- ":x:\tYour project's Git configuration does not follow SSB recommendations,\n:x:\twhich may result in sensitive data being pushed to GitHub."
73
- )
74
- confirm_fix_ssb_git_config(
75
- project_name,
76
- template_repo_url,
77
- checkout,
78
- project_root,
79
- valid_global_git_config,
80
- valid_project_git_config,
81
- )
82
-
83
- if running_onprem(JUPYTER_IMAGE_SPEC):
61
+
62
+ check_and_fix_onprem_source(project_root)
63
+
64
+ poetry_install(project_root)
65
+ if not no_kernel:
66
+ install_ipykernel(project_root, project_name)
67
+ ipykernel_attach_bashrc(project_name)
68
+
69
+
70
+ def validate_and_fix_git_config(
71
+ template_repo_url: str, checkout: str | None, project_name: str, project_root: Path
72
+ ) -> None:
73
+ """Validate and fix the git config.
74
+
75
+ Args:
76
+ template_repo_url: Template repository url
77
+ checkout: The git reference to check against. Supports branches, tags and commit hashes.
78
+ project_name: The name of the project
79
+ project_root: The root directory of the project/repo.
80
+ """
81
+ try:
82
+ valid_global_git_config = kvakk_git_tools.validate_git_config()
83
+ except FileExistsError:
84
+ # If gitconfig does not exist the configuration is invalid
85
+ valid_global_git_config = False
86
+ valid_project_git_config = verify_local_config(
87
+ template_repo_url,
88
+ checkout,
89
+ cwd=str(project_root),
90
+ )
91
+ if not valid_global_git_config or not valid_project_git_config:
84
92
  print(
85
- ":twisted_rightwards_arrows:\tDetected onprem environment, using proxy for package installation"
93
+ ":x:\tYour project's Git configuration does not follow SSB recommendations,\n:x:\twhich may result in sensitive data being pushed to GitHub."
86
94
  )
87
- if poetry_source_includes_source_name(project_root):
88
- poetry_source_remove(project_root, lock_update=False)
89
- poetry_source_add(PIP_INDEX_URL, project_root)
90
- elif poetry_source_includes_source_name(project_root):
91
- print(
92
- ":twisted_rightwards_arrows:\tDetected non-onprem environment, removing proxy for package installation"
95
+ confirm_fix_ssb_git_config(
96
+ project_name,
97
+ template_repo_url,
98
+ checkout,
99
+ project_root,
100
+ valid_global_git_config,
101
+ valid_project_git_config,
93
102
  )
94
- poetry_source_remove(project_root)
95
-
96
- poetry_install(project_root)
97
- install_ipykernel(project_root, project_name)
98
- ipykernel_attach_bashrc(project_name)
99
103
 
100
104
 
101
105
  def ipykernel_attach_bashrc(project_name: str) -> None:
@@ -8,6 +8,9 @@ from rich import print
8
8
 
9
9
  from .environment import NEXUS_SOURCE_NAME
10
10
  from ssb_project_cli.ssb_project.util import execute_command
11
+ from .environment import JUPYTER_IMAGE_SPEC
12
+ from .environment import PIP_INDEX_URL
13
+ from .environment import running_onprem
11
14
 
12
15
 
13
16
  def poetry_install(project_directory: Path) -> None:
@@ -35,6 +38,33 @@ def poetry_install(project_directory: Path) -> None:
35
38
  )
36
39
 
37
40
 
41
+ def poetry_update_lockfile_dependencies(project_directory: Path) -> None:
42
+ """Call poetry update --lock in project_directory.
43
+
44
+ Update the lock file dependencies without installing packages.
45
+
46
+ Args:
47
+ project_directory: Path of project
48
+ """
49
+ with Progress(
50
+ SpinnerColumn(),
51
+ TextColumn("[progress.description]{task.description}"),
52
+ transient=True,
53
+ ) as progress:
54
+ progress.add_task(
55
+ description="Updating lock file dependencies... This may take some time.",
56
+ total=None,
57
+ )
58
+
59
+ execute_command(
60
+ "poetry update --lock".split(" "),
61
+ "poetry-update-lock-deps",
62
+ ":white_check_mark:\tUpdated lock file dependencies",
63
+ "Error: Something went wrong when updating lock file dependencies with Poetry.",
64
+ project_directory,
65
+ )
66
+
67
+
38
68
  def poetry_source_includes_source_name(
39
69
  cwd: Path, source_name: str = NEXUS_SOURCE_NAME
40
70
  ) -> bool:
@@ -164,3 +194,23 @@ def install_ipykernel(project_directory: Path, project_name: str) -> None:
164
194
  "Something went wrong while installing ipykernel.",
165
195
  project_directory,
166
196
  )
197
+
198
+
199
+ def check_and_fix_onprem_source(project_root: Path) -> None:
200
+ """Check if running onprem and fix source in pyproject.toml if so.
201
+
202
+ Args:
203
+ project_root: Path to the root of the project
204
+ """
205
+ if running_onprem(JUPYTER_IMAGE_SPEC):
206
+ print(
207
+ ":twisted_rightwards_arrows:\tDetected onprem environment, using proxy for package installation"
208
+ )
209
+ if poetry_source_includes_source_name(project_root):
210
+ poetry_source_remove(project_root, lock_update=False)
211
+ poetry_source_add(PIP_INDEX_URL, project_root)
212
+ elif poetry_source_includes_source_name(project_root):
213
+ print(
214
+ ":twisted_rightwards_arrows:\tDetected non-onprem environment, removing proxy for package installation"
215
+ )
216
+ poetry_source_remove(project_root)
@@ -4,7 +4,7 @@ from types import TracebackType
4
4
  from typing import Optional
5
5
  from typing import Type
6
6
 
7
- from git import Repo # type: ignore[attr-defined]
7
+ from git import Repo
8
8
 
9
9
 
10
10
  class TempTemplateRepo:
@@ -36,6 +36,7 @@ def create_project( # noqa: C901
36
36
  template_repo_url: str,
37
37
  checkout: str | None,
38
38
  verify_config: bool = True,
39
+ no_kernel: bool = False,
39
40
  ) -> None:
40
41
  """Create an SSB-project.
41
42
 
@@ -51,6 +52,7 @@ def create_project( # noqa: C901
51
52
  template_repo_url: The Cookiecutter template URI.
52
53
  checkout: The git reference to check against. Supports branches, tags and commit hashes.
53
54
  verify_config: Determines if gitconfig is verified.
55
+ no_kernel: Determines if a kernel shall be generated or not.
54
56
  """
55
57
  is_memory_full()
56
58
 
@@ -105,6 +107,7 @@ def create_project( # noqa: C901
105
107
  template_repo_url,
106
108
  checkout,
107
109
  verify_config,
110
+ no_kernel,
108
111
  )
109
112
 
110
113
  git_repo_dir = Path(working_directory.joinpath(project_name))
@@ -40,7 +40,7 @@ def create_github(
40
40
  try:
41
41
  # Ignoring mypy warning: Unexpected keyword argument "visibility"
42
42
  # for "create_repo" of "Organization" [call-arg]
43
- g.get_organization(github_org_name).create_repo( # type: ignore
43
+ g.get_organization(github_org_name).create_repo(
44
44
  repo_name,
45
45
  visibility=repo_privacy,
46
46
  auto_init=False,
@@ -207,6 +207,8 @@ def set_branch_protection_rules(
207
207
  required_approving_review_count=1,
208
208
  dismiss_stale_reviews=True,
209
209
  enforce_admins=True,
210
+ # Need to supply the line under as a workaround until PyGithub is updated to v2
211
+ users_bypass_pull_request_allowances=[],
210
212
  )
211
213
 
212
214
 
@@ -6,10 +6,12 @@ from datetime import datetime
6
6
  from pathlib import Path
7
7
  from typing import Optional
8
8
 
9
- import cruft # type: ignore[import]
10
- from git import Repo # type: ignore[attr-defined]
9
+ import cruft
10
+ from git import Repo
11
11
  from rich import print
12
12
 
13
+ from ssb_project_cli.ssb_project.build.poetry import check_and_fix_onprem_source
14
+ from ssb_project_cli.ssb_project.build.poetry import poetry_update_lockfile_dependencies
13
15
  from ssb_project_cli.ssb_project.create import temp_git_repo
14
16
  from ssb_project_cli.ssb_project.create.github import (
15
17
  get_environment_specific_github_object,
@@ -71,6 +73,9 @@ def create_project_from_template(
71
73
  no_input=(template_repo_url == STAT_TEMPLATE_REPO_URL),
72
74
  extra_context=template_info,
73
75
  )
76
+ project_root = project_dir / project_name
77
+ check_and_fix_onprem_source(project_root)
78
+ poetry_update_lockfile_dependencies(project_root)
74
79
 
75
80
  return project_dir
76
81
 
@@ -3,7 +3,7 @@ from types import TracebackType
3
3
  from typing import Optional
4
4
  from typing import Type
5
5
 
6
- from git import Repo # type: ignore[attr-defined]
6
+ from git import Repo
7
7
 
8
8
 
9
9
  class TempGitRemote:
@@ -16,7 +16,7 @@ from rich import print
16
16
  from .settings import HOME_PATH
17
17
 
18
18
 
19
- kernelspec_manager = jupyter_client.kernelspec.KernelSpecManager() # type: ignore[no-untyped-call]
19
+ kernelspec_manager = jupyter_client.kernelspec.KernelSpecManager()
20
20
 
21
21
 
22
22
  def set_debug_logging(home_path: Path = HOME_PATH) -> None:
@@ -109,12 +109,12 @@ def get_kernels_dict() -> dict[str, dict[str, str]]:
109
109
  Returns:
110
110
  kernel_dict: Dictionary of installed kernel specifications
111
111
  """
112
- return kernelspec_manager.get_all_specs() # type: ignore
112
+ return kernelspec_manager.get_all_specs()
113
113
 
114
114
 
115
115
  def remove_kernel_spec(kernel_name: str) -> None:
116
116
  """Remove a kernel spec."""
117
- kernelspec_manager.remove_kernel_spec(kernel_name) # type: ignore[no-untyped-call]
117
+ kernelspec_manager.remove_kernel_spec(kernel_name)
118
118
 
119
119
 
120
120
  def get_project_name_and_root_path(
File without changes