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.
- bmsdna/devtools/__init__.py +0 -0
- bmsdna/devtools/ado_auth.py +37 -0
- bmsdna/devtools/app_service_logs.py +76 -0
- bmsdna/devtools/cli.py +138 -0
- bmsdna/devtools/cli_tools.py +31 -0
- bmsdna/devtools/commit.py +204 -0
- bmsdna/devtools/env_config.py +61 -0
- bmsdna/devtools/gh_pr.py +140 -0
- bmsdna/devtools/gitrepo.py +123 -0
- bmsdna/devtools/logs.py +170 -0
- bmsdna/devtools/pr_build.py +206 -0
- bmsdna/devtools/skills/bmsdna-devtools/SKILL.md +111 -0
- bmsdna/devtools/worktree.py +49 -0
- bmsdna_devtools-0.2.0.dist-info/METADATA +143 -0
- bmsdna_devtools-0.2.0.dist-info/RECORD +17 -0
- bmsdna_devtools-0.2.0.dist-info/WHEEL +4 -0
- bmsdna_devtools-0.2.0.dist-info/entry_points.txt +2 -0
|
@@ -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,,
|