devready-cli 0.1.0__py3-none-any.whl → 0.3.0__py3-none-any.whl

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.
devready/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.0"
1
+ __version__ = "0.3.0"
devready/baseline.py ADDED
@@ -0,0 +1,43 @@
1
+ """Compare a run with a saved report (`devready check --format json > baseline.json`).
2
+
3
+ DevReady only reads the baseline; saving or committing it is up to you. That covers both a
4
+ shared team baseline (committed file) and diffing against an earlier local run.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import re
11
+ from pathlib import Path
12
+
13
+ from devready.checks.project import _read
14
+ from devready.models import Result, Status
15
+
16
+ _ID = re.compile(r"^[a-z_]+(\.[a-z_]+)+$")
17
+ _RANK = {Status.PASS: 0, Status.SKIP: 0, Status.WARN: 1, Status.ERROR: 2, Status.FAIL: 3}
18
+
19
+
20
+ def load_baseline(path: Path) -> dict[str, Status] | None:
21
+ """check_id -> status, or None if the file is missing, too big, or not a v1 report."""
22
+ text = _read(path)
23
+ try:
24
+ data = json.loads(text) if text else None
25
+ if data["schema_version"] != 1:
26
+ return None
27
+ return {
28
+ r["check_id"]: Status(r["status"])
29
+ for r in data["results"]
30
+ if isinstance(r["check_id"], str) and _ID.match(r["check_id"])
31
+ }
32
+ except (ValueError, KeyError, TypeError):
33
+ return None
34
+
35
+
36
+ def diff(results: list[Result], base: dict[str, Status]) -> tuple[list[Result], bool]:
37
+ """(results that are new or changed status, whether any FAIL got worse)."""
38
+ changed = [r for r in results if base.get(r.check_id) is not r.status]
39
+ worse = any(
40
+ r.status is Status.FAIL and _RANK[r.status] > _RANK.get(base.get(r.check_id), 0)
41
+ for r in changed
42
+ )
43
+ return changed, worse
@@ -0,0 +1,102 @@
1
+ """Optional `.devready.json`: extra requirements, required env var names, checks to skip.
2
+
3
+ {"skip": ["project.ports"], "require": {"node": ">=20", "python": ">=3.11"}, "env": ["API_KEY"]}
4
+
5
+ Read-only, same file rules as project.py. Env vars are tested for presence only; values are
6
+ never read. Invalid files give one ERROR result and never echo file content.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import os
13
+ import re
14
+ from collections.abc import Mapping
15
+ from pathlib import Path
16
+
17
+ from devready.checks.project import _compare, _read
18
+ from devready.models import Result, Status
19
+ from devready.versions import SAFE_SPEC, parse_version
20
+
21
+ CONFIG_FILE = ".devready.json"
22
+ _ID = re.compile(r"^[a-z_]+(\.[a-z_]+)*$")
23
+ _ENV_NAME = re.compile(r"^[A-Za-z_][A-Za-z0-9_]{0,63}$")
24
+ _RUNTIMES = {"node": "Node", "python": "Python"}
25
+
26
+
27
+ def _valid(cfg: object) -> bool:
28
+ if not isinstance(cfg, dict) or not set(cfg) <= {"skip", "require", "env"}:
29
+ return False
30
+ skip, req, env = cfg.get("skip", []), cfg.get("require", {}), cfg.get("env", [])
31
+ return (
32
+ isinstance(skip, list)
33
+ and all(isinstance(i, str) and _ID.match(i) for i in skip)
34
+ and isinstance(req, dict)
35
+ and all(
36
+ k in _RUNTIMES and isinstance(v, str) and SAFE_SPEC.match(v) for k, v in req.items()
37
+ )
38
+ and isinstance(env, list)
39
+ and all(isinstance(n, str) and _ENV_NAME.match(n) for n in env)
40
+ )
41
+
42
+
43
+ def load_config(root: Path) -> tuple[dict | None, Result | None]:
44
+ """(config, None) if absent/valid ({} when absent), (None, error result) if invalid."""
45
+ text = _read(root / CONFIG_FILE)
46
+ if text is None:
47
+ return {}, None
48
+ try:
49
+ cfg = json.loads(text)
50
+ except ValueError:
51
+ cfg = None
52
+ if _valid(cfg):
53
+ return cfg, None
54
+ return None, Result(
55
+ "project.config.file",
56
+ "Config",
57
+ Status.ERROR,
58
+ f"{CONFIG_FILE} is invalid; it was ignored",
59
+ 'Allowed keys: "skip" (check ids), "require" (node/python specs), "env" (variable names).',
60
+ )
61
+
62
+
63
+ def check_config(
64
+ cfg: dict, node: str | None, python: str | None, environ: Mapping[str, str] = os.environ
65
+ ) -> list[Result]:
66
+ out: list[Result] = []
67
+ versions = {
68
+ "node": parse_version(node) if node else None,
69
+ "python": parse_version(python or ""),
70
+ }
71
+ for key, spec in cfg.get("require", {}).items():
72
+ out.append(
73
+ _compare(
74
+ f"project.{key}.config",
75
+ f"{_RUNTIMES[key]} required",
76
+ CONFIG_FILE,
77
+ spec,
78
+ versions[key],
79
+ Status.FAIL,
80
+ )
81
+ )
82
+ wanted = cfg.get("env", [])
83
+ if wanted:
84
+ missing = [n for n in wanted if n not in environ]
85
+ cid, title = "project.env.required", "Required env"
86
+ if missing:
87
+ out.append(
88
+ Result(
89
+ cid,
90
+ title,
91
+ Status.FAIL,
92
+ f"{len(missing)} of {len(wanted)} not set: {', '.join(missing[:10])}",
93
+ "Set these variables in your shell or CI (values are never read).",
94
+ )
95
+ )
96
+ else:
97
+ out.append(Result(cid, title, Status.PASS, f"all {len(wanted)} variables are set"))
98
+ return out
99
+
100
+
101
+ # Empty on purpose: pre-filling "env" from .env.example would make optional variables fail.
102
+ TEMPLATE = json.dumps({"skip": [], "require": {}, "env": []}, indent=2)
@@ -0,0 +1,108 @@
1
+ """OS-specific pain points, each checked only when the project makes it relevant.
2
+
3
+ Windows: long paths, PowerShell execution policy (blocks npm.ps1), git line endings.
4
+ macOS/Linux: a compiler toolchain when the project looks like it builds native code.
5
+ Read-only; fixed argv only.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import shutil
11
+ import sys
12
+ from collections.abc import Callable
13
+ from pathlib import Path
14
+
15
+ from devready.checks.extras import _run
16
+ from devready.models import Result, Status
17
+
18
+ NATIVE_HINTS = ("binding.gyp", "setup.py", "Gemfile", "Cargo.toml")
19
+ BLOCKING_POLICIES = {"Restricted", "AllSigned"}
20
+ KNOWN_POLICIES = BLOCKING_POLICIES | {"RemoteSigned", "Unrestricted", "Bypass", "Undefined"}
21
+
22
+
23
+ def _long_paths_enabled() -> bool | None:
24
+ try:
25
+ import winreg
26
+
27
+ with winreg.OpenKey(
28
+ winreg.HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\FileSystem"
29
+ ) as key:
30
+ return bool(winreg.QueryValueEx(key, "LongPathsEnabled")[0])
31
+ except (ImportError, OSError):
32
+ return None
33
+
34
+
35
+ def _windows(root: Path, run: Callable, which: Callable, long_paths: Callable) -> list[Result]:
36
+ out: list[Result] = []
37
+ if (root / "package.json").is_file():
38
+ if long_paths() is False:
39
+ out.append(
40
+ Result(
41
+ "platform.long_paths",
42
+ "Long paths",
43
+ Status.WARN,
44
+ "Windows long path support is off; deep node_modules trees can fail",
45
+ "Enable LongPathsEnabled (administrator) and git's core.longpaths.",
46
+ )
47
+ )
48
+ ps = which("powershell")
49
+ p = (
50
+ run([ps, "-NoProfile", "-NonInteractive", "-Command", "Get-ExecutionPolicy"])
51
+ if ps
52
+ else None
53
+ )
54
+ policy = p.stdout.strip() if p is not None and p.returncode == 0 else ""
55
+ if policy in BLOCKING_POLICIES:
56
+ out.append(
57
+ Result(
58
+ "platform.exec_policy",
59
+ "PowerShell policy",
60
+ Status.WARN,
61
+ f"PowerShell policy is {policy}; npm/pnpm .ps1 scripts will be blocked",
62
+ "Use cmd, or allow local scripts for your user: "
63
+ "Set-ExecutionPolicy -Scope CurrentUser RemoteSigned",
64
+ )
65
+ )
66
+ git = which("git")
67
+ if git and (root / ".git").exists() and not (root / ".gitattributes").is_file():
68
+ p = run([git, "-C", str(root), "config", "--get", "core.autocrlf"])
69
+ if p is not None and not p.stdout.strip():
70
+ out.append(
71
+ Result(
72
+ "platform.autocrlf",
73
+ "Line endings",
74
+ Status.WARN,
75
+ "core.autocrlf is unset and the repo has no .gitattributes",
76
+ "Add a .gitattributes with line-ending rules, or set core.autocrlf.",
77
+ )
78
+ )
79
+ return out
80
+
81
+
82
+ def _build_tools(root: Path, plat: str, run: Callable, which: Callable) -> list[Result]:
83
+ if not any((root / n).is_file() for n in NATIVE_HINTS):
84
+ return []
85
+ cid, title = "platform.build_tools", "Build tools"
86
+ if plat == "darwin":
87
+ xs = which("xcode-select")
88
+ p = run([xs, "-p"]) if xs else None
89
+ ok = p is not None and p.returncode == 0
90
+ fix = "Install the Xcode Command Line Tools: xcode-select --install"
91
+ else:
92
+ ok = any(which(c) for c in ("cc", "gcc", "clang")) and bool(which("make"))
93
+ fix = "Install a C compiler and make (for example your distro's build-essential)."
94
+ if ok:
95
+ return [Result(cid, title, Status.PASS, "compiler toolchain found")]
96
+ return [Result(cid, title, Status.WARN, "no compiler toolchain found for native builds", fix)]
97
+
98
+
99
+ def check_platform(
100
+ root: Path,
101
+ plat: str = sys.platform,
102
+ run: Callable = _run,
103
+ which: Callable = shutil.which,
104
+ long_paths: Callable = _long_paths_enabled,
105
+ ) -> list[Result]:
106
+ if plat == "win32":
107
+ return _windows(root, run, which, long_paths)
108
+ return _build_tools(root, plat, run, which)
@@ -11,7 +11,7 @@ import re
11
11
  from pathlib import Path
12
12
 
13
13
  from devready.models import Result, Status
14
- from devready.versions import SAFE_SPEC, Version, parse_version, satisfies
14
+ from devready.versions import Version, parse_version, satisfies
15
15
 
16
16
  MAX_BYTES = 1_000_000
17
17
 
@@ -25,7 +25,8 @@ def _read(path: Path) -> str | None:
25
25
  def _compare(
26
26
  check_id: str, title: str, source: str, spec: str, installed: Version | None, miss: Status
27
27
  ) -> Result:
28
- shown = spec if SAFE_SPEC.match(spec) else "(unrecognized)"
28
+ # Echo only specs the matcher fully parses: plain words can pass SAFE_SPEC but are not versions.
29
+ shown = spec if satisfies((0, 0, 0), spec) is not None else "(unrecognized)"
29
30
  if installed is None:
30
31
  return Result(check_id, title, Status.SKIP, f"{source} wants {shown}; tool not found")
31
32
  ok = satisfies(installed, spec)
devready/cli.py CHANGED
@@ -6,26 +6,26 @@ import sys
6
6
  from pathlib import Path
7
7
 
8
8
  from devready import __version__
9
+ from devready.baseline import diff, load_baseline
9
10
  from devready.formats import fix_plan, junit, sarif
10
11
  from devready.models import Result, Status
11
- from devready.runner import report, run_checks
12
+ from devready.runner import matches, report, run_checks
12
13
 
13
14
  EXIT_OK, EXIT_FAILED, EXIT_USAGE, EXIT_INTERNAL = 0, 1, 2, 3
14
15
 
15
16
 
16
17
  def _text(results: list[Result]) -> str:
17
18
  lines = ["DevReady - Environment Check", ""]
18
- lines += [f"[{r.status.value.upper():<5}] {r.title:<12} {r.summary}" for r in results]
19
+ for r in results:
20
+ lines.append(f"[{r.status.value.upper():<5}] {r.title:<12} {r.summary}")
21
+ if r.status is not Status.PASS and r.suggestion:
22
+ lines.append(f" {r.suggestion}")
19
23
  lines += ["", "No changes were made to your system."]
20
24
  return "\n".join(lines)
21
25
 
22
26
 
23
- def _matches(check_id: str, ids: list[str]) -> bool:
24
- return any(check_id == i or check_id.startswith(i + ".") for i in ids)
25
-
26
-
27
27
  def _selected(check_id: str, only: list[str], skip: list[str]) -> bool:
28
- return (not only or _matches(check_id, only)) and not _matches(check_id, skip)
28
+ return (not only or matches(check_id, only)) and not matches(check_id, skip)
29
29
 
30
30
 
31
31
  def main(argv: list[str] | None = None) -> int:
@@ -34,10 +34,14 @@ def main(argv: list[str] | None = None) -> int:
34
34
  sub = parser.add_subparsers(dest="command", required=True)
35
35
  check = sub.add_parser("check", help="run read-only environment checks")
36
36
  check.add_argument("--format", choices=["text", "json", "junit", "sarif"], default="text")
37
+ check.add_argument(
38
+ "--baseline", metavar="FILE", help="saved --format json report; show only what changed"
39
+ )
37
40
  fix = sub.add_parser("fix", help="print suggested fixes (never runs them)")
38
41
  fix.add_argument("--plan", action="store_true", help="required: list steps without running")
39
42
  explain = sub.add_parser("explain", help="explain what a check id means")
40
43
  explain.add_argument("check_id")
44
+ sub.add_parser("init", help="print a starter .devready.json (does not write it)")
41
45
  sub.add_parser("mcp", help="run as an MCP server over stdio")
42
46
  for p in (check, fix):
43
47
  p.add_argument("--project", default=".", help="directory whose version pins to compare")
@@ -54,6 +58,12 @@ def main(argv: list[str] | None = None) -> int:
54
58
 
55
59
  return serve()
56
60
 
61
+ if args.command == "init":
62
+ from devready.checks.config import TEMPLATE
63
+
64
+ print(TEMPLATE)
65
+ return EXIT_OK
66
+
57
67
  if args.command == "explain":
58
68
  from devready.explain import EXPLANATIONS
59
69
 
@@ -86,12 +96,24 @@ def main(argv: list[str] | None = None) -> int:
86
96
  if args.command == "fix":
87
97
  print(fix_plan(results))
88
98
  return EXIT_OK
99
+
100
+ regressed = None
101
+ if args.baseline:
102
+ base = load_baseline(Path(args.baseline))
103
+ if base is None:
104
+ print("devready: baseline is not a readable devready JSON report", file=sys.stderr)
105
+ return EXIT_USAGE
106
+ total = len(results)
107
+ results, regressed = diff(results, base)
108
+ print(f"Compared with baseline: {len(results)} of {total} changed.", file=sys.stderr)
89
109
  if args.format == "json":
90
110
  print(json.dumps(report(results), indent=2))
91
111
  elif args.format in ("junit", "sarif"):
92
112
  print(junit(results) if args.format == "junit" else sarif(results))
93
113
  else:
94
114
  print(_text(results))
115
+ if regressed is not None: # with a baseline only a new or worse FAIL breaks the build
116
+ return EXIT_FAILED if regressed else EXIT_OK
95
117
  return EXIT_FAILED if any(r.status is Status.FAIL for r in results) else EXIT_OK
96
118
 
97
119
 
devready/explain.py CHANGED
@@ -43,4 +43,12 @@ EXPLANATIONS = {
43
43
  "project.env.ignored": "Warns when .env exists but git would commit it (not ignored, or already tracked). Values are never shown.",
44
44
  "project.node.modules": "Checked when package.json lists dependencies: node_modules must exist and not be older than a lockfile.",
45
45
  "project.ports.free": "Ports declared in compose files (host side) or *PORT= lines in .env.example, tested by connecting to localhost. A busy port may be this project already running.",
46
+ "project.config.file": ".devready.json is optional. With unknown keys or invalid values it is ignored entirely. Run `devready init` for a starter.",
47
+ "project.node.config": "require.node in .devready.json is a hard requirement (fails when unmet).",
48
+ "project.python.config": "require.python in .devready.json is a hard requirement (fails when unmet).",
49
+ "project.env.required": "Variable NAMES listed under env in .devready.json must be set in the environment. Values are never read.",
50
+ "platform.long_paths": "Windows only, when package.json exists. Without LongPathsEnabled, deeply nested node_modules paths can exceed 260 characters and installs fail.",
51
+ "platform.exec_policy": "Windows only, when package.json exists. A Restricted or AllSigned PowerShell policy blocks npm.ps1 ('running scripts is disabled'). Use cmd or relax the policy for your user.",
52
+ "platform.autocrlf": "Windows only, in a git repo without .gitattributes. Unset core.autocrlf can flip line endings between Windows and Linux/macOS contributors.",
53
+ "platform.build_tools": "macOS/Linux, when the project has binding.gyp, setup.py, Gemfile or Cargo.toml. Native dependencies need a compiler (Xcode CLT on macOS, cc/gcc/clang and make on Linux).",
46
54
  }
devready/runner.py CHANGED
@@ -3,8 +3,10 @@ from __future__ import annotations
3
3
  import platform
4
4
  from pathlib import Path
5
5
 
6
+ from devready.checks.config import check_config, load_config
6
7
  from devready.checks.extras import check_disk, check_docker, check_git_identity
7
8
  from devready.checks.health import check_health
9
+ from devready.checks.platform_checks import check_platform
8
10
  from devready.checks.project import check_project
9
11
  from devready.checks.python_check import check_python
10
12
  from devready.checks.runtimes import check_runtimes
@@ -12,7 +14,12 @@ from devready.checks.tools import TOOLS, check_tool
12
14
  from devready.models import Result
13
15
 
14
16
 
17
+ def matches(check_id: str, ids: list[str]) -> bool:
18
+ return any(check_id == i or check_id.startswith(i + ".") for i in ids)
19
+
20
+
15
21
  def run_checks(root: Path) -> list[Result]:
22
+ cfg, cfg_error = load_config(root)
16
23
  results = [check_python()]
17
24
  versions = {}
18
25
  for tool in TOOLS:
@@ -21,7 +28,12 @@ def run_checks(root: Path) -> list[Result]:
21
28
  results += check_git_identity()
22
29
  results += check_project(root, versions["node"], platform.python_version())
23
30
  results += check_runtimes(root) + check_health(root)
24
- return results + check_docker(root) + check_disk(root)
31
+ results += check_docker(root) + check_platform(root) + check_disk(root)
32
+ results += (
33
+ [cfg_error] if cfg_error else check_config(cfg, versions["node"], platform.python_version())
34
+ )
35
+ skip = (cfg or {}).get("skip", [])
36
+ return [r for r in results if not matches(r.check_id, skip)]
25
37
 
26
38
 
27
39
  def report(results: list[Result]) -> dict:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: devready-cli
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: A local-first, read-only CLI that checks a project's environment requirements against what is installed.
5
5
  Project-URL: Homepage, https://devready-ten.vercel.app/
6
6
  Project-URL: Repository, https://github.com/Evalogical-Inc/devReady
@@ -114,6 +114,9 @@ devready explain docker.daemon # what a check means and how to fix it
114
114
  devready check --format junit # or sarif, for CI
115
115
  devready check --only project --skip project.ports # filter by id or prefix
116
116
  devready fix --plan # suggested steps only; never runs them
117
+ devready check --format json > baseline.json # save a snapshot (commit it for a team baseline)
118
+ devready check --baseline baseline.json # show only what changed; fail only on new/worse failures
119
+ devready init > .devready.json # optional config: skip ids, require node/python, required env names
117
120
  devready mcp # run as an MCP server over stdio
118
121
  devready --version
119
122
  ```
@@ -190,7 +193,7 @@ args = ["--from", "devready-cli", "devready", "mcp"]
190
193
  - Environment variable values are never read into output. Nothing leaves your machine.
191
194
  - A passing report does **not** guarantee your project builds.
192
195
 
193
- See [SECURITY.md](SECURITY.md) to report a vulnerability.
196
+ See [docs/security.md](docs/security.md) for the model, [docs/versioning.md](docs/versioning.md) for what stays stable, [docs/checks.md](docs/checks.md) for every check, and [SECURITY.md](SECURITY.md) to report a vulnerability.
194
197
 
195
198
  ## Limitations (alpha)
196
199
 
@@ -202,7 +205,8 @@ See [SECURITY.md](SECURITY.md) to report a vulnerability.
202
205
 
203
206
  - [x] Docker CLI + daemon reachability, `.tool-versions`, `.env` key-name diff, disk space, git identity, `devready explain`
204
207
  - [x] Port-in-use checks, more ecosystems (Go, Rust, Java, Ruby, .NET, pnpm/yarn/bun), JUnit/SARIF output, `fix --plan`, GitHub Action
205
- - [ ] Config file, shared baseline (see [ROADMAP.md](ROADMAP.md))
208
+ - [x] `.devready.json` config, `--baseline` snapshots
209
+ - [ ] Platform-specific checks (see [ROADMAP.md](ROADMAP.md))
206
210
  - [ ] Standalone binaries
207
211
 
208
212
  Have a setup problem DevReady should catch? [Open an issue](https://github.com/Evalogical-Inc/devReady/issues/new/choose). Early feedback shapes the roadmap.
@@ -1,21 +1,24 @@
1
- devready/__init__.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
1
+ devready/__init__.py,sha256=VrXpHDu3erkzwl_WXrqINBm9xWkcyUy53IQOj042dOs,22
2
2
  devready/__main__.py,sha256=c-4qpm2SKZs1nENGzSnPnChNTo8iMwjY0XaPyAApn4I,60
3
- devready/cli.py,sha256=OucYELHjvcFY2qw96Kc6yi4lp1RX9GnSif3MlelJ3ks,3787
4
- devready/explain.py,sha256=UbYKUdfdVsITUtuFIvG4vJ21SP8GI-HNPKh9xp6LCRE,4641
3
+ devready/baseline.py,sha256=pfVzZ695bLEiSWKUBK0PNDp1S2UWTWj9lfUCDAsVS4g,1524
4
+ devready/cli.py,sha256=oetC_jJlXk4SlyB_oKqi5XYwDouFBjeT5Ya9vUmSfXc,4736
5
+ devready/explain.py,sha256=zVRUNzqtVdO-EcC6rUCLPuwswbMlo59xzncCBiSvi1M,5889
5
6
  devready/formats.py,sha256=akN62ouKLeZQB6POcXNzINYKHwpUd4im0n2-9rtB8eE,3129
6
7
  devready/mcp_server.py,sha256=zVm89kZL_-pZwTSWkt6rxKonytNklUSa0RCQkX0lzFk,3177
7
8
  devready/models.py,sha256=KyGp3ie2LVQmuSfzLV8tbEH_hJyU5-Vi11d0JcQPAuE,646
8
- devready/runner.py,sha256=3OLWash5jGZKQM30iA1ObAzF2FTmM7STsiDD3LMO9Qs,1005
9
+ devready/runner.py,sha256=yjd7cdH0G-ksUD9viJ6coEB0iug7CazqWBQPlIW2lLU,1538
9
10
  devready/versions.py,sha256=dXKIl1-qvcfadRNaCURMoftwx7YtadDZ-YfUp-85XZc,2112
10
11
  devready/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ devready/checks/config.py,sha256=SGyIot_QXmZtPLIybtxnyJEFL2aV1NemSqX_fXbFI6A,3471
11
13
  devready/checks/extras.py,sha256=pDJbFaAwjkLc92tcFagOmj-5c_vMx32_MtYa_DBfCz8,3428
12
14
  devready/checks/health.py,sha256=woaaUL2TJ_biRuiStXqJtnvPua_y69bW2quNPlwd7tQ,4235
13
- devready/checks/project.py,sha256=UnnjuZmG2aXXBAY45wTEP-bj4CWODMv3DPfEi1V_QDE,5983
15
+ devready/checks/platform_checks.py,sha256=_ayTrJalFf4k5As0jq-t8GDh4IOMmgZJJdhKU4rIujQ,4113
16
+ devready/checks/project.py,sha256=JTeSmkuz4Z7Jy5aQnP4o4TcdhQYRZfGaGhj6f0NslXw,6090
14
17
  devready/checks/python_check.py,sha256=uQCd-N0LEwt9R5gwZm5mlYiPMST1JXVDNQOdZ5xpako,328
15
18
  devready/checks/runtimes.py,sha256=OiC5LEhmfkiMseP2PbQS6Dc6TC2JhYNICU6LmdFFvqk,4446
16
19
  devready/checks/tools.py,sha256=AiL9TdIREmY7tEkkpt62DELKuJ2lhu3XcA2yGak9QkA,1616
17
- devready_cli-0.1.0.dist-info/METADATA,sha256=jlbjbIv1omn0U0G-ZlgrrHdDMP-O33GC4tMmAJC8pdE,10176
18
- devready_cli-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
19
- devready_cli-0.1.0.dist-info/entry_points.txt,sha256=7oAecSWtsIt7qLOP8PipOeDqhXCkEJat0oxhD4T1RpY,47
20
- devready_cli-0.1.0.dist-info/licenses/LICENSE,sha256=S_AQsEw289FIsOgT-OPWL5JZeV8nn5kicwEq0r9qu7s,1071
21
- devready_cli-0.1.0.dist-info/RECORD,,
20
+ devready_cli-0.3.0.dist-info/METADATA,sha256=RV9QzIMUHmNpmJLfHQaUtAmKQybnQ97MILhHPl3Z2xs,10703
21
+ devready_cli-0.3.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
22
+ devready_cli-0.3.0.dist-info/entry_points.txt,sha256=7oAecSWtsIt7qLOP8PipOeDqhXCkEJat0oxhD4T1RpY,47
23
+ devready_cli-0.3.0.dist-info/licenses/LICENSE,sha256=S_AQsEw289FIsOgT-OPWL5JZeV8nn5kicwEq0r9qu7s,1071
24
+ devready_cli-0.3.0.dist-info/RECORD,,