daktari 0.0.300__tar.gz → 0.0.306__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 (77) hide show
  1. {daktari-0.0.300/daktari.egg-info → daktari-0.0.306}/PKG-INFO +5 -5
  2. {daktari-0.0.300 → daktari-0.0.306}/README.md +1 -1
  3. daktari-0.0.306/daktari/__init__.py +1 -0
  4. daktari-0.0.306/daktari/checks/npmrc.py +126 -0
  5. daktari-0.0.306/daktari/checks/pnpm.py +14 -0
  6. daktari-0.0.306/daktari/checks/test_npmrc.py +161 -0
  7. daktari-0.0.306/daktari/checks/test_pnpm.py +25 -0
  8. {daktari-0.0.300 → daktari-0.0.306/daktari.egg-info}/PKG-INFO +5 -5
  9. {daktari-0.0.300 → daktari-0.0.306}/daktari.egg-info/SOURCES.txt +4 -0
  10. {daktari-0.0.300 → daktari-0.0.306}/daktari.egg-info/requires.txt +3 -3
  11. {daktari-0.0.300 → daktari-0.0.306}/pyproject.toml +1 -1
  12. {daktari-0.0.300 → daktari-0.0.306}/requirements.txt +3 -3
  13. daktari-0.0.300/daktari/__init__.py +0 -1
  14. {daktari-0.0.300 → daktari-0.0.306}/LICENSE.txt +0 -0
  15. {daktari-0.0.300 → daktari-0.0.306}/MANIFEST.in +0 -0
  16. {daktari-0.0.300 → daktari-0.0.306}/daktari/__main__.py +0 -0
  17. {daktari-0.0.300 → daktari-0.0.306}/daktari/asdf.py +0 -0
  18. {daktari-0.0.300 → daktari-0.0.306}/daktari/check.py +0 -0
  19. {daktari-0.0.300 → daktari-0.0.306}/daktari/check_runner.py +0 -0
  20. {daktari-0.0.300 → daktari-0.0.306}/daktari/check_sorter.py +0 -0
  21. {daktari-0.0.300 → daktari-0.0.306}/daktari/check_utils.py +0 -0
  22. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/__init__.py +0 -0
  23. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/android.py +0 -0
  24. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/aws.py +0 -0
  25. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/certs.py +0 -0
  26. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/conan.py +0 -0
  27. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/direnv.py +0 -0
  28. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/docker.py +0 -0
  29. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/etc_hosts.py +0 -0
  30. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/files.py +0 -0
  31. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/flutter.py +0 -0
  32. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/git.py +0 -0
  33. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/google.py +0 -0
  34. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/intellij_idea.py +0 -0
  35. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/java.py +0 -0
  36. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/kubernetes.py +0 -0
  37. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/misc.py +0 -0
  38. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/nodejs.py +0 -0
  39. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/onepassword.py +0 -0
  40. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/python.py +0 -0
  41. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/ssh.py +0 -0
  42. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/terraform.py +0 -0
  43. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/test_certs.py +0 -0
  44. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/test_intellij_idea.py +0 -0
  45. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/test_java.py +0 -0
  46. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/test_misc.py +0 -0
  47. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/test_onepassword.py +0 -0
  48. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/test_ssh.py +0 -0
  49. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/test_yarn.py +0 -0
  50. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/xml.py +0 -0
  51. {daktari-0.0.300 → daktari-0.0.306}/daktari/checks/yarn.py +0 -0
  52. {daktari-0.0.300 → daktari-0.0.306}/daktari/collection_utils.py +0 -0
  53. {daktari-0.0.300 → daktari-0.0.306}/daktari/command_utils.py +0 -0
  54. {daktari-0.0.300 → daktari-0.0.306}/daktari/config.py +0 -0
  55. {daktari-0.0.300 → daktari-0.0.306}/daktari/file_utils.py +0 -0
  56. {daktari-0.0.300 → daktari-0.0.306}/daktari/options.py +0 -0
  57. {daktari-0.0.300 → daktari-0.0.306}/daktari/os.py +0 -0
  58. {daktari-0.0.300 → daktari-0.0.306}/daktari/resource_utils.py +0 -0
  59. {daktari-0.0.300 → daktari-0.0.306}/daktari/resources/__init__.py +0 -0
  60. {daktari-0.0.300 → daktari-0.0.306}/daktari/resources/daktari-local-template.yaml +0 -0
  61. {daktari-0.0.300 → daktari-0.0.306}/daktari/resources/mock_cert.pem +0 -0
  62. {daktari-0.0.300 → daktari-0.0.306}/daktari/result_printer.py +0 -0
  63. {daktari-0.0.300 → daktari-0.0.306}/daktari/test_asdf.py +0 -0
  64. {daktari-0.0.300 → daktari-0.0.306}/daktari/test_check.py +0 -0
  65. {daktari-0.0.300 → daktari-0.0.306}/daktari/test_check_factory.py +0 -0
  66. {daktari-0.0.300 → daktari-0.0.306}/daktari/test_check_runner.py +0 -0
  67. {daktari-0.0.300 → daktari-0.0.306}/daktari/test_check_sorter.py +0 -0
  68. {daktari-0.0.300 → daktari-0.0.306}/daktari/test_check_utils.py +0 -0
  69. {daktari-0.0.300 → daktari-0.0.306}/daktari/test_collection_utils.py +0 -0
  70. {daktari-0.0.300 → daktari-0.0.306}/daktari/test_config.py +0 -0
  71. {daktari-0.0.300 → daktari-0.0.306}/daktari/test_result_printer.py +0 -0
  72. {daktari-0.0.300 → daktari-0.0.306}/daktari/test_version_utils.py +0 -0
  73. {daktari-0.0.300 → daktari-0.0.306}/daktari/version_utils.py +0 -0
  74. {daktari-0.0.300 → daktari-0.0.306}/daktari.egg-info/dependency_links.txt +0 -0
  75. {daktari-0.0.300 → daktari-0.0.306}/daktari.egg-info/entry_points.txt +0 -0
  76. {daktari-0.0.300 → daktari-0.0.306}/daktari.egg-info/top_level.txt +0 -0
  77. {daktari-0.0.300 → daktari-0.0.306}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: daktari
3
- Version: 0.0.300
3
+ Version: 0.0.306
4
4
  Summary: Assist in setting up and maintaining developer environments
5
5
  Author-email: Matt Russell <matthew.russell@sonocent.com>
6
6
  License: Copyright 2021 Sonocent Ltd
@@ -18,8 +18,8 @@ Requires-Dist: ansicolors==1.1.8
18
18
  Requires-Dist: distro==1.9.0
19
19
  Requires-Dist: pyfiglet==1.0.4
20
20
  Requires-Dist: importlib_resources==6.5.2
21
- Requires-Dist: packaging==25.0
22
- Requires-Dist: setuptools==80.9.0
21
+ Requires-Dist: packaging==26.0
22
+ Requires-Dist: setuptools==80.10.2
23
23
  Requires-Dist: requests==2.32.5
24
24
  Requires-Dist: responses==0.25.8
25
25
  Requires-Dist: semver==3.0.4
@@ -33,7 +33,7 @@ Requires-Dist: dpath==2.2.0
33
33
  Requires-Dist: pyOpenSSL==25.3.0
34
34
  Requires-Dist: types-pyOpenSSL==24.1.0.20240722
35
35
  Requires-Dist: pyclip==0.7.0
36
- Requires-Dist: urllib3==2.6.2
36
+ Requires-Dist: urllib3==2.6.3
37
37
  Dynamic: license-file
38
38
 
39
39
  **Daktari** is a tool to help the initial setup and ongoing maintenance of developer environments. It runs a series of checks (for example, that required software is installed) and provides suggestions on how to fix the issue if the check fails.
@@ -45,7 +45,7 @@ In the root of the project repository, create a `.daktari.py` configuration file
45
45
  ```python
46
46
  from daktari.checks.git import *
47
47
 
48
- version = "0.0.300"
48
+ version = "0.0.306"
49
49
  title = "My Project"
50
50
 
51
51
  checks = [
@@ -7,7 +7,7 @@ In the root of the project repository, create a `.daktari.py` configuration file
7
7
  ```python
8
8
  from daktari.checks.git import *
9
9
 
10
- version = "0.0.300"
10
+ version = "0.0.306"
11
11
  title = "My Project"
12
12
 
13
13
  checks = [
@@ -0,0 +1 @@
1
+ __version__ = "0.0.306"
@@ -0,0 +1,126 @@
1
+ import logging
2
+ import os
3
+ from dataclasses import dataclass
4
+ from typing import List, Optional
5
+ from urllib.parse import urlparse
6
+
7
+ from daktari.check import Check, CheckResult
8
+ from daktari.command_utils import can_run_command
9
+ from daktari.file_utils import file_exists
10
+ from daktari.os import OS
11
+
12
+ PLACEHOLDER_TOKEN = "UPDATE_WITH_TOKEN"
13
+
14
+
15
+ @dataclass
16
+ class NpmrcScope:
17
+ name: str
18
+ registry: str
19
+ require_auth_token: bool = False
20
+
21
+
22
+ def get_npmrc_path() -> str:
23
+ return os.path.expanduser("~/.npmrc")
24
+
25
+
26
+ def get_npmrc_contents() -> List[str]:
27
+ npmrc_path = get_npmrc_path()
28
+ if not file_exists(npmrc_path):
29
+ raise Exception(f"{npmrc_path} does not exist")
30
+
31
+ try:
32
+ with open(npmrc_path, "r") as npmrc_file:
33
+ return npmrc_file.readlines()
34
+ except Exception:
35
+ logging.error(f"Exception reading {npmrc_path}", exc_info=True)
36
+ raise Exception("Failed to read npmrc")
37
+
38
+
39
+ def get_registry_host(registry_url: str) -> str:
40
+ parsed = urlparse(registry_url)
41
+ return parsed.netloc
42
+
43
+
44
+ def npmrc_contains_scope_registry(lines: List[str], scope: NpmrcScope) -> bool:
45
+ expected_line = f"@{scope.name}:registry={scope.registry}"
46
+ for line in lines:
47
+ if line.strip() == expected_line:
48
+ return True
49
+ return False
50
+
51
+
52
+ def npmrc_contains_auth_token(lines: List[str], registry_url: str) -> bool:
53
+ host = get_registry_host(registry_url)
54
+ auth_token_prefix = f"//{host}/:_authToken="
55
+ for line in lines:
56
+ stripped = line.strip()
57
+ if stripped.startswith(auth_token_prefix):
58
+ token_value = stripped[len(auth_token_prefix) :]
59
+ if token_value and token_value != PLACEHOLDER_TOKEN:
60
+ return True
61
+ return False
62
+
63
+
64
+ def npmrc_scope_is_configured(lines: List[str], scope: NpmrcScope) -> bool:
65
+ if not npmrc_contains_scope_registry(lines, scope):
66
+ return False
67
+ if scope.require_auth_token and not npmrc_contains_auth_token(lines, scope.registry):
68
+ return False
69
+ return True
70
+
71
+
72
+ def get_npmrc_suggestion(scope: NpmrcScope) -> str:
73
+ lines = [f"@{scope.name}:registry={scope.registry}"]
74
+ if scope.require_auth_token:
75
+ host = get_registry_host(scope.registry)
76
+ lines.append(f"//{host}/:_authToken={PLACEHOLDER_TOKEN}")
77
+ return "\n".join(lines)
78
+
79
+
80
+ class NpmrcScopeConfigured(Check):
81
+ name = "npmrc.scopeConfigured"
82
+
83
+ def __init__(self, scope: NpmrcScope, token_instructions: Optional[str] = None):
84
+ self.scope = scope
85
+ self.npmrc_suggestion = get_npmrc_suggestion(scope)
86
+ token_instruction_string = f"\n\n{token_instructions}" if token_instructions else ""
87
+ self.suggestions = {
88
+ OS.GENERIC: f"""Add the lines below to ~/.npmrc:
89
+
90
+ {self.npmrc_suggestion}{token_instruction_string}"""
91
+ }
92
+
93
+ def check(self) -> CheckResult:
94
+ try:
95
+ lines = get_npmrc_contents()
96
+ except Exception as e:
97
+ return self.failed(str(e))
98
+
99
+ if not npmrc_scope_is_configured(lines, self.scope):
100
+ return self.failed(f"Scope {self.scope.name} not configured in npmrc")
101
+
102
+ return self.passed(f"Scope {self.scope.name} configured in npmrc")
103
+
104
+
105
+ class NpmrcGithubTokenValid(Check):
106
+ name = "npmrc.githubTokenValid"
107
+ depends_on = [NpmrcScopeConfigured]
108
+
109
+ def __init__(self, scope_name: str, test_package: str):
110
+ self.scope_name = scope_name
111
+ self.test_package = test_package
112
+ self.suggestions = {
113
+ OS.GENERIC: "Please check the token was copied correctly from GitHub."
114
+ " Ensure the token hasn't expired, or has been revoked."
115
+ " Also, ensure it has the correct permissions to read packages."
116
+ }
117
+
118
+ def check(self) -> CheckResult:
119
+ package_spec = f"@{self.scope_name}/{self.test_package}"
120
+ command = f"npm view {package_spec} version"
121
+ logging.debug(f"Checking npm registry access with: {command}")
122
+
123
+ if can_run_command(command):
124
+ return self.passed(f"GitHub npm token is valid (can access {package_spec})")
125
+ else:
126
+ return self.failed(f"GitHub npm token is not valid (cannot access {package_spec})")
@@ -0,0 +1,14 @@
1
+ from daktari.check import Check, CheckResult
2
+ from daktari.os import OS
3
+
4
+
5
+ class PnpmInstalled(Check):
6
+ name = "pnpm.installed"
7
+
8
+ suggestions = {
9
+ OS.OS_X: "<cmd>brew install pnpm</cmd>",
10
+ OS.GENERIC: "<cmd>npm install -g pnpm</cmd>",
11
+ }
12
+
13
+ def check(self) -> CheckResult:
14
+ return self.verify_install("pnpm")
@@ -0,0 +1,161 @@
1
+ import unittest
2
+ from unittest import mock
3
+
4
+ from daktari.check import CheckStatus
5
+ from daktari.checks.npmrc import (
6
+ NpmrcScope,
7
+ NpmrcScopeConfigured,
8
+ NpmrcGithubTokenValid,
9
+ get_registry_host,
10
+ npmrc_contains_scope_registry,
11
+ npmrc_contains_auth_token,
12
+ npmrc_scope_is_configured,
13
+ get_npmrc_suggestion,
14
+ )
15
+
16
+ TEST_SCOPE_NAME = "my-org"
17
+ TEST_REGISTRY = "https://npm.pkg.github.com"
18
+ TEST_REGISTRY_HOST = "npm.pkg.github.com"
19
+ TEST_AUTH_TOKEN = "ghp_abc123xyz"
20
+
21
+
22
+ class TestNpmrcHelpers(unittest.TestCase):
23
+ def test_get_registry_host(self):
24
+ self.assertEqual(get_registry_host("https://npm.pkg.github.com"), "npm.pkg.github.com")
25
+ self.assertEqual(get_registry_host("https://registry.npmjs.org"), "registry.npmjs.org")
26
+ self.assertEqual(get_registry_host("https://npm.example.com/custom/path"), "npm.example.com")
27
+
28
+ def test_npmrc_contains_scope_registry_matching(self):
29
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY)
30
+ lines = [
31
+ f"@{TEST_SCOPE_NAME}:registry={TEST_REGISTRY}\n",
32
+ f"//{TEST_REGISTRY_HOST}/:_authToken={TEST_AUTH_TOKEN}\n",
33
+ ]
34
+ self.assertTrue(npmrc_contains_scope_registry(lines, scope))
35
+
36
+ def test_npmrc_contains_scope_registry_not_matching(self):
37
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY)
38
+ lines = [
39
+ "@other-scope:registry=https://registry.npmjs.org\n",
40
+ ]
41
+ self.assertFalse(npmrc_contains_scope_registry(lines, scope))
42
+
43
+ def test_npmrc_contains_scope_registry_empty_lines(self):
44
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY)
45
+ lines = []
46
+ self.assertFalse(npmrc_contains_scope_registry(lines, scope))
47
+
48
+ def test_npmrc_contains_auth_token_matching(self):
49
+ lines = [
50
+ f"@{TEST_SCOPE_NAME}:registry={TEST_REGISTRY}\n",
51
+ f"//{TEST_REGISTRY_HOST}/:_authToken={TEST_AUTH_TOKEN}\n",
52
+ ]
53
+ self.assertTrue(npmrc_contains_auth_token(lines, TEST_REGISTRY))
54
+
55
+ def test_npmrc_contains_auth_token_not_matching(self):
56
+ lines = [
57
+ f"@{TEST_SCOPE_NAME}:registry={TEST_REGISTRY}\n",
58
+ "//registry.npmjs.org/:_authToken=some-token\n",
59
+ ]
60
+ self.assertFalse(npmrc_contains_auth_token(lines, TEST_REGISTRY))
61
+
62
+ def test_npmrc_contains_auth_token_placeholder_rejected(self):
63
+ lines = [
64
+ f"//{TEST_REGISTRY_HOST}/:_authToken=UPDATE_WITH_TOKEN\n",
65
+ ]
66
+ self.assertFalse(npmrc_contains_auth_token(lines, TEST_REGISTRY))
67
+
68
+ def test_npmrc_contains_auth_token_empty_rejected(self):
69
+ lines = [
70
+ f"//{TEST_REGISTRY_HOST}/:_authToken=\n",
71
+ ]
72
+ self.assertFalse(npmrc_contains_auth_token(lines, TEST_REGISTRY))
73
+
74
+ def test_npmrc_scope_is_configured_without_auth(self):
75
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY, require_auth_token=False)
76
+ lines = [
77
+ f"@{TEST_SCOPE_NAME}:registry={TEST_REGISTRY}\n",
78
+ ]
79
+ self.assertTrue(npmrc_scope_is_configured(lines, scope))
80
+
81
+ def test_npmrc_scope_is_configured_with_auth_present(self):
82
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY, require_auth_token=True)
83
+ lines = [
84
+ f"@{TEST_SCOPE_NAME}:registry={TEST_REGISTRY}\n",
85
+ f"//{TEST_REGISTRY_HOST}/:_authToken={TEST_AUTH_TOKEN}\n",
86
+ ]
87
+ self.assertTrue(npmrc_scope_is_configured(lines, scope))
88
+
89
+ def test_npmrc_scope_is_configured_with_auth_missing(self):
90
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY, require_auth_token=True)
91
+ lines = [
92
+ f"@{TEST_SCOPE_NAME}:registry={TEST_REGISTRY}\n",
93
+ ]
94
+ self.assertFalse(npmrc_scope_is_configured(lines, scope))
95
+
96
+ def test_npmrc_scope_is_configured_registry_missing(self):
97
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY)
98
+ lines = [
99
+ f"//{TEST_REGISTRY_HOST}/:_authToken={TEST_AUTH_TOKEN}\n",
100
+ ]
101
+ self.assertFalse(npmrc_scope_is_configured(lines, scope))
102
+
103
+ def test_get_npmrc_suggestion_without_auth(self):
104
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY, require_auth_token=False)
105
+ suggestion = get_npmrc_suggestion(scope)
106
+ self.assertEqual(suggestion, f"@{TEST_SCOPE_NAME}:registry={TEST_REGISTRY}")
107
+
108
+ def test_get_npmrc_suggestion_with_auth(self):
109
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY, require_auth_token=True)
110
+ suggestion = get_npmrc_suggestion(scope)
111
+ expected = f"@{TEST_SCOPE_NAME}:registry={TEST_REGISTRY}\n//{TEST_REGISTRY_HOST}/:_authToken=UPDATE_WITH_TOKEN"
112
+ self.assertEqual(suggestion, expected)
113
+
114
+
115
+ class TestNpmrcScopeConfigured(unittest.TestCase):
116
+ @mock.patch("daktari.checks.npmrc.get_npmrc_contents")
117
+ def test_returns_pass_when_scope_configured(self, mock_get_contents):
118
+ mock_get_contents.return_value = [
119
+ f"@{TEST_SCOPE_NAME}:registry={TEST_REGISTRY}\n",
120
+ f"//{TEST_REGISTRY_HOST}/:_authToken={TEST_AUTH_TOKEN}\n",
121
+ ]
122
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY, require_auth_token=True)
123
+ result = NpmrcScopeConfigured(scope).check()
124
+ self.assertEqual(result.status, CheckStatus.PASS)
125
+
126
+ @mock.patch("daktari.checks.npmrc.get_npmrc_contents")
127
+ def test_returns_fail_when_scope_not_configured(self, mock_get_contents):
128
+ mock_get_contents.return_value = [
129
+ "@other-scope:registry=https://registry.npmjs.org\n",
130
+ ]
131
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY)
132
+ result = NpmrcScopeConfigured(scope).check()
133
+ self.assertEqual(result.status, CheckStatus.FAIL)
134
+
135
+ @mock.patch("daktari.checks.npmrc.get_npmrc_contents")
136
+ def test_returns_fail_when_file_not_found(self, mock_get_contents):
137
+ mock_get_contents.side_effect = Exception("~/.npmrc does not exist")
138
+ scope = NpmrcScope(name=TEST_SCOPE_NAME, registry=TEST_REGISTRY)
139
+ result = NpmrcScopeConfigured(scope).check()
140
+ self.assertEqual(result.status, CheckStatus.FAIL)
141
+ self.assertIn("does not exist", result.summary)
142
+
143
+
144
+ class TestNpmrcGithubTokenValid(unittest.TestCase):
145
+ @mock.patch("daktari.checks.npmrc.can_run_command")
146
+ def test_returns_pass_when_token_valid(self, mock_can_run):
147
+ mock_can_run.return_value = True
148
+ result = NpmrcGithubTokenValid(scope_name=TEST_SCOPE_NAME, test_package="some-package").check()
149
+ self.assertEqual(result.status, CheckStatus.PASS)
150
+ mock_can_run.assert_called_once_with(f"npm view @{TEST_SCOPE_NAME}/some-package version")
151
+
152
+ @mock.patch("daktari.checks.npmrc.can_run_command")
153
+ def test_returns_fail_when_token_invalid(self, mock_can_run):
154
+ mock_can_run.return_value = False
155
+ result = NpmrcGithubTokenValid(scope_name=TEST_SCOPE_NAME, test_package="some-package").check()
156
+ self.assertEqual(result.status, CheckStatus.FAIL)
157
+ mock_can_run.assert_called_once_with(f"npm view @{TEST_SCOPE_NAME}/some-package version")
158
+
159
+
160
+ if __name__ == "__main__":
161
+ unittest.main()
@@ -0,0 +1,25 @@
1
+ import unittest
2
+ from unittest import mock
3
+
4
+ from daktari.check import CheckStatus
5
+ from daktari.checks.pnpm import PnpmInstalled
6
+
7
+
8
+ class TestPnpm(unittest.TestCase):
9
+ @mock.patch("daktari.check.can_run_command")
10
+ def test_pnpm_installed_returns_pass_when_installed(self, mock_can_run_command):
11
+ mock_can_run_command.return_value = True
12
+ result = PnpmInstalled().check()
13
+ self.assertEqual(result.status, CheckStatus.PASS)
14
+ mock_can_run_command.assert_called_once_with("pnpm --version")
15
+
16
+ @mock.patch("daktari.check.can_run_command")
17
+ def test_pnpm_installed_returns_fail_when_not_installed(self, mock_can_run_command):
18
+ mock_can_run_command.return_value = False
19
+ result = PnpmInstalled().check()
20
+ self.assertEqual(result.status, CheckStatus.FAIL)
21
+ mock_can_run_command.assert_called_once_with("pnpm --version")
22
+
23
+
24
+ if __name__ == "__main__":
25
+ unittest.main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: daktari
3
- Version: 0.0.300
3
+ Version: 0.0.306
4
4
  Summary: Assist in setting up and maintaining developer environments
5
5
  Author-email: Matt Russell <matthew.russell@sonocent.com>
6
6
  License: Copyright 2021 Sonocent Ltd
@@ -18,8 +18,8 @@ Requires-Dist: ansicolors==1.1.8
18
18
  Requires-Dist: distro==1.9.0
19
19
  Requires-Dist: pyfiglet==1.0.4
20
20
  Requires-Dist: importlib_resources==6.5.2
21
- Requires-Dist: packaging==25.0
22
- Requires-Dist: setuptools==80.9.0
21
+ Requires-Dist: packaging==26.0
22
+ Requires-Dist: setuptools==80.10.2
23
23
  Requires-Dist: requests==2.32.5
24
24
  Requires-Dist: responses==0.25.8
25
25
  Requires-Dist: semver==3.0.4
@@ -33,7 +33,7 @@ Requires-Dist: dpath==2.2.0
33
33
  Requires-Dist: pyOpenSSL==25.3.0
34
34
  Requires-Dist: types-pyOpenSSL==24.1.0.20240722
35
35
  Requires-Dist: pyclip==0.7.0
36
- Requires-Dist: urllib3==2.6.2
36
+ Requires-Dist: urllib3==2.6.3
37
37
  Dynamic: license-file
38
38
 
39
39
  **Daktari** is a tool to help the initial setup and ongoing maintenance of developer environments. It runs a series of checks (for example, that required software is installed) and provides suggestions on how to fix the issue if the check fails.
@@ -45,7 +45,7 @@ In the root of the project repository, create a `.daktari.py` configuration file
45
45
  ```python
46
46
  from daktari.checks.git import *
47
47
 
48
- version = "0.0.300"
48
+ version = "0.0.306"
49
49
  title = "My Project"
50
50
 
51
51
  checks = [
@@ -52,7 +52,9 @@ daktari/checks/java.py
52
52
  daktari/checks/kubernetes.py
53
53
  daktari/checks/misc.py
54
54
  daktari/checks/nodejs.py
55
+ daktari/checks/npmrc.py
55
56
  daktari/checks/onepassword.py
57
+ daktari/checks/pnpm.py
56
58
  daktari/checks/python.py
57
59
  daktari/checks/ssh.py
58
60
  daktari/checks/terraform.py
@@ -60,7 +62,9 @@ daktari/checks/test_certs.py
60
62
  daktari/checks/test_intellij_idea.py
61
63
  daktari/checks/test_java.py
62
64
  daktari/checks/test_misc.py
65
+ daktari/checks/test_npmrc.py
63
66
  daktari/checks/test_onepassword.py
67
+ daktari/checks/test_pnpm.py
64
68
  daktari/checks/test_ssh.py
65
69
  daktari/checks/test_yarn.py
66
70
  daktari/checks/xml.py
@@ -2,8 +2,8 @@ ansicolors==1.1.8
2
2
  distro==1.9.0
3
3
  pyfiglet==1.0.4
4
4
  importlib_resources==6.5.2
5
- packaging==25.0
6
- setuptools==80.9.0
5
+ packaging==26.0
6
+ setuptools==80.10.2
7
7
  requests==2.32.5
8
8
  responses==0.25.8
9
9
  semver==3.0.4
@@ -15,7 +15,7 @@ dpath==2.2.0
15
15
  pyOpenSSL==25.3.0
16
16
  types-pyOpenSSL==24.1.0.20240722
17
17
  pyclip==0.7.0
18
- urllib3==2.6.2
18
+ urllib3==2.6.3
19
19
 
20
20
  [:sys_platform == "darwin"]
21
21
  pyobjc-core==12.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "daktari"
7
- version = "0.0.300"
7
+ version = "0.0.306"
8
8
  description = "Assist in setting up and maintaining developer environments"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE.txt" }
@@ -2,8 +2,8 @@ ansicolors==1.1.8
2
2
  distro==1.9.0
3
3
  pyfiglet==1.0.4
4
4
  importlib_resources==6.5.2
5
- packaging==25.0
6
- setuptools==80.9.0
5
+ packaging==26.0
6
+ setuptools==80.10.2
7
7
  requests==2.32.5
8
8
  responses==0.25.8
9
9
  semver==3.0.4
@@ -17,4 +17,4 @@ dpath==2.2.0
17
17
  pyOpenSSL==25.3.0
18
18
  types-pyOpenSSL==24.1.0.20240722
19
19
  pyclip==0.7.0
20
- urllib3==2.6.2
20
+ urllib3==2.6.3
@@ -1 +0,0 @@
1
- __version__ = "0.0.300"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes