@databricks-solutions/lakebase-scm-utils 0.3.4 → 0.3.5
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.
- package/dist/scripts/github/index.cjs +14 -0
- package/dist/scripts/github/index.d.cts +19 -1
- package/dist/scripts/github/index.d.ts +19 -1
- package/dist/scripts/github/index.js +13 -0
- package/dist/scripts/index.cjs +79 -2
- package/dist/scripts/index.d.cts +2 -2
- package/dist/scripts/index.d.ts +2 -2
- package/dist/scripts/index.js +76 -2
- package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +2 -2
- package/dist/scripts/lakebase/ci-resolve-branch.cli.js +2 -2
- package/dist/scripts/lakebase/collapse-heads.cli.cjs +2 -2
- package/dist/scripts/lakebase/collapse-heads.cli.js +2 -2
- package/dist/scripts/lakebase/detect-language.cli.cjs +2 -2
- package/dist/scripts/lakebase/detect-language.cli.js +2 -2
- package/dist/scripts/lakebase/doctor.cli.cjs +15664 -7598
- package/dist/scripts/lakebase/doctor.cli.js +8243 -106
- package/dist/scripts/lakebase/get-connection.cli.cjs +2 -2
- package/dist/scripts/lakebase/get-connection.cli.js +2 -2
- package/dist/scripts/lakebase/index.cjs +172 -95
- package/dist/scripts/lakebase/index.d.cts +22 -1
- package/dist/scripts/lakebase/index.d.ts +22 -1
- package/dist/scripts/lakebase/index.js +170 -95
- package/dist/scripts/lakebase/infra-runner.cli.cjs +2 -2
- package/dist/scripts/lakebase/infra-runner.cli.js +2 -2
- package/dist/scripts/lakebase/new-migration.cli.cjs +2 -2
- package/dist/scripts/lakebase/new-migration.cli.js +2 -2
- package/dist/scripts/lakebase/schema-diff.cli.cjs +2 -2
- package/dist/scripts/lakebase/schema-diff.cli.js +2 -2
- package/dist/scripts/lakebase/schema-migrate.cli.cjs +2 -2
- package/dist/scripts/lakebase/schema-migrate.cli.js +2 -2
- package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +2 -2
- package/dist/scripts/lakebase/scm-claim-feature.cli.js +2 -2
- package/dist/scripts/lakebase/scm-doctor.cli.cjs +2 -2
- package/dist/scripts/lakebase/scm-doctor.cli.js +2 -2
- package/dist/scripts/lakebase/scm-merge.cli.cjs +2 -2
- package/dist/scripts/lakebase/scm-merge.cli.js +2 -2
- package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +2 -2
- package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +2 -2
- package/dist/scripts/util/index.cjs +2 -2
- package/dist/scripts/util/index.js +2 -2
- package/package.json +1 -1
- package/scripts/github/repo.ts +37 -1
- package/scripts/lakebase/create-preflight.ts +45 -0
- package/scripts/lakebase/create-project.ts +15 -0
- package/scripts/lakebase/doctor.ts +50 -0
- package/templates/project/common/.github/workflows/pr.yml +14 -5
|
@@ -20,6 +20,8 @@ import {
|
|
|
20
20
|
import {
|
|
21
21
|
checkDatabricksAuth,
|
|
22
22
|
databricksAuthPrereqMessage,
|
|
23
|
+
checkGitHubWorkflowScope,
|
|
24
|
+
githubWorkflowScopePrereqMessage,
|
|
23
25
|
withLakebaseRollback,
|
|
24
26
|
validateCreateInputs,
|
|
25
27
|
dirIsEmpty,
|
|
@@ -289,6 +291,19 @@ export async function createProject(
|
|
|
289
291
|
throw new Error(databricksAuthPrereqMessage(host, auth.reason));
|
|
290
292
|
}
|
|
291
293
|
|
|
294
|
+
// ── GitHub token `workflow` scope precondition ────────────────
|
|
295
|
+
// The scaffold's final push commits .github/workflows/*, which GitHub rejects
|
|
296
|
+
// unless the token carries the `workflow` OAuth scope. Check it HERE, before any
|
|
297
|
+
// GitHub repo or Lakebase project exists, so a missing scope fails in seconds with
|
|
298
|
+
// a fix instead of at the final push after all provisioning (which then rolls back).
|
|
299
|
+
if (useGithub) {
|
|
300
|
+
report("Checking GitHub token scopes...");
|
|
301
|
+
const scope = await checkGitHubWorkflowScope();
|
|
302
|
+
if (!scope.ok) {
|
|
303
|
+
throw new Error(githubWorkflowScopePrereqMessage(scope.reason));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
292
307
|
// ── Step 1+2: GitHub repo + clone, OR local-only setup ────────
|
|
293
308
|
if (useGithub) {
|
|
294
309
|
report("Creating GitHub repository...", fullRepoName);
|
|
@@ -14,6 +14,7 @@ import { listBranches } from "./branch-utils.js";
|
|
|
14
14
|
import { verifyHooks } from "./project-verify.js";
|
|
15
15
|
import { detectLanguage } from "./schema-migrate.js";
|
|
16
16
|
import { detectWorkflowDrift } from "./workflow-drift.js";
|
|
17
|
+
import { checkGitHubScopes } from "../github/repo.js";
|
|
17
18
|
|
|
18
19
|
export type CheckStatus = "ok" | "warn" | "fail" | "skip";
|
|
19
20
|
|
|
@@ -593,6 +594,53 @@ async function checkGitRemote(projectDir: string): Promise<CheckResult> {
|
|
|
593
594
|
}
|
|
594
595
|
}
|
|
595
596
|
|
|
597
|
+
/**
|
|
598
|
+
* Probe whether the GitHub token carries the `workflow` scope needed to push
|
|
599
|
+
* `.github/workflows/*`. A missing scope is exactly why a scaffold push (or any
|
|
600
|
+
* later workflow edit) gets rejected at the very end and rolls back. Best-effort:
|
|
601
|
+
* no token, OR a fine-grained / GitHub App token (no visible OAuth scopes), OR
|
|
602
|
+
* an API error → `skip`, never a false `fail`. `probe` is injectable for tests.
|
|
603
|
+
*/
|
|
604
|
+
export async function checkGitHubTokenScope(
|
|
605
|
+
probe: () => Promise<{ granted: string[] | null; missing: string[] }> = () =>
|
|
606
|
+
checkGitHubScopes(["workflow"])
|
|
607
|
+
): Promise<CheckResult> {
|
|
608
|
+
try {
|
|
609
|
+
const { granted, missing } = await probe();
|
|
610
|
+
if (granted === null) {
|
|
611
|
+
return {
|
|
612
|
+
name: "github-token-scope",
|
|
613
|
+
status: "skip",
|
|
614
|
+
message:
|
|
615
|
+
"GitHub token scopes not visible (fine-grained PAT / App token) - `workflow` scope unverified",
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
if (missing.includes("workflow")) {
|
|
619
|
+
return {
|
|
620
|
+
name: "github-token-scope",
|
|
621
|
+
status: "fail",
|
|
622
|
+
message:
|
|
623
|
+
"GitHub token lacks the `workflow` scope - pushes touching .github/workflows/* will be rejected",
|
|
624
|
+
detail: { granted },
|
|
625
|
+
hint: "Grant it with `gh auth refresh -h github.com -s workflow`, re-sign in to GitHub in VS Code and approve the workflow scope, or set GITHUB_TOKEN to a PAT that includes `workflow`.",
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
return {
|
|
629
|
+
name: "github-token-scope",
|
|
630
|
+
status: "ok",
|
|
631
|
+
message: "GitHub token has the `workflow` scope",
|
|
632
|
+
detail: { granted },
|
|
633
|
+
};
|
|
634
|
+
} catch (err) {
|
|
635
|
+
return {
|
|
636
|
+
name: "github-token-scope",
|
|
637
|
+
status: "skip",
|
|
638
|
+
message: "GitHub token scope check skipped (no token resolved, or GitHub unreachable)",
|
|
639
|
+
detail: { error: (err as Error).message },
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
596
644
|
function checkLanguage(projectDir: string): CheckResult {
|
|
597
645
|
try {
|
|
598
646
|
const lang = detectLanguage(projectDir);
|
|
@@ -732,6 +780,7 @@ export async function runDoctor(args: DoctorArgs = {}): Promise<DoctorReport> {
|
|
|
732
780
|
host
|
|
733
781
|
);
|
|
734
782
|
const gitRemote = await checkGitRemote(projectDir);
|
|
783
|
+
const githubTokenScope = await checkGitHubTokenScope();
|
|
735
784
|
const language = checkLanguage(projectDir);
|
|
736
785
|
const hooks = checkHooks(projectDir);
|
|
737
786
|
const workflowDrift = checkWorkflowDrift(projectDir);
|
|
@@ -763,6 +812,7 @@ export async function runDoctor(args: DoctorArgs = {}): Promise<DoctorReport> {
|
|
|
763
812
|
configProfile,
|
|
764
813
|
lakebaseProject,
|
|
765
814
|
gitRemote,
|
|
815
|
+
githubTokenScope,
|
|
766
816
|
language,
|
|
767
817
|
hooks,
|
|
768
818
|
workflowDrift,
|
|
@@ -148,11 +148,6 @@ jobs:
|
|
|
148
148
|
# the CI branch is provisioned and fail fast. `--if-present` no-ops a
|
|
149
149
|
# client with no `test` script. The client's Playwright E2E runs later
|
|
150
150
|
# (its own step, gated on client/playwright.config.ts).
|
|
151
|
-
- name: Run client unit tests
|
|
152
|
-
if: hashFiles('client/package.json') != ''
|
|
153
|
-
working-directory: client
|
|
154
|
-
run: npm run test --if-present
|
|
155
|
-
|
|
156
151
|
# The official action installs to a user-writable path (no sudo). It's
|
|
157
152
|
# a no-op if a compatible databricks CLI is already on PATH.
|
|
158
153
|
- name: Install Databricks CLI
|
|
@@ -384,6 +379,20 @@ jobs:
|
|
|
384
379
|
--pretty
|
|
385
380
|
echo "Migrations completed."
|
|
386
381
|
|
|
382
|
+
- name: Run client unit tests
|
|
383
|
+
# The kit's client/vitest.globalSetup.ts boots a REAL backend over the /api
|
|
384
|
+
# boundary (never mock when a real counterpart exists), so the component suite
|
|
385
|
+
# NEEDS the CI Lakebase branch + DATABASE_URL. Run it AFTER datasource config +
|
|
386
|
+
# migrations, not before. No-op when there are no component tests (globalSetup
|
|
387
|
+
# returns early); skipped when there is no CI Lakebase branch (url empty).
|
|
388
|
+
if: hashFiles('client/package.json') != '' && steps.lakebase-db.outputs.url != ''
|
|
389
|
+
working-directory: client
|
|
390
|
+
env:
|
|
391
|
+
DATABASE_URL: ${{ env.DATABASE_URL }}
|
|
392
|
+
DB_USERNAME: ${{ env.DB_USERNAME }}
|
|
393
|
+
DB_PASSWORD: ${{ env.DB_PASSWORD }}
|
|
394
|
+
run: npm run test --if-present
|
|
395
|
+
|
|
387
396
|
- name: Run tests
|
|
388
397
|
env:
|
|
389
398
|
DATABASE_URL: ${{ env.DATABASE_URL }}
|