bmsdna-devtools 0.43.1__tar.gz → 0.44.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.
- bmsdna_devtools-0.43.1/README.md → bmsdna_devtools-0.44.0/PKG-INFO +95 -54
- bmsdna_devtools-0.43.1/PKG-INFO → bmsdna_devtools-0.44.0/README.md +77 -71
- bmsdna_devtools-0.44.0/bmsdna/devtools/ado_auth.py +28 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/app_service_logs.py +38 -16
- bmsdna_devtools-0.44.0/bmsdna/devtools/azure_arm.py +98 -0
- bmsdna_devtools-0.44.0/bmsdna/devtools/azure_auth.py +30 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/cli.py +109 -99
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/cli_tools.py +5 -8
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/find_repo.py +87 -46
- bmsdna_devtools-0.44.0/bmsdna/devtools/gh_args.py +72 -0
- bmsdna_devtools-0.44.0/bmsdna/devtools/gh_issue.py +719 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/gh_pr.py +421 -175
- bmsdna_devtools-0.44.0/bmsdna/devtools/github_api.py +180 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/issue_do.py +4 -6
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/logs.py +39 -45
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/pr_build.py +174 -32
- bmsdna_devtools-0.44.0/bmsdna/devtools/pr_create_args.py +281 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/pyproject.toml +2 -1
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/skills/bmsdna-devtools/SKILL.md +16 -15
- bmsdna_devtools-0.44.0/tests/fake_github.py +78 -0
- bmsdna_devtools-0.44.0/tests/test_ado_auth.py +71 -0
- bmsdna_devtools-0.44.0/tests/test_app_service_logs.py +152 -0
- bmsdna_devtools-0.44.0/tests/test_azure_arm.py +136 -0
- bmsdna_devtools-0.44.0/tests/test_cli_pr_create.py +461 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_cli_pr_id.py +1 -1
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_find_repo.py +218 -104
- bmsdna_devtools-0.44.0/tests/test_gh_issue.py +722 -0
- bmsdna_devtools-0.44.0/tests/test_gh_pr.py +1320 -0
- bmsdna_devtools-0.44.0/tests/test_github_api.py +180 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_issue_do.py +7 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_issue_for_me.py +52 -52
- bmsdna_devtools-0.44.0/tests/test_logs.py +162 -0
- bmsdna_devtools-0.44.0/tests/test_pr_build_create_options.py +166 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_pr_choice.py +42 -27
- bmsdna_devtools-0.44.0/tests/test_pr_create_args.py +152 -0
- bmsdna_devtools-0.44.0/tests/test_pr_description_not_truncated.py +200 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_pr_info.py +21 -16
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/uv.lock +203 -1
- bmsdna_devtools-0.43.1/bmsdna/devtools/ado_auth.py +0 -44
- bmsdna_devtools-0.43.1/bmsdna/devtools/gh_issue.py +0 -541
- bmsdna_devtools-0.43.1/tests/test_ado_auth.py +0 -62
- bmsdna_devtools-0.43.1/tests/test_app_service_logs.py +0 -39
- bmsdna_devtools-0.43.1/tests/test_cli_pr_create.py +0 -569
- bmsdna_devtools-0.43.1/tests/test_gh_issue.py +0 -611
- bmsdna_devtools-0.43.1/tests/test_gh_pr.py +0 -1072
- bmsdna_devtools-0.43.1/tests/test_pr_description_not_truncated.py +0 -138
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/.github/workflows/auto-release.yml +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/.github/workflows/python-publish.yml +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/.github/workflows/python-test.yml +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/.gitignore +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/.python-version +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/__init__.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/_api_dump.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/ado_issue.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/agent_mentions.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/api_usage.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/bdt_config.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/commit.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/dead_code.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/env_config.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/env_files.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/find_injection.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/gitrepo.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/injection_frontend.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/injection_python.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/issue_show.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/issue_watch.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/lint.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/lint_findings.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/lint_models.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/lint_sql.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/lint_sql_files.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/lint_tooling.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/lint_typescript.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/pr_choice.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/pr_info.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/pr_issue_link.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/pr_labels.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/pr_markdown.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/pull.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/testdb.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/translate.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/__init__.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/cli.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/pipeline.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/pricing.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/report.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/sql/00_schema.sql +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/sql/01_ingest_claude.sql +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/sql/01_ingest_codex.sql +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/sql/02_messages.sql +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/sql/03_markers.sql +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/sql/04_facts.sql +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/usage/sql/05_views.sql +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/bmsdna/devtools/worktree.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/justfile +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/conftest.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_ado_issue.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_ado_issue_flow.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_agent_mentions.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_api_usage.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_bdt_config.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_cli_cleanup.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_cli_commit.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_cli_issue.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_cli_pull.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_cli_tools.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_cli_version.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_commit.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_env_config.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_env_files.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_find_injection.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_gitrepo.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_issue_show.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_issue_watch.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_lint.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_lint_models.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_lint_sql.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_lint_sql_files.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_lint_tooling.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_lint_typescript.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_pr_build.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_pr_build_flow.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_pr_issue_link.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_pr_labels.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_pr_markdown.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_pull.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_testdb.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_translate.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_usage.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_wait_timeout.py +0 -0
- {bmsdna_devtools-0.43.1 → bmsdna_devtools-0.44.0}/tests/test_worktree_clean.py +0 -0
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: bmsdna-devtools
|
|
3
|
+
Version: 0.44.0
|
|
4
|
+
Summary: Shared Azure DevOps / GitHub / git / Azure Monitor developer tooling for BMS projects
|
|
5
|
+
Requires-Python: >=3.14
|
|
6
|
+
Requires-Dist: azure-identity>=1.19.0
|
|
7
|
+
Requires-Dist: pgdevkit[db]>=0.7.1
|
|
8
|
+
Requires-Dist: requests>=2.32.0
|
|
9
|
+
Requires-Dist: rich>=13.0.0
|
|
10
|
+
Requires-Dist: tomli-w>=1.0.0
|
|
11
|
+
Requires-Dist: typer>=0.26.7
|
|
12
|
+
Provides-Extra: lint
|
|
13
|
+
Requires-Dist: sqlglot>=27.0.0; extra == 'lint'
|
|
14
|
+
Provides-Extra: usage
|
|
15
|
+
Requires-Dist: duckdb>=1.3.0; extra == 'usage'
|
|
16
|
+
Requires-Dist: plotly>=5.24.0; extra == 'usage'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
1
19
|
# bmsdna-devtools
|
|
2
20
|
|
|
3
21
|
Shared developer tooling for BMS projects: PR build/check status and a
|
|
@@ -8,16 +26,24 @@ postgres/psycopg (and arrowbricks) SQL rules, pydantic-model placement, hand-wir
|
|
|
8
26
|
TypeScript and baseline tooling, plus `bdt dead-code` for `.sql` files nothing loads and
|
|
9
27
|
backend routes nothing calls.
|
|
10
28
|
`bdt pr *` and `bdt issue *` auto-detect whether the current repo's `origin`
|
|
11
|
-
remote is Azure DevOps or GitHub and
|
|
29
|
+
remote is Azure DevOps or GitHub and call the matching REST API.
|
|
12
30
|
Consolidates near-duplicate scripts that used to be copy-pasted across
|
|
13
31
|
OneSales, ccmt2, and MDMApp into one versioned package with a `bdt` CLI.
|
|
14
32
|
|
|
15
|
-
Requires `git`
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
`
|
|
33
|
+
Requires only `git` on PATH (plus `psql` for `bdt testdb`); the `az` and `gh` CLIs are
|
|
34
|
+
**not** needed — everything talks to GitHub (REST + GraphQL), Azure DevOps and Azure
|
|
35
|
+
(ARM / Application Insights) over raw HTTP (`requests`).
|
|
36
|
+
|
|
37
|
+
Auth:
|
|
38
|
+
- **GitHub**: the `GH_TOKEN` / `GITHUB_TOKEN` environment variable, else (if `gh` happens to be
|
|
39
|
+
installed) the output of `gh auth token`. The token needs the `repo` scope, plus `project` for
|
|
40
|
+
boards and `workflow` for reruns.
|
|
41
|
+
- **Azure DevOps**: `--pat` / `AZURE_DEVOPS_EXT_PAT` / `AZURE_DEVOPS_PAT`, else azure-identity's
|
|
42
|
+
`DefaultAzureCredential` (environment variables, managed identity, a cached `az login`, ...).
|
|
43
|
+
- **Azure (`bdt logs *`)**: the same `DefaultAzureCredential`, against ARM / Application Insights;
|
|
44
|
+
`AZURE_SUBSCRIPTION_ID` selects the subscription, else the only enabled one is used.
|
|
45
|
+
|
|
46
|
+
Works on Windows: output is decoded as UTF-8 rather than
|
|
21
47
|
relying on the console's default codepage, and file arguments accept either
|
|
22
48
|
slash style.
|
|
23
49
|
|
|
@@ -76,17 +102,16 @@ polling forever (a failed policy lookup is ignored and the wait continues).
|
|
|
76
102
|
**Azure DevOps**: org/project/repo are auto-detected from
|
|
77
103
|
`git remote get-url origin` (handles SSH, `dev.azure.com` HTTPS, and
|
|
78
104
|
`*.visualstudio.com` HTTPS forms). Auth is an explicit PAT (`--pat` or
|
|
79
|
-
`AZURE_DEVOPS_EXT_PAT`/`AZURE_DEVOPS_PAT` env var), falling back to a short-lived token from
|
|
80
|
-
caller's own `az login` — never embed a PAT literal in a script or CI file.
|
|
105
|
+
`AZURE_DEVOPS_EXT_PAT`/`AZURE_DEVOPS_PAT` env var), falling back to a short-lived token from
|
|
106
|
+
azure-identity's `DefaultAzureCredential` (e.g. the caller's own `az login`) — never embed a PAT literal in a script or CI file.
|
|
81
107
|
`--target-branch` optionally restricts the lookup to PRs into that branch (default: any).
|
|
82
108
|
|
|
83
|
-
**GitHub**: uses `
|
|
84
|
-
PR opened from the current branch (
|
|
85
|
-
`--target-branch` to that base branch if given; with none open,
|
|
86
|
-
|
|
87
|
-
is shown in the output. Check status is computed from
|
|
88
|
-
`
|
|
89
|
-
since the latter flag isn't available in all `gh` releases.
|
|
109
|
+
**GitHub**: uses the `GH_TOKEN`/`GITHUB_TOKEN` auth above and resolves the open
|
|
110
|
+
PR opened from the current branch (REST pulls filtered by head, narrowed by
|
|
111
|
+
`--target-branch` to that base branch if given; with none open, a merged/closed one
|
|
112
|
+
is looked up); the PR's actual base branch
|
|
113
|
+
is shown in the output. Check status is computed from the PR's
|
|
114
|
+
`statusCheckRollup`, fetched via GraphQL.
|
|
90
115
|
|
|
91
116
|
Pass `--pr-id <number>` to check a specific PR directly instead of resolving
|
|
92
117
|
it from the current branch — useful when that PR's branch isn't checked out
|
|
@@ -135,7 +160,7 @@ anything depending on them) in place — distinct from queuing a brand new
|
|
|
135
160
|
build. One retry call per pipeline that has a failed build for the PR.
|
|
136
161
|
`--target-branch` selects which PR to look at, same as `bdt pr status`.
|
|
137
162
|
|
|
138
|
-
**GitHub**:
|
|
163
|
+
**GitHub**: POSTs `actions/runs/<run-id>/rerun-failed-jobs`, which reruns only the
|
|
139
164
|
failed job(s) (and their dependents) of a workflow run — the run ID(s) are
|
|
140
165
|
found automatically from the PR's failing checks. Checks that aren't backed
|
|
141
166
|
by a GitHub Actions run (e.g. a legacy commit status from an external CI)
|
|
@@ -166,10 +191,10 @@ skipped rather than blocking or crashing `pr status`.
|
|
|
166
191
|
`pr status` uses, just queried by `branchName=refs/heads/<target-branch>`
|
|
167
192
|
instead of the PR's merge/source ref.
|
|
168
193
|
|
|
169
|
-
**GitHub**:
|
|
194
|
+
**GitHub**: lists workflow runs via REST filtered by `branch=<target-branch>&event=push`, which
|
|
170
195
|
selects workflow runs triggered by a push to that branch — as opposed to a
|
|
171
196
|
`pull_request`-triggered run for some still-open PR targeting the same
|
|
172
|
-
branch. Failed steps are printed
|
|
197
|
+
branch. Failed steps are printed as the tail of each failed job's log.
|
|
173
198
|
|
|
174
199
|
## `bdt pr create`
|
|
175
200
|
|
|
@@ -178,17 +203,34 @@ bdt pr create --target dev # or --target main / test
|
|
|
178
203
|
```
|
|
179
204
|
|
|
180
205
|
Creates a PR from the current branch into `--target`. On Azure DevOps,
|
|
181
|
-
a
|
|
182
|
-
`
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
`
|
|
206
|
+
a REST POST to `pullrequests` (org/project/repo inferred from the git remote). On GitHub,
|
|
207
|
+
a REST POST to `pulls`; title/body default to the branch's commit(s) so it never blocks on an
|
|
208
|
+
interactive prompt.
|
|
209
|
+
|
|
210
|
+
Extra arguments after `--` take the union of `gh pr create` and `az repos pr create` spellings on **both**
|
|
211
|
+
hosts (`--opt value` and `--opt=value`; list flags take every value up to the next option, comma-separated
|
|
212
|
+
values work too; boolean flags take an optional `true`/`false`):
|
|
213
|
+
|
|
214
|
+
| Meaning | Flags |
|
|
215
|
+
|---|---|
|
|
216
|
+
| title / body | `--title`/`-t`, `--body`/`--description`/`-b` (`-d` on Azure DevOps), `--body-file`/`-F` (`-` = stdin) |
|
|
217
|
+
| branches | `--base`/`-B`/`--target-branch`, `--head`/`-H`/`--source-branch`/`-s` |
|
|
218
|
+
| draft | `--draft [true\|false]` (`-d` on GitHub) |
|
|
219
|
+
| labels / reviewers | `--label`/`--labels`/`-l`, `--reviewer`/`--reviewers` (`-r` on GitHub), `--required-reviewers` |
|
|
220
|
+
| work items / issues | `--work-items` (same as `--issue`: linked and tagged `pr-available`) |
|
|
221
|
+
| merge | `--auto-complete`/`--auto-merge`, `--squash`, `--delete-source-branch`, `--merge-commit-message`, `--bypass-policy`, `--bypass-policy-reason`, `--transition-work-items` |
|
|
222
|
+
| other | `--assignee`/`-a`, `--milestone`/`-m`, `--project`/`-p` (GitHub board), `--fill`/`-f`, `--web`/`-w`/`--open`, `--dry-run` |
|
|
223
|
+
| Azure DevOps target | `--organization`/`--org`, `--project`/`-p`, `--repository`/`-r` override the remote-derived values |
|
|
224
|
+
| accepted, ignored | `--detect`, `--verbose`, `--debug`, `--subscription`, `--output`/`-o`, `--query` |
|
|
225
|
+
|
|
226
|
+
Azure DevOps resolves reviewers (GUID, e-mail or display name) through the Identities API, sets
|
|
227
|
+
`--auto-complete` as the current user and applies the merge options in a follow-up update, as `az` does.
|
|
228
|
+
A flag the host has no counterpart for (e.g. `--milestone` on Azure DevOps, `--delete-source-branch` on
|
|
229
|
+
GitHub) is reported on stderr (`Note: --milestone is ignored on Azure DevOps`), never dropped silently.
|
|
230
|
+
Unknown flags fail with the list of supported ones.
|
|
186
231
|
|
|
187
232
|
Pass the text with `--title "..."` and `--description "$(cat pr.md)"` rather than as passthrough
|
|
188
|
-
args:
|
|
189
|
-
Azure DevOps it is set over the REST API right after `az` creates the PR, because
|
|
190
|
-
`az repos pr create --description` has been seen cutting long text at ~450 characters (a `--title`/
|
|
191
|
-
`--description` given after `--` is intercepted the same way). Azure DevOps itself allows at most
|
|
233
|
+
args: the description is always sent in full. Azure DevOps itself allows at most
|
|
192
234
|
4000 characters in a PR description: a longer one is rejected up front, and a description the
|
|
193
235
|
server stored shorter than sent is reported as a warning (`bdt pr update` does the same check).
|
|
194
236
|
|
|
@@ -198,15 +240,15 @@ it ready for review. Pass `--no-draft` to open it ready for review
|
|
|
198
240
|
immediately instead.
|
|
199
241
|
|
|
200
242
|
`--label` (repeatable) applies labels to the PR on either host: on GitHub
|
|
201
|
-
these
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
create prints the PR's web/GUI link (not just the REST API URL Azure DevOps
|
|
205
|
-
|
|
243
|
+
these are applied to the PR, and unknown labels are created automatically
|
|
244
|
+
by GitHub (no pre-existing label required); on Azure DevOps labels are freeform and get
|
|
245
|
+
created on the fly. A successful
|
|
246
|
+
create prints the PR's web/GUI link (not just the REST API URL Azure DevOps
|
|
247
|
+
returns).
|
|
206
248
|
|
|
207
249
|
`[tool.bdt.pr.required_labels]` in pyproject.toml can require at least one
|
|
208
250
|
label from each named group before the PR is created — checked locally
|
|
209
|
-
(no
|
|
251
|
+
(no API call happens if a group isn't satisfied):
|
|
210
252
|
|
|
211
253
|
```toml
|
|
212
254
|
[tool.bdt.pr.required_labels]
|
|
@@ -336,27 +378,26 @@ On `update`, `--board` only moves the item when you pass it explicitly — it
|
|
|
336
378
|
never falls back to `pyproject.toml`, so an unrelated field update (e.g.
|
|
337
379
|
just `--title`) can't silently relocate the item to a different board.
|
|
338
380
|
|
|
339
|
-
**GitHub**:
|
|
340
|
-
|
|
381
|
+
**GitHub**: REST/GraphQL calls for issue create / edit / delete /
|
|
382
|
+
comment. `--label`/`--tag` add a label on `create`, or add/remove one on
|
|
341
383
|
`update` (paired with `--remove-label`/`--remove-tag`); labels must already
|
|
342
384
|
exist in the repo. `--screenshot` pushes images to a `pr-assets` branch (same trick `bdt
|
|
343
385
|
pr create --screenshot` uses, since GitHub has no API for uploading an image
|
|
344
386
|
into an issue) and appends them to the issue body / comment as Markdown.
|
|
345
387
|
`issue delete` is **permanent** — GitHub has no recycle bin for issues.
|
|
346
|
-
Comment update/delete go through
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
`
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
`--
|
|
353
|
-
|
|
388
|
+
Comment update/delete go through REST. Extra arguments
|
|
389
|
+
to `bdt issue create` accept the `gh issue create` flags `--title`/`-t`, `--body`/`-b`, `--body-file`/`-F`
|
|
390
|
+
(`-` = stdin), `--label`/`-l`, `--assignee`/`-a` (`@me` works), `--milestone`/`-m` (title or number),
|
|
391
|
+
`--project`/`-p` (Projects board, repeatable) and `--web`/`-w`; `--template` / `--recover` are rejected. E.g.
|
|
392
|
+
`bdt issue create --title "..." -- --assignee @me --project Roadmap`.
|
|
393
|
+
|
|
394
|
+
`--parent` / `--blocked-by` use GitHub's sub-issues and issue dependencies REST endpoints; `issue show` reads
|
|
395
|
+
the parent, sub-issues, blocked-by and blocking links the same way. `--iteration` isn't supported: a
|
|
354
396
|
GitHub Projects (v2) iteration is a per-project field, not a property of the issue.
|
|
355
397
|
|
|
356
398
|
`--board <name>` on `create` adds the issue to that GitHub Projects (v2)
|
|
357
|
-
board by title (needs a token with the `project` scope
|
|
358
|
-
|
|
359
|
-
currently on that board; since `gh issue list` has no board filter of its
|
|
399
|
+
board by title (needs a token with the `project` scope). On `search`, `--board` (title or number) scopes results to issues
|
|
400
|
+
currently on that board; since the issue list has no board filter of its
|
|
360
401
|
own, this fetches a wider raw pool and filters it down client-side, so a
|
|
361
402
|
board with few matches may return fewer results than `--limit` asks for. A
|
|
362
403
|
CLI flag beats `[tool.bdt.github].board` in `pyproject.toml`:
|
|
@@ -392,7 +433,7 @@ Claims an issue (GitHub) or work item (Azure DevOps): comments `Taken by <you>`
|
|
|
392
433
|
running coding agent's session (the same `<Agent> Session: <id>` note every bdt comment gets: a
|
|
393
434
|
claude.ai link under a bridged Claude session, otherwise the bare session id; nothing outside an
|
|
394
435
|
agent), so others can see who is on it. `<you>` is the GitHub login
|
|
395
|
-
|
|
436
|
+
the token authenticates as, else the git `user.name`. Without `NUMBER` it takes the issue the current
|
|
396
437
|
branch's PR closes (`Fixes #N`, or an issue/work-item URL in the PR body); it refuses to guess if
|
|
397
438
|
that is none or several. If the issue's newest comment already is a "Taken by ..." claim (by anyone) it
|
|
398
439
|
says so and posts nothing, so it's safe to run repeatedly -- including before `bdt issue do`.
|
|
@@ -413,7 +454,7 @@ addresses the calling agent. It combines with every other `search` filter (keywo
|
|
|
413
454
|
the agent that is running `bdt`, or `@Agent`, which addresses every agent. Matching is case-insensitive and
|
|
414
455
|
on whole words: `@claude`, `@CLAUDE,` and `@Claude.` match, `@Claudette`, `@claude-bot` and `me@claude.ai` do not.
|
|
415
456
|
Only the newest comment counts, so once someone (including the agent, e.g. with a reply) comments after the
|
|
416
|
-
mention, the issue drops out of the list. The newest comment isn't part of the list output of
|
|
457
|
+
mention, the issue drops out of the list. The newest comment isn't part of the list output of GitHub/Azure DevOps,
|
|
417
458
|
so this costs one extra request per candidate; candidates are scanned in recently-updated order (up to 10x
|
|
418
459
|
`--limit` on GitHub, 200 on Azure DevOps) until `--limit` have matched.
|
|
419
460
|
|
|
@@ -544,10 +585,10 @@ Configuration (flags override env vars):
|
|
|
544
585
|
| Local work dir | `--root` | `AZDO_WORK_DIR`, `BMS_WORK_DIR` | `~/projects` (`C:/Projects` on Windows) |
|
|
545
586
|
| Azure DevOps org | `--org` | `AZDO_ORG`, `BMS_ORG` | none (ADO not searched) |
|
|
546
587
|
| GitHub org | `--github-org` | `GITHUB_ORG`, `BMS_GITHUB_ORG` | none (GitHub not searched) |
|
|
547
|
-
| ADO PAT for cloning | `--pat` | `AZURE_DEVOPS_EXT_PAT`, `AZURE_DEVOPS_PAT` | falls back to `
|
|
588
|
+
| ADO PAT for cloning | `--pat` | `AZURE_DEVOPS_EXT_PAT`, `AZURE_DEVOPS_PAT` | falls back to `DefaultAzureCredential` |
|
|
548
589
|
|
|
549
590
|
Set the org env vars in your shell profile to make `bdt find-repo <name>` work anywhere. It replaces
|
|
550
|
-
the `cross-repo-discovery` skill's `ALL_REPOS.md` sync. Needs
|
|
591
|
+
the `cross-repo-discovery` skill's `ALL_REPOS.md` sync. Needs ADO auth / a GitHub token only when
|
|
551
592
|
those orgs are searched.
|
|
552
593
|
|
|
553
594
|
## `bdt cleanup worktrees` / `bdt cleanup orphaned-dbs` / `bdt cleanup db` / `bdt cleanup worktree`
|
|
@@ -702,7 +743,7 @@ sandbox mode too.
|
|
|
702
743
|
## `bdt logs roles` / `bdt logs tail`
|
|
703
744
|
|
|
704
745
|
Query Application Insights (KQL over `traces`/`exceptions`) via
|
|
705
|
-
|
|
746
|
+
the Application Insights REST API (azure-identity credential). No defaults are baked in — pass
|
|
706
747
|
`--resource-group`/`--app-insights` explicitly (or set
|
|
707
748
|
`AZURE_RESOURCE_GROUP`/`AZURE_APP_INSIGHTS`), since which Azure resource
|
|
708
749
|
"this repo" maps to isn't derivable from the git remote.
|
|
@@ -715,7 +756,7 @@ bdt logs tail --resource-group my-rg --app-insights my-app-insights --role my-se
|
|
|
715
756
|
## `bdt logs fetch`
|
|
716
757
|
|
|
717
758
|
Downloads the App Service log archive for a webapp/slot via
|
|
718
|
-
|
|
759
|
+
the App Service Kudu/ARM log download, unzips it, and writes every line matching a
|
|
719
760
|
common error/warning marker (`ERROR`, `CRITICAL`, `WARNING`, tracebacks,
|
|
720
761
|
`4xx`/`5xx`, `FAILED`, `FATAL`) to `<out>/<slot>_errors.log`. Simpler and
|
|
721
762
|
often preferable to the KQL commands above when you just want "what broke
|
|
@@ -723,7 +764,7 @@ recently" rather than a queryable trace stream.
|
|
|
723
764
|
|
|
724
765
|
The webapp/resource-group/slot come from a named environment configured in
|
|
725
766
|
the calling repo's `pyproject.toml`. `slot` is optional — omit it for an
|
|
726
|
-
app's default/production slot (no
|
|
767
|
+
app's default/production slot (no slot is used); set it for a
|
|
727
768
|
named deployment slot:
|
|
728
769
|
|
|
729
770
|
```toml
|
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: bmsdna-devtools
|
|
3
|
-
Version: 0.43.1
|
|
4
|
-
Summary: Shared Azure DevOps / GitHub / git / Azure Monitor developer tooling for BMS projects
|
|
5
|
-
Requires-Python: >=3.14
|
|
6
|
-
Requires-Dist: pgdevkit[db]>=0.7.1
|
|
7
|
-
Requires-Dist: requests>=2.32.0
|
|
8
|
-
Requires-Dist: rich>=13.0.0
|
|
9
|
-
Requires-Dist: tomli-w>=1.0.0
|
|
10
|
-
Requires-Dist: typer>=0.26.7
|
|
11
|
-
Provides-Extra: lint
|
|
12
|
-
Requires-Dist: sqlglot>=27.0.0; extra == 'lint'
|
|
13
|
-
Provides-Extra: usage
|
|
14
|
-
Requires-Dist: duckdb>=1.3.0; extra == 'usage'
|
|
15
|
-
Requires-Dist: plotly>=5.24.0; extra == 'usage'
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
|
|
18
1
|
# bmsdna-devtools
|
|
19
2
|
|
|
20
3
|
Shared developer tooling for BMS projects: PR build/check status and a
|
|
@@ -25,16 +8,24 @@ postgres/psycopg (and arrowbricks) SQL rules, pydantic-model placement, hand-wir
|
|
|
25
8
|
TypeScript and baseline tooling, plus `bdt dead-code` for `.sql` files nothing loads and
|
|
26
9
|
backend routes nothing calls.
|
|
27
10
|
`bdt pr *` and `bdt issue *` auto-detect whether the current repo's `origin`
|
|
28
|
-
remote is Azure DevOps or GitHub and
|
|
11
|
+
remote is Azure DevOps or GitHub and call the matching REST API.
|
|
29
12
|
Consolidates near-duplicate scripts that used to be copy-pasted across
|
|
30
13
|
OneSales, ccmt2, and MDMApp into one versioned package with a `bdt` CLI.
|
|
31
14
|
|
|
32
|
-
Requires `git`
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
`
|
|
15
|
+
Requires only `git` on PATH (plus `psql` for `bdt testdb`); the `az` and `gh` CLIs are
|
|
16
|
+
**not** needed — everything talks to GitHub (REST + GraphQL), Azure DevOps and Azure
|
|
17
|
+
(ARM / Application Insights) over raw HTTP (`requests`).
|
|
18
|
+
|
|
19
|
+
Auth:
|
|
20
|
+
- **GitHub**: the `GH_TOKEN` / `GITHUB_TOKEN` environment variable, else (if `gh` happens to be
|
|
21
|
+
installed) the output of `gh auth token`. The token needs the `repo` scope, plus `project` for
|
|
22
|
+
boards and `workflow` for reruns.
|
|
23
|
+
- **Azure DevOps**: `--pat` / `AZURE_DEVOPS_EXT_PAT` / `AZURE_DEVOPS_PAT`, else azure-identity's
|
|
24
|
+
`DefaultAzureCredential` (environment variables, managed identity, a cached `az login`, ...).
|
|
25
|
+
- **Azure (`bdt logs *`)**: the same `DefaultAzureCredential`, against ARM / Application Insights;
|
|
26
|
+
`AZURE_SUBSCRIPTION_ID` selects the subscription, else the only enabled one is used.
|
|
27
|
+
|
|
28
|
+
Works on Windows: output is decoded as UTF-8 rather than
|
|
38
29
|
relying on the console's default codepage, and file arguments accept either
|
|
39
30
|
slash style.
|
|
40
31
|
|
|
@@ -93,17 +84,16 @@ polling forever (a failed policy lookup is ignored and the wait continues).
|
|
|
93
84
|
**Azure DevOps**: org/project/repo are auto-detected from
|
|
94
85
|
`git remote get-url origin` (handles SSH, `dev.azure.com` HTTPS, and
|
|
95
86
|
`*.visualstudio.com` HTTPS forms). Auth is an explicit PAT (`--pat` or
|
|
96
|
-
`AZURE_DEVOPS_EXT_PAT`/`AZURE_DEVOPS_PAT` env var), falling back to a short-lived token from
|
|
97
|
-
caller's own `az login` — never embed a PAT literal in a script or CI file.
|
|
87
|
+
`AZURE_DEVOPS_EXT_PAT`/`AZURE_DEVOPS_PAT` env var), falling back to a short-lived token from
|
|
88
|
+
azure-identity's `DefaultAzureCredential` (e.g. the caller's own `az login`) — never embed a PAT literal in a script or CI file.
|
|
98
89
|
`--target-branch` optionally restricts the lookup to PRs into that branch (default: any).
|
|
99
90
|
|
|
100
|
-
**GitHub**: uses `
|
|
101
|
-
PR opened from the current branch (
|
|
102
|
-
`--target-branch` to that base branch if given; with none open,
|
|
103
|
-
|
|
104
|
-
is shown in the output. Check status is computed from
|
|
105
|
-
`
|
|
106
|
-
since the latter flag isn't available in all `gh` releases.
|
|
91
|
+
**GitHub**: uses the `GH_TOKEN`/`GITHUB_TOKEN` auth above and resolves the open
|
|
92
|
+
PR opened from the current branch (REST pulls filtered by head, narrowed by
|
|
93
|
+
`--target-branch` to that base branch if given; with none open, a merged/closed one
|
|
94
|
+
is looked up); the PR's actual base branch
|
|
95
|
+
is shown in the output. Check status is computed from the PR's
|
|
96
|
+
`statusCheckRollup`, fetched via GraphQL.
|
|
107
97
|
|
|
108
98
|
Pass `--pr-id <number>` to check a specific PR directly instead of resolving
|
|
109
99
|
it from the current branch — useful when that PR's branch isn't checked out
|
|
@@ -152,7 +142,7 @@ anything depending on them) in place — distinct from queuing a brand new
|
|
|
152
142
|
build. One retry call per pipeline that has a failed build for the PR.
|
|
153
143
|
`--target-branch` selects which PR to look at, same as `bdt pr status`.
|
|
154
144
|
|
|
155
|
-
**GitHub**:
|
|
145
|
+
**GitHub**: POSTs `actions/runs/<run-id>/rerun-failed-jobs`, which reruns only the
|
|
156
146
|
failed job(s) (and their dependents) of a workflow run — the run ID(s) are
|
|
157
147
|
found automatically from the PR's failing checks. Checks that aren't backed
|
|
158
148
|
by a GitHub Actions run (e.g. a legacy commit status from an external CI)
|
|
@@ -183,10 +173,10 @@ skipped rather than blocking or crashing `pr status`.
|
|
|
183
173
|
`pr status` uses, just queried by `branchName=refs/heads/<target-branch>`
|
|
184
174
|
instead of the PR's merge/source ref.
|
|
185
175
|
|
|
186
|
-
**GitHub**:
|
|
176
|
+
**GitHub**: lists workflow runs via REST filtered by `branch=<target-branch>&event=push`, which
|
|
187
177
|
selects workflow runs triggered by a push to that branch — as opposed to a
|
|
188
178
|
`pull_request`-triggered run for some still-open PR targeting the same
|
|
189
|
-
branch. Failed steps are printed
|
|
179
|
+
branch. Failed steps are printed as the tail of each failed job's log.
|
|
190
180
|
|
|
191
181
|
## `bdt pr create`
|
|
192
182
|
|
|
@@ -195,17 +185,34 @@ bdt pr create --target dev # or --target main / test
|
|
|
195
185
|
```
|
|
196
186
|
|
|
197
187
|
Creates a PR from the current branch into `--target`. On Azure DevOps,
|
|
198
|
-
a
|
|
199
|
-
`
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
`
|
|
188
|
+
a REST POST to `pullrequests` (org/project/repo inferred from the git remote). On GitHub,
|
|
189
|
+
a REST POST to `pulls`; title/body default to the branch's commit(s) so it never blocks on an
|
|
190
|
+
interactive prompt.
|
|
191
|
+
|
|
192
|
+
Extra arguments after `--` take the union of `gh pr create` and `az repos pr create` spellings on **both**
|
|
193
|
+
hosts (`--opt value` and `--opt=value`; list flags take every value up to the next option, comma-separated
|
|
194
|
+
values work too; boolean flags take an optional `true`/`false`):
|
|
195
|
+
|
|
196
|
+
| Meaning | Flags |
|
|
197
|
+
|---|---|
|
|
198
|
+
| title / body | `--title`/`-t`, `--body`/`--description`/`-b` (`-d` on Azure DevOps), `--body-file`/`-F` (`-` = stdin) |
|
|
199
|
+
| branches | `--base`/`-B`/`--target-branch`, `--head`/`-H`/`--source-branch`/`-s` |
|
|
200
|
+
| draft | `--draft [true\|false]` (`-d` on GitHub) |
|
|
201
|
+
| labels / reviewers | `--label`/`--labels`/`-l`, `--reviewer`/`--reviewers` (`-r` on GitHub), `--required-reviewers` |
|
|
202
|
+
| work items / issues | `--work-items` (same as `--issue`: linked and tagged `pr-available`) |
|
|
203
|
+
| merge | `--auto-complete`/`--auto-merge`, `--squash`, `--delete-source-branch`, `--merge-commit-message`, `--bypass-policy`, `--bypass-policy-reason`, `--transition-work-items` |
|
|
204
|
+
| other | `--assignee`/`-a`, `--milestone`/`-m`, `--project`/`-p` (GitHub board), `--fill`/`-f`, `--web`/`-w`/`--open`, `--dry-run` |
|
|
205
|
+
| Azure DevOps target | `--organization`/`--org`, `--project`/`-p`, `--repository`/`-r` override the remote-derived values |
|
|
206
|
+
| accepted, ignored | `--detect`, `--verbose`, `--debug`, `--subscription`, `--output`/`-o`, `--query` |
|
|
207
|
+
|
|
208
|
+
Azure DevOps resolves reviewers (GUID, e-mail or display name) through the Identities API, sets
|
|
209
|
+
`--auto-complete` as the current user and applies the merge options in a follow-up update, as `az` does.
|
|
210
|
+
A flag the host has no counterpart for (e.g. `--milestone` on Azure DevOps, `--delete-source-branch` on
|
|
211
|
+
GitHub) is reported on stderr (`Note: --milestone is ignored on Azure DevOps`), never dropped silently.
|
|
212
|
+
Unknown flags fail with the list of supported ones.
|
|
203
213
|
|
|
204
214
|
Pass the text with `--title "..."` and `--description "$(cat pr.md)"` rather than as passthrough
|
|
205
|
-
args:
|
|
206
|
-
Azure DevOps it is set over the REST API right after `az` creates the PR, because
|
|
207
|
-
`az repos pr create --description` has been seen cutting long text at ~450 characters (a `--title`/
|
|
208
|
-
`--description` given after `--` is intercepted the same way). Azure DevOps itself allows at most
|
|
215
|
+
args: the description is always sent in full. Azure DevOps itself allows at most
|
|
209
216
|
4000 characters in a PR description: a longer one is rejected up front, and a description the
|
|
210
217
|
server stored shorter than sent is reported as a warning (`bdt pr update` does the same check).
|
|
211
218
|
|
|
@@ -215,15 +222,15 @@ it ready for review. Pass `--no-draft` to open it ready for review
|
|
|
215
222
|
immediately instead.
|
|
216
223
|
|
|
217
224
|
`--label` (repeatable) applies labels to the PR on either host: on GitHub
|
|
218
|
-
these
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
create prints the PR's web/GUI link (not just the REST API URL Azure DevOps
|
|
222
|
-
|
|
225
|
+
these are applied to the PR, and unknown labels are created automatically
|
|
226
|
+
by GitHub (no pre-existing label required); on Azure DevOps labels are freeform and get
|
|
227
|
+
created on the fly. A successful
|
|
228
|
+
create prints the PR's web/GUI link (not just the REST API URL Azure DevOps
|
|
229
|
+
returns).
|
|
223
230
|
|
|
224
231
|
`[tool.bdt.pr.required_labels]` in pyproject.toml can require at least one
|
|
225
232
|
label from each named group before the PR is created — checked locally
|
|
226
|
-
(no
|
|
233
|
+
(no API call happens if a group isn't satisfied):
|
|
227
234
|
|
|
228
235
|
```toml
|
|
229
236
|
[tool.bdt.pr.required_labels]
|
|
@@ -353,27 +360,26 @@ On `update`, `--board` only moves the item when you pass it explicitly — it
|
|
|
353
360
|
never falls back to `pyproject.toml`, so an unrelated field update (e.g.
|
|
354
361
|
just `--title`) can't silently relocate the item to a different board.
|
|
355
362
|
|
|
356
|
-
**GitHub**:
|
|
357
|
-
|
|
363
|
+
**GitHub**: REST/GraphQL calls for issue create / edit / delete /
|
|
364
|
+
comment. `--label`/`--tag` add a label on `create`, or add/remove one on
|
|
358
365
|
`update` (paired with `--remove-label`/`--remove-tag`); labels must already
|
|
359
366
|
exist in the repo. `--screenshot` pushes images to a `pr-assets` branch (same trick `bdt
|
|
360
367
|
pr create --screenshot` uses, since GitHub has no API for uploading an image
|
|
361
368
|
into an issue) and appends them to the issue body / comment as Markdown.
|
|
362
369
|
`issue delete` is **permanent** — GitHub has no recycle bin for issues.
|
|
363
|
-
Comment update/delete go through
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
`
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
`--
|
|
370
|
-
|
|
370
|
+
Comment update/delete go through REST. Extra arguments
|
|
371
|
+
to `bdt issue create` accept the `gh issue create` flags `--title`/`-t`, `--body`/`-b`, `--body-file`/`-F`
|
|
372
|
+
(`-` = stdin), `--label`/`-l`, `--assignee`/`-a` (`@me` works), `--milestone`/`-m` (title or number),
|
|
373
|
+
`--project`/`-p` (Projects board, repeatable) and `--web`/`-w`; `--template` / `--recover` are rejected. E.g.
|
|
374
|
+
`bdt issue create --title "..." -- --assignee @me --project Roadmap`.
|
|
375
|
+
|
|
376
|
+
`--parent` / `--blocked-by` use GitHub's sub-issues and issue dependencies REST endpoints; `issue show` reads
|
|
377
|
+
the parent, sub-issues, blocked-by and blocking links the same way. `--iteration` isn't supported: a
|
|
371
378
|
GitHub Projects (v2) iteration is a per-project field, not a property of the issue.
|
|
372
379
|
|
|
373
380
|
`--board <name>` on `create` adds the issue to that GitHub Projects (v2)
|
|
374
|
-
board by title (needs a token with the `project` scope
|
|
375
|
-
|
|
376
|
-
currently on that board; since `gh issue list` has no board filter of its
|
|
381
|
+
board by title (needs a token with the `project` scope). On `search`, `--board` (title or number) scopes results to issues
|
|
382
|
+
currently on that board; since the issue list has no board filter of its
|
|
377
383
|
own, this fetches a wider raw pool and filters it down client-side, so a
|
|
378
384
|
board with few matches may return fewer results than `--limit` asks for. A
|
|
379
385
|
CLI flag beats `[tool.bdt.github].board` in `pyproject.toml`:
|
|
@@ -409,7 +415,7 @@ Claims an issue (GitHub) or work item (Azure DevOps): comments `Taken by <you>`
|
|
|
409
415
|
running coding agent's session (the same `<Agent> Session: <id>` note every bdt comment gets: a
|
|
410
416
|
claude.ai link under a bridged Claude session, otherwise the bare session id; nothing outside an
|
|
411
417
|
agent), so others can see who is on it. `<you>` is the GitHub login
|
|
412
|
-
|
|
418
|
+
the token authenticates as, else the git `user.name`. Without `NUMBER` it takes the issue the current
|
|
413
419
|
branch's PR closes (`Fixes #N`, or an issue/work-item URL in the PR body); it refuses to guess if
|
|
414
420
|
that is none or several. If the issue's newest comment already is a "Taken by ..." claim (by anyone) it
|
|
415
421
|
says so and posts nothing, so it's safe to run repeatedly -- including before `bdt issue do`.
|
|
@@ -430,7 +436,7 @@ addresses the calling agent. It combines with every other `search` filter (keywo
|
|
|
430
436
|
the agent that is running `bdt`, or `@Agent`, which addresses every agent. Matching is case-insensitive and
|
|
431
437
|
on whole words: `@claude`, `@CLAUDE,` and `@Claude.` match, `@Claudette`, `@claude-bot` and `me@claude.ai` do not.
|
|
432
438
|
Only the newest comment counts, so once someone (including the agent, e.g. with a reply) comments after the
|
|
433
|
-
mention, the issue drops out of the list. The newest comment isn't part of the list output of
|
|
439
|
+
mention, the issue drops out of the list. The newest comment isn't part of the list output of GitHub/Azure DevOps,
|
|
434
440
|
so this costs one extra request per candidate; candidates are scanned in recently-updated order (up to 10x
|
|
435
441
|
`--limit` on GitHub, 200 on Azure DevOps) until `--limit` have matched.
|
|
436
442
|
|
|
@@ -561,10 +567,10 @@ Configuration (flags override env vars):
|
|
|
561
567
|
| Local work dir | `--root` | `AZDO_WORK_DIR`, `BMS_WORK_DIR` | `~/projects` (`C:/Projects` on Windows) |
|
|
562
568
|
| Azure DevOps org | `--org` | `AZDO_ORG`, `BMS_ORG` | none (ADO not searched) |
|
|
563
569
|
| GitHub org | `--github-org` | `GITHUB_ORG`, `BMS_GITHUB_ORG` | none (GitHub not searched) |
|
|
564
|
-
| ADO PAT for cloning | `--pat` | `AZURE_DEVOPS_EXT_PAT`, `AZURE_DEVOPS_PAT` | falls back to `
|
|
570
|
+
| ADO PAT for cloning | `--pat` | `AZURE_DEVOPS_EXT_PAT`, `AZURE_DEVOPS_PAT` | falls back to `DefaultAzureCredential` |
|
|
565
571
|
|
|
566
572
|
Set the org env vars in your shell profile to make `bdt find-repo <name>` work anywhere. It replaces
|
|
567
|
-
the `cross-repo-discovery` skill's `ALL_REPOS.md` sync. Needs
|
|
573
|
+
the `cross-repo-discovery` skill's `ALL_REPOS.md` sync. Needs ADO auth / a GitHub token only when
|
|
568
574
|
those orgs are searched.
|
|
569
575
|
|
|
570
576
|
## `bdt cleanup worktrees` / `bdt cleanup orphaned-dbs` / `bdt cleanup db` / `bdt cleanup worktree`
|
|
@@ -719,7 +725,7 @@ sandbox mode too.
|
|
|
719
725
|
## `bdt logs roles` / `bdt logs tail`
|
|
720
726
|
|
|
721
727
|
Query Application Insights (KQL over `traces`/`exceptions`) via
|
|
722
|
-
|
|
728
|
+
the Application Insights REST API (azure-identity credential). No defaults are baked in — pass
|
|
723
729
|
`--resource-group`/`--app-insights` explicitly (or set
|
|
724
730
|
`AZURE_RESOURCE_GROUP`/`AZURE_APP_INSIGHTS`), since which Azure resource
|
|
725
731
|
"this repo" maps to isn't derivable from the git remote.
|
|
@@ -732,7 +738,7 @@ bdt logs tail --resource-group my-rg --app-insights my-app-insights --role my-se
|
|
|
732
738
|
## `bdt logs fetch`
|
|
733
739
|
|
|
734
740
|
Downloads the App Service log archive for a webapp/slot via
|
|
735
|
-
|
|
741
|
+
the App Service Kudu/ARM log download, unzips it, and writes every line matching a
|
|
736
742
|
common error/warning marker (`ERROR`, `CRITICAL`, `WARNING`, tracebacks,
|
|
737
743
|
`4xx`/`5xx`, `FAILED`, `FATAL`) to `<out>/<slot>_errors.log`. Simpler and
|
|
738
744
|
often preferable to the KQL commands above when you just want "what broke
|
|
@@ -740,7 +746,7 @@ recently" rather than a queryable trace stream.
|
|
|
740
746
|
|
|
741
747
|
The webapp/resource-group/slot come from a named environment configured in
|
|
742
748
|
the calling repo's `pyproject.toml`. `slot` is optional — omit it for an
|
|
743
|
-
app's default/production slot (no
|
|
749
|
+
app's default/production slot (no slot is used); set it for a
|
|
744
750
|
named deployment slot:
|
|
745
751
|
|
|
746
752
|
```toml
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Azure DevOps auth: explicit PAT (`--pat` / AZURE_DEVOPS_EXT_PAT / AZURE_DEVOPS_PAT), or a token from
|
|
2
|
+
`DefaultAzureCredential` (see `azure_auth`)."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import base64
|
|
7
|
+
|
|
8
|
+
from .azure_auth import get_azure_token
|
|
9
|
+
|
|
10
|
+
# Well-known Azure DevOps resource ID; `<id>/.default` is its AAD scope.
|
|
11
|
+
ADO_RESOURCE_ID = "499b84ac-1321-427f-aa17-267ca6975798"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_az_devops_token() -> str:
|
|
15
|
+
return get_azure_token(f"{ADO_RESOURCE_ID}/.default")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def auth_header(pat: str | None) -> dict[str, str]:
|
|
19
|
+
"""Basic-auth header for an explicit PAT, else Bearer via `DefaultAzureCredential`.
|
|
20
|
+
|
|
21
|
+
Never hardcode a PAT literal in a caller — pass it in from an env var
|
|
22
|
+
(e.g. AZURE_DEVOPS_EXT_PAT) or a CLI flag, or omit it and let azure-identity supply a
|
|
23
|
+
short-lived token from the operator's own login.
|
|
24
|
+
"""
|
|
25
|
+
if pat:
|
|
26
|
+
token = base64.b64encode(f":{pat}".encode()).decode()
|
|
27
|
+
return {"Authorization": f"Basic {token}"}
|
|
28
|
+
return {"Authorization": f"Bearer {get_az_devops_token()}"}
|