bmsdna-devtools 0.2.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.
@@ -0,0 +1,111 @@
1
+ ---
2
+ name: bmsdna-devtools
3
+ description: >
4
+ Use the `bdt` CLI (from the bmsdna-devtools package) instead of ad hoc git/az/gh
5
+ commands or repo-local scripts for: checking PR build/check status, creating
6
+ a PR, creating a git worktree, committing and pushing files (with pre-flight
7
+ checks), and querying Azure logs. `bdt pr *` works against both Azure DevOps
8
+ and GitHub — it auto-detects which one from the `origin` remote. Trigger
9
+ whenever the user asks to check a build/PR status, create a PR, make a
10
+ worktree, commit changes, or fetch/tail application logs in a repo that has
11
+ bmsdna-devtools installed (check for `bdt` on PATH, or `bmsdna-devtools` in
12
+ pyproject.toml, before assuming it applies).
13
+ ---
14
+
15
+ # bmsdna-devtools — shared BMS developer tooling
16
+
17
+ A single `bdt` CLI replacing the near-duplicate `get_pr_build.py`,
18
+ `commit.py`, and `just worktree`/`just pr-main` recipes that used to be
19
+ copy-pasted across OneSales, ccmt2, and MDMApp. Install with
20
+ `uv tool install bmsdna-devtools` (global) or `uv add bmsdna-devtools`
21
+ (per-project).
22
+
23
+ `bdt pr *` auto-detects Azure DevOps vs. GitHub from the `origin` remote and
24
+ shells out to `az`/`gh` accordingly — you don't need to pick a backend
25
+ yourself, and there's no need to fall back to raw `gh pr create`/`gh pr
26
+ checks` for a GitHub-hosted repo, `bdt pr *` covers that too. Each external
27
+ CLI (`az`, `gh`) is only required for the commands that actually need it,
28
+ and is checked lazily with a clear "not found, install it here" error
29
+ rather than a raw traceback — if you see that error, tell the user which
30
+ CLI to install rather than trying to work around it.
31
+
32
+ ## Checking PR build/check status
33
+
34
+ ```bash
35
+ bdt pr status [--target-branch main] [--wait]
36
+ ```
37
+
38
+ Finds the PR opened from the current branch and prints build/check status,
39
+ inlining failed-step logs. `--wait` polls until everything finishes (use
40
+ this after pushing, instead of guessing when CI is done). Exits non-zero if
41
+ anything failed — safe to gate a script on. If the PR has merge conflicts
42
+ (or, on Azure DevOps, failed/was rejected by policy), that's reported
43
+ immediately instead of waiting for builds that will never run — check the
44
+ error message for `mergeStatus=conflicts` (ADO) or `mergeable=CONFLICTING`
45
+ (GitHub) and tell the user to resolve conflicts rather than assuming CI is
46
+ just slow.
47
+
48
+ `--target-branch` only applies on Azure DevOps (its search API needs one to
49
+ find the right PR); on GitHub, `gh pr view` always resolves the PR for the
50
+ current branch regardless, so the flag is ignored there — the PR's actual
51
+ base branch is shown in the output instead.
52
+
53
+ Auth: Azure DevOps works with no setup if the caller is already `az
54
+ login`'d (only pass `--pat`/`AZURE_DEVOPS_PAT` if there's no `az` session
55
+ available); GitHub uses whatever `gh auth login` session is active.
56
+
57
+ ## Creating a PR
58
+
59
+ ```bash
60
+ bdt pr create --target main # or --target test
61
+ ```
62
+
63
+ Uses the current branch as source. On Azure DevOps this wraps `az repos pr
64
+ create`; on GitHub, `gh pr create --fill` (autofills title/body from commit
65
+ info, so it never blocks waiting on an interactive prompt). Extra args pass
66
+ straight through either way, e.g.
67
+ `bdt pr create --target main -- --title "..." --description "..."`.
68
+
69
+ ## Creating a worktree
70
+
71
+ ```bash
72
+ bdt worktree <name> [--base dev] [--install "just install"]
73
+ ```
74
+
75
+ Creates `.worktrees/<name>`, inits submodules if `.gitmodules` exists,
76
+ copies an env file in (auto-detects `.local_env` then `.env`), and runs
77
+ `--install` inside the new worktree if given. Prefer this over raw
78
+ `git worktree add` so env-file copying and submodule init aren't forgotten.
79
+
80
+ ## Committing and pushing
81
+
82
+ ```bash
83
+ bdt commit "feat(x): add widget support" file1.py file2.py
84
+ ```
85
+
86
+ Use this instead of raw `git commit && git push` in any repo where it's
87
+ the established convention (check the repo's AGENTS.md/CLAUDE.md — several
88
+ BMS repos mandate it). It runs pre-flight checks (files exist, message
89
+ looks like `type: description`, not on `main`/`master`) and retries once
90
+ if a pre-commit hook reformats files. Pass `--json` when calling
91
+ programmatically from an agent loop — the schema is documented in
92
+ `bdt commit --help`. Pass `--subrepo database` (repeatable) for repos that
93
+ vendor a git submodule under that path.
94
+
95
+ ## Application Insights logs
96
+
97
+ ```bash
98
+ bdt logs roles --resource-group <rg> --app-insights <name> --minutes 60
99
+ bdt logs tail --resource-group <rg> --app-insights <name> --role <role> --level warning
100
+ ```
101
+
102
+ `logs roles` lists which `cloud_RoleName`s have recent traffic — run this
103
+ first if you don't already know the role name to filter `logs tail` by.
104
+ No defaults are baked in (unlike the other commands, this can't infer
105
+ anything from the git remote) — always pass `--resource-group`/`--app-insights`
106
+ or set `AZURE_RESOURCE_GROUP`/`AZURE_APP_INSIGHTS`.
107
+
108
+ For "what broke recently" without a KQL query, `bdt logs fetch --webapp
109
+ <name> --resource-group <rg> --slot <slot>` downloads the App Service log
110
+ archive and extracts error/warning lines to `logs/<slot>_errors.log` —
111
+ often the faster path when you don't need a filterable trace stream.
@@ -0,0 +1,49 @@
1
+ """Create a git worktree for a new branch, mirroring the `just worktree` recipes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import shutil
6
+ import subprocess
7
+ import sys
8
+ from pathlib import Path
9
+
10
+
11
+ def _run(cmd: list[str], cwd: Path) -> None:
12
+ try:
13
+ subprocess.run(cmd, cwd=cwd, check=True)
14
+ except FileNotFoundError:
15
+ sys.exit(f"'{cmd[0]}' is required for this command but wasn't found on PATH.")
16
+
17
+
18
+ def create(
19
+ name: str,
20
+ base: str = "dev",
21
+ env_file: str | None = None,
22
+ submodules: bool = True,
23
+ install_cmd: list[str] | None = None,
24
+ root: Path | None = None,
25
+ ) -> Path:
26
+ root = root or Path.cwd()
27
+ path = root / ".worktrees" / name
28
+ if path.exists():
29
+ sys.exit(f"error: {path} already exists")
30
+
31
+ _run(["git", "worktree", "add", str(path), "-b", name, base], cwd=root)
32
+
33
+ if submodules and (root / ".gitmodules").exists():
34
+ _run(["git", "submodule", "update", "--init"], cwd=path)
35
+
36
+ if env_file is None:
37
+ for candidate in (".local_env", ".env"):
38
+ if (root / candidate).exists():
39
+ env_file = candidate
40
+ break
41
+
42
+ if env_file and (root / env_file).exists():
43
+ shutil.copy(root / env_file, path / ".env")
44
+
45
+ if install_cmd:
46
+ _run(install_cmd, cwd=path)
47
+
48
+ print(f"worktree ready at {path}")
49
+ return path
@@ -0,0 +1,143 @@
1
+ Metadata-Version: 2.4
2
+ Name: bmsdna-devtools
3
+ Version: 0.2.0
4
+ Summary: Shared Azure DevOps / GitHub / git / Azure Monitor developer tooling for BMS projects
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: requests>=2.32.0
7
+ Requires-Dist: rich>=13.0.0
8
+ Requires-Dist: typer>=0.26.7
9
+ Description-Content-Type: text/markdown
10
+
11
+ # bmsdna-devtools
12
+
13
+ Shared developer tooling for BMS projects: PR build/check status, PR
14
+ creation, git worktrees, a commit-and-push helper with pre-flight checks,
15
+ and Azure log queries. `bdt pr *` auto-detects whether the current repo's
16
+ `origin` remote is Azure DevOps or GitHub and uses `az`/`gh` accordingly.
17
+ Consolidates near-duplicate scripts that used to be copy-pasted across
18
+ OneSales, ccmt2, and MDMApp into one versioned package with a `bdt` CLI.
19
+
20
+ Requires `git` always, plus `az` (Azure DevOps commands, and all `bdt logs`
21
+ commands) and/or `gh` (GitHub commands) on PATH as needed — each is checked
22
+ lazily, only when a command actually needs it, with a clear error and an
23
+ install link if missing rather than a raw traceback. Works on Windows: CLI
24
+ shims (e.g. `az.cmd`) are resolved via `shutil.which` (which honors
25
+ `PATHEXT`) rather than shelling out, output is decoded as UTF-8 rather than
26
+ relying on the console's default codepage, and file arguments accept either
27
+ slash style.
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ uv tool install bmsdna-devtools
33
+ ```
34
+
35
+ Or as a project dependency: `uv add bmsdna-devtools`.
36
+
37
+ ## `bdt pr status`
38
+
39
+ Find the PR opened from the current branch and report build/check status
40
+ (failed steps print their logs inline). Works against Azure DevOps or
41
+ GitHub — whichever `origin` points at.
42
+
43
+ ```bash
44
+ bdt pr status [--target-branch main] [--wait]
45
+ ```
46
+
47
+ If the PR can't be merged, that's reported immediately instead of polling
48
+ for builds/checks that will never run — e.g. on Azure DevOps:
49
+ `PR #42 ('feat: widgets') has merge conflicts with the target branch (mergeStatus=conflicts)`;
50
+ on GitHub: `PR #42 ('feat: widgets') has merge conflicts with 'main' (mergeable=CONFLICTING)`.
51
+ Exit code 1 either way.
52
+
53
+ **Azure DevOps**: org/project/repo are auto-detected from
54
+ `git remote get-url origin` (handles SSH, `dev.azure.com` HTTPS, and
55
+ `*.visualstudio.com` HTTPS forms). Auth is an explicit PAT (`--pat` or
56
+ `AZURE_DEVOPS_PAT` env var), falling back to a short-lived token from the
57
+ caller's own `az login` — never embed a PAT literal in a script or CI file.
58
+ `--target-branch` selects which PR to look at (ADO's search API needs one).
59
+
60
+ **GitHub**: uses `gh`'s own auth (`gh auth login`) and always resolves the
61
+ PR opened from the current branch — `gh pr view` has no target-branch
62
+ filter, so `--target-branch` is ignored here; the PR's actual base branch
63
+ is shown in the output. Check status is computed from
64
+ `gh pr view --json statusCheckRollup` rather than `gh pr checks --json`,
65
+ since the latter flag isn't available in all `gh` releases.
66
+
67
+ ## `bdt pr create`
68
+
69
+ ```bash
70
+ bdt pr create --target main # or --target test
71
+ ```
72
+
73
+ Creates a PR from the current branch into `--target`. On Azure DevOps,
74
+ a thin wrapper around `az repos pr create` (org/project/repo inferred by
75
+ `az` itself from the git remote). On GitHub, `gh pr create --fill` (autofills
76
+ title/body from commit info so it never blocks on an interactive prompt).
77
+ Extra arguments pass through either way, e.g.
78
+ `bdt pr create --target main -- --title "..."`.
79
+
80
+ ## `bdt worktree`
81
+
82
+ ```bash
83
+ bdt worktree my-feature [--base dev] [--env-file .local_env] [--no-submodules] [--install "just install"]
84
+ ```
85
+
86
+ Creates `.worktrees/<name>` branched from `--base`, initializes submodules
87
+ (unless `--no-submodules`), and copies an env file into the new worktree as
88
+ `.env` (auto-detects `.local_env` then `.env` if `--env-file` isn't given).
89
+
90
+ ## `bdt commit`
91
+
92
+ ```bash
93
+ bdt commit "feat(x): add widget support" file1.py file2.py [--json] [--no-verify] [--subrepo database]
94
+ ```
95
+
96
+ Stages, commits, and pushes the given files. Pre-flight checks: files
97
+ exist, commit message looks like `type: description` (skip with
98
+ `--skip-message-check`), not on `main`/`master` (skip with `--allow-main`).
99
+ Retries once (re-`git add`) if a pre-commit hook reformats files. Pass
100
+ `--subrepo <dir>` (repeatable) for repos that vendor a submodule (e.g.
101
+ `database`) — files under that prefix are committed/pushed inside the
102
+ submodule first, then the bump is staged in the parent repo.
103
+
104
+ Set `IS_BMS_AI_SANDBOX=1` to skip the push step (commit only) — used when
105
+ an AI coding sandbox pushes on its own schedule separately.
106
+
107
+ `--json` emits a machine-readable result for AI-agent callers:
108
+
109
+ ```json
110
+ {
111
+ "success": true, "committed": true, "pushed": true,
112
+ "message": "...", "files": ["..."], "commit_sha": "abc1234",
113
+ "error": null, "hint": null
114
+ }
115
+ ```
116
+
117
+ ## `bdt logs roles` / `bdt logs tail`
118
+
119
+ Query Application Insights (KQL over `traces`/`exceptions`) via
120
+ `az monitor app-insights query`. No defaults are baked in — pass
121
+ `--resource-group`/`--app-insights` explicitly (or set
122
+ `AZURE_RESOURCE_GROUP`/`AZURE_APP_INSIGHTS`), since which Azure resource
123
+ "this repo" maps to isn't derivable from the git remote.
124
+
125
+ ```bash
126
+ bdt logs roles --resource-group my-rg --app-insights my-app-insights --minutes 60
127
+ bdt logs tail --resource-group my-rg --app-insights my-app-insights --role my-service --level warning
128
+ ```
129
+
130
+ ## `bdt logs fetch`
131
+
132
+ Downloads the App Service log archive for a webapp/slot via
133
+ `az webapp log download`, unzips it, and writes every line matching a
134
+ common error/warning marker (`ERROR`, `CRITICAL`, `WARNING`, tracebacks,
135
+ `4xx`/`5xx`, `FAILED`, `FATAL`) to `<out>/<slot>_errors.log`. Simpler and
136
+ often preferable to the KQL commands above when you just want "what broke
137
+ recently" rather than a queryable trace stream — no defaults are baked in
138
+ here either.
139
+
140
+ ```bash
141
+ bdt logs fetch --webapp my-webapp --resource-group my-rg --slot production
142
+ bdt logs fetch --webapp my-webapp --resource-group my-rg --slot production --out logs/ --keep-archive
143
+ ```
@@ -0,0 +1,17 @@
1
+ bmsdna/devtools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ bmsdna/devtools/ado_auth.py,sha256=w2CQx6Rz8YaDpRhGn_qi0YJw7w8KHqo6HnXz1DBKIYg,1269
3
+ bmsdna/devtools/app_service_logs.py,sha256=hbF8Rc7oA7IEXDCJ6I6E_cGmiGPtqv4kLL2sVazbrWE,2475
4
+ bmsdna/devtools/cli.py,sha256=38tKLcy-yNVQksK64oyRQ25iGgZ6YpyWkSHp_fvscOQ,6489
5
+ bmsdna/devtools/cli_tools.py,sha256=uGvVUiIPKt0YUvvH8Sz-4SHgzz_g8tmO-poGZk5QTEg,1047
6
+ bmsdna/devtools/commit.py,sha256=1AtqNPApOQ0F3Ani9LdVpRVXGGpYYV1r-BlKfcqdfxY,7843
7
+ bmsdna/devtools/env_config.py,sha256=QpAkwRsdrPqEP7YQHlxLDVHmhbDmw0spSDnB-Xsagsk,1900
8
+ bmsdna/devtools/gh_pr.py,sha256=TXb0ZHb5ZEp6LH91_n8cb90xBc5KVGLZJvhJh3ZnIXo,4657
9
+ bmsdna/devtools/gitrepo.py,sha256=EbcCLjkAslAnk8ofJB3uh2Gv4MlxRxF7D0g6N0o10Vs,3920
10
+ bmsdna/devtools/logs.py,sha256=sNKqMF4XcvydMHheRcsLJkRemNBqey7NskljzVcKorY,6393
11
+ bmsdna/devtools/pr_build.py,sha256=EJxwc88sf0Y7Qg44QQo80VX0IZaGCETHs_EFxcTaE-I,7995
12
+ bmsdna/devtools/worktree.py,sha256=mbfmnFtTleidAO4hiPGJ9zJpbfsvLL1qZsvYfpwBmmU,1339
13
+ bmsdna/devtools/skills/bmsdna-devtools/SKILL.md,sha256=fe_IQAe8TLJS1ok6mInV0GW_L9Fyr1EvJl6f0ZApnYg,5094
14
+ bmsdna_devtools-0.2.0.dist-info/METADATA,sha256=ETnKRPD80VqDhPCRsffmD7tuk17qRgLvWLHyvRzfehU,5891
15
+ bmsdna_devtools-0.2.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
16
+ bmsdna_devtools-0.2.0.dist-info/entry_points.txt,sha256=DdDUJbHPaZAI5u2kQoCXyn649vAzMLPhiTvUv-CcPNU,48
17
+ bmsdna_devtools-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ bdt = bmsdna.devtools.cli:app