ai-project-manage-cli 7.1.20 → 7.1.24
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.
|
@@ -452,6 +452,116 @@ async function ensureRemoteBaselineBranch(cwd, baselineBranch) {
|
|
|
452
452
|
`[apm] \u8FDC\u7A0B\u4E0D\u5B58\u5728\u57FA\u7EBF\u5206\u652F origin/${baselineBranch}\uFF0C\u8BF7\u786E\u8BA4\u4ED3\u5E93\u9ED8\u8BA4\u5206\u652F\u5DF2\u63A8\u9001\u5230 origin`
|
|
453
453
|
);
|
|
454
454
|
}
|
|
455
|
+
async function branchHasChangesAgainstBase(cwd, baseBranch, headBranch) {
|
|
456
|
+
const base = baseBranch.trim().replace(/^origin\//, "");
|
|
457
|
+
const head = headBranch.trim().replace(/^origin\//, "");
|
|
458
|
+
if (!base || !head) return false;
|
|
459
|
+
await execGit(cwd, ["fetch", "origin", base], true);
|
|
460
|
+
let headRef = head;
|
|
461
|
+
try {
|
|
462
|
+
await execGit(cwd, ["fetch", "origin", head], true);
|
|
463
|
+
await execGit(cwd, ["rev-parse", "--verify", `origin/${head}`], true);
|
|
464
|
+
headRef = `origin/${head}`;
|
|
465
|
+
} catch {
|
|
466
|
+
await execGit(cwd, ["rev-parse", "--verify", head], true);
|
|
467
|
+
}
|
|
468
|
+
const baseRef = `origin/${base}`;
|
|
469
|
+
const ahead = (await execGit(cwd, ["rev-list", "--count", `${baseRef}..${headRef}`], true)).trim();
|
|
470
|
+
if ((Number.parseInt(ahead, 10) || 0) <= 0) {
|
|
471
|
+
return false;
|
|
472
|
+
}
|
|
473
|
+
try {
|
|
474
|
+
await execGit(cwd, ["diff", "--quiet", `${baseRef}...${headRef}`], true);
|
|
475
|
+
return false;
|
|
476
|
+
} catch {
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
var FEATURE_BRANCH_RE = /^feat\/(task|session)-.+/;
|
|
481
|
+
function isFeatureBranchName(branch) {
|
|
482
|
+
return FEATURE_BRANCH_RE.test(branch.trim().replace(/^origin\//, ""));
|
|
483
|
+
}
|
|
484
|
+
async function resolveFeatureBranchBaseFromGit(cwd, headBranch) {
|
|
485
|
+
const head = headBranch.trim().replace(/^origin\//, "");
|
|
486
|
+
if (!head) {
|
|
487
|
+
throw new Error("[apm] head \u5206\u652F\u540D\u4E3A\u7A7A\uFF0C\u65E0\u6CD5\u63A8\u65AD\u57FA\u7EBF");
|
|
488
|
+
}
|
|
489
|
+
try {
|
|
490
|
+
const reflog = await execGit(
|
|
491
|
+
cwd,
|
|
492
|
+
["reflog", "show", "--date=iso", head],
|
|
493
|
+
true
|
|
494
|
+
);
|
|
495
|
+
for (const line of reflog.split("\n")) {
|
|
496
|
+
const created = line.match(
|
|
497
|
+
/Created from (?:refs\/remotes\/origin\/|origin\/)?(\S+)/i
|
|
498
|
+
);
|
|
499
|
+
if (created?.[1]) {
|
|
500
|
+
const name = created[1].replace(/^origin\//, "");
|
|
501
|
+
if (name && name !== head && !isFeatureBranchName(name)) {
|
|
502
|
+
return name;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const moving = line.match(
|
|
506
|
+
/checkout: moving from (\S+) to (?:origin\/)?\S+/i
|
|
507
|
+
);
|
|
508
|
+
if (moving?.[1]) {
|
|
509
|
+
const from = moving[1].replace(/^origin\//, "");
|
|
510
|
+
if (from && from !== head && !isFeatureBranchName(from)) {
|
|
511
|
+
return from;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
} catch {
|
|
516
|
+
}
|
|
517
|
+
await execGit(cwd, ["fetch", "origin", "--prune"], true);
|
|
518
|
+
let headRef = head;
|
|
519
|
+
try {
|
|
520
|
+
await execGit(cwd, ["rev-parse", "--verify", `origin/${head}`], true);
|
|
521
|
+
headRef = `origin/${head}`;
|
|
522
|
+
} catch {
|
|
523
|
+
await execGit(cwd, ["rev-parse", "--verify", head], true);
|
|
524
|
+
}
|
|
525
|
+
const refsOut = await execGit(
|
|
526
|
+
cwd,
|
|
527
|
+
["for-each-ref", "--format=%(refname:short)", "refs/remotes/origin/"],
|
|
528
|
+
true
|
|
529
|
+
);
|
|
530
|
+
let best = null;
|
|
531
|
+
for (const ref of refsOut.split("\n").map((s) => s.trim()).filter(Boolean)) {
|
|
532
|
+
const name = ref.replace(/^origin\//, "");
|
|
533
|
+
if (!name || name === "HEAD" || name === head || isFeatureBranchName(name)) {
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
try {
|
|
537
|
+
await execGit(
|
|
538
|
+
cwd,
|
|
539
|
+
["merge-base", "--is-ancestor", `origin/${name}`, headRef],
|
|
540
|
+
true
|
|
541
|
+
);
|
|
542
|
+
const ahead = Number.parseInt(
|
|
543
|
+
(await execGit(
|
|
544
|
+
cwd,
|
|
545
|
+
["rev-list", "--count", `origin/${name}..${headRef}`],
|
|
546
|
+
true
|
|
547
|
+
)).trim(),
|
|
548
|
+
10
|
|
549
|
+
);
|
|
550
|
+
if (!Number.isFinite(ahead) || ahead < 0) continue;
|
|
551
|
+
if (!best || ahead < best.ahead) {
|
|
552
|
+
best = { name, ahead };
|
|
553
|
+
}
|
|
554
|
+
} catch {
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
if (best) {
|
|
559
|
+
return best.name;
|
|
560
|
+
}
|
|
561
|
+
throw new Error(
|
|
562
|
+
`[apm] \u65E0\u6CD5\u63A8\u65AD ${head} \u57FA\u4E8E\u54EA\u6761\u5206\u652F\u521B\u5EFA\uFF0C\u8BF7\u786E\u8BA4\u672C\u5730 reflog \u6216 origin \u8FDC\u7A0B\u5206\u652F`
|
|
563
|
+
);
|
|
564
|
+
}
|
|
455
565
|
async function hasUpstream(cwd) {
|
|
456
566
|
try {
|
|
457
567
|
await execGit(cwd, ["rev-parse", "--abbrev-ref", "@{upstream}"], true);
|
|
@@ -3108,60 +3218,198 @@ function shouldEnsureWebIdePullRequests(action) {
|
|
|
3108
3218
|
function shouldEnsureWebIdePullRequestsAfterAgent(action) {
|
|
3109
3219
|
return POST_AGENT_PR_ACTIONS.has(action);
|
|
3110
3220
|
}
|
|
3221
|
+
function formatWebIdePullRequestSummary(result) {
|
|
3222
|
+
const lines = [];
|
|
3223
|
+
lines.push("## PR \u521B\u5EFA\u7ED3\u679C");
|
|
3224
|
+
lines.push(
|
|
3225
|
+
`\u5408\u8BA1\uFF1A\u6210\u529F ${result.ensured} \u6761\uFF0C\u65E0\u53D8\u66F4\u8DF3\u8FC7 ${result.skippedNoChanges} \u6761\uFF0C\u5176\u4ED6\u8DF3\u8FC7 ${result.skipped} \u6761\uFF0C\u5931\u8D25 ${result.failed} \u6761\u3002`
|
|
3226
|
+
);
|
|
3227
|
+
if (result.items.length === 0) {
|
|
3228
|
+
lines.push("\u672A\u5904\u7406\u4EFB\u4F55\u4ED3\u5E93\u3002");
|
|
3229
|
+
return lines.join("\n");
|
|
3230
|
+
}
|
|
3231
|
+
lines.push("");
|
|
3232
|
+
for (const item of result.items) {
|
|
3233
|
+
if (item.outcome === "created") {
|
|
3234
|
+
const num = item.number != null && item.number > 0 ? `#${item.number}` : "\uFF08\u65E0\u7F16\u53F7\uFF09";
|
|
3235
|
+
const branch = item.headBranch && item.baseBranch ? `${item.headBranch} \u2192 ${item.baseBranch}` : item.baseBranch ? `\u76EE\u6807\u5206\u652F ${item.baseBranch}` : "";
|
|
3236
|
+
const state = item.state ? `\u72B6\u6001 ${item.state}` : "";
|
|
3237
|
+
const url = item.url?.trim() ? item.url.trim() : "";
|
|
3238
|
+
lines.push(
|
|
3239
|
+
`- **${item.label}**\uFF1A\u5DF2\u521B\u5EFA ${num}${branch ? `\uFF0C${branch}` : ""}${state ? `\uFF0C${state}` : ""}${url ? `\uFF0C${url}` : ""}`
|
|
3240
|
+
);
|
|
3241
|
+
continue;
|
|
3242
|
+
}
|
|
3243
|
+
if (item.outcome === "skipped_no_changes") {
|
|
3244
|
+
lines.push(
|
|
3245
|
+
`- **${item.label}**\uFF1A\u76F8\u5BF9\u57FA\u7EBF ${item.baseBranch || "\uFF08\u672A\u77E5\uFF09"} \u65E0\u4EE3\u7801\u53D8\u66F4\uFF0C\u672A\u521B\u5EFA PR`
|
|
3246
|
+
);
|
|
3247
|
+
continue;
|
|
3248
|
+
}
|
|
3249
|
+
if (item.outcome === "skipped") {
|
|
3250
|
+
lines.push(`- **${item.label}**\uFF1A\u5DF2\u8DF3\u8FC7 \u2014 ${item.detail}`);
|
|
3251
|
+
continue;
|
|
3252
|
+
}
|
|
3253
|
+
lines.push(`- **${item.label}**\uFF1A\u521B\u5EFA\u5931\u8D25 \u2014 ${item.detail}`);
|
|
3254
|
+
}
|
|
3255
|
+
return lines.join("\n");
|
|
3256
|
+
}
|
|
3111
3257
|
async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
3112
3258
|
const api = createApmApiClient(cfg);
|
|
3259
|
+
const empty = () => ({
|
|
3260
|
+
ensured: 0,
|
|
3261
|
+
skipped: 0,
|
|
3262
|
+
skippedNoChanges: 0,
|
|
3263
|
+
failed: 0,
|
|
3264
|
+
items: [],
|
|
3265
|
+
tips: []
|
|
3266
|
+
});
|
|
3113
3267
|
let repoRoots;
|
|
3114
3268
|
try {
|
|
3115
3269
|
const manifest = loadWorkspaceReposCache(workdir);
|
|
3116
3270
|
repoRoots = resolveWorkspaceRepoAbsolutePaths(manifest);
|
|
3117
3271
|
} catch (err) {
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3272
|
+
const tip = `\u8BFB\u53D6\u4ED3\u5E93\u6E05\u5355\u5931\u8D25: ${err instanceof Error ? err.message : err}`;
|
|
3273
|
+
console.warn(`[apm] WebIDE PR\uFF1A${tip}`);
|
|
3274
|
+
return {
|
|
3275
|
+
...empty(),
|
|
3276
|
+
failed: 1,
|
|
3277
|
+
tips: [tip],
|
|
3278
|
+
items: [
|
|
3279
|
+
{
|
|
3280
|
+
label: "\u5DE5\u4F5C\u533A",
|
|
3281
|
+
outcome: "failed",
|
|
3282
|
+
detail: tip
|
|
3283
|
+
}
|
|
3284
|
+
]
|
|
3285
|
+
};
|
|
3123
3286
|
}
|
|
3287
|
+
const expectedHead = `feat/task-${taskId}`;
|
|
3124
3288
|
console.log(
|
|
3125
|
-
`[apm] WebIDE PR\uFF1A\u51C6\u5907\
|
|
3289
|
+
`[apm] WebIDE PR\uFF1A\u51C6\u5907\u68C0\u67E5 ${repoRoots.length} \u4E2A\u4ED3\u5E93\uFF08\u671F\u671B\u7279\u6027\u5206\u652F ${expectedHead}\uFF09`
|
|
3126
3290
|
);
|
|
3127
3291
|
let ensured = 0;
|
|
3128
3292
|
let skipped = 0;
|
|
3293
|
+
let skippedNoChanges = 0;
|
|
3129
3294
|
let failed = 0;
|
|
3295
|
+
const tips = [];
|
|
3296
|
+
const items = [];
|
|
3130
3297
|
for (const gitRoot of repoRoots) {
|
|
3131
3298
|
const label = formatRepoLabel(workdir, gitRoot);
|
|
3132
3299
|
try {
|
|
3300
|
+
const current = await getCurrentBranch(gitRoot);
|
|
3301
|
+
if (!isFeatureBranchName(current)) {
|
|
3302
|
+
const tip = `${label}\uFF1A\u5F53\u524D\u5206\u652F ${current} \u4E0D\u662F feat/task-* / feat/session-*\uFF0C\u4E0D\u7B26\u5408\u521B\u5EFA PR \u6761\u4EF6`;
|
|
3303
|
+
console.warn(`[apm] WebIDE PR\uFF1A${tip}`);
|
|
3304
|
+
tips.push(tip);
|
|
3305
|
+
skipped += 1;
|
|
3306
|
+
items.push({
|
|
3307
|
+
label,
|
|
3308
|
+
outcome: "skipped",
|
|
3309
|
+
headBranch: current,
|
|
3310
|
+
detail: tip
|
|
3311
|
+
});
|
|
3312
|
+
continue;
|
|
3313
|
+
}
|
|
3314
|
+
if (current !== expectedHead) {
|
|
3315
|
+
const tip = `${label}\uFF1A\u5F53\u524D\u4E3A ${current}\uFF0C\u671F\u671B ${expectedHead}\uFF0C\u5DF2\u8DF3\u8FC7`;
|
|
3316
|
+
console.warn(`[apm] WebIDE PR\uFF1A${tip}`);
|
|
3317
|
+
tips.push(tip);
|
|
3318
|
+
skipped += 1;
|
|
3319
|
+
items.push({
|
|
3320
|
+
label,
|
|
3321
|
+
outcome: "skipped",
|
|
3322
|
+
headBranch: current,
|
|
3323
|
+
detail: tip
|
|
3324
|
+
});
|
|
3325
|
+
continue;
|
|
3326
|
+
}
|
|
3327
|
+
const headBranch = current;
|
|
3133
3328
|
const originUrl = await tryReadGitOriginUrl(gitRoot);
|
|
3134
3329
|
if (!originUrl) {
|
|
3135
|
-
|
|
3330
|
+
const tip = `${label}\uFF1A\u65E0 remote.origin.url`;
|
|
3331
|
+
console.warn(`[apm] WebIDE PR\uFF1A\u8DF3\u8FC7 ${tip}`);
|
|
3332
|
+
tips.push(tip);
|
|
3136
3333
|
skipped += 1;
|
|
3334
|
+
items.push({
|
|
3335
|
+
label,
|
|
3336
|
+
outcome: "skipped",
|
|
3337
|
+
headBranch,
|
|
3338
|
+
detail: tip
|
|
3339
|
+
});
|
|
3137
3340
|
continue;
|
|
3138
3341
|
}
|
|
3139
3342
|
const matched = await api.cli.matchRepository({ url: originUrl });
|
|
3140
3343
|
const repositoryId = matched.repositoryId?.trim();
|
|
3141
3344
|
if (!repositoryId) {
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
);
|
|
3345
|
+
const tip = `${label}\uFF1A\u5E73\u53F0\u672A\u767B\u8BB0\u4ED3\u5E93 ${originUrl}`;
|
|
3346
|
+
console.warn(`[apm] WebIDE PR\uFF1A\u8DF3\u8FC7 ${tip}`);
|
|
3347
|
+
tips.push(tip);
|
|
3145
3348
|
skipped += 1;
|
|
3349
|
+
items.push({
|
|
3350
|
+
label,
|
|
3351
|
+
outcome: "skipped",
|
|
3352
|
+
headBranch,
|
|
3353
|
+
detail: tip
|
|
3354
|
+
});
|
|
3355
|
+
continue;
|
|
3356
|
+
}
|
|
3357
|
+
const baseBranch = await resolveFeatureBranchBaseFromGit(
|
|
3358
|
+
gitRoot,
|
|
3359
|
+
headBranch
|
|
3360
|
+
);
|
|
3361
|
+
const hasChanges = await branchHasChangesAgainstBase(
|
|
3362
|
+
gitRoot,
|
|
3363
|
+
baseBranch,
|
|
3364
|
+
headBranch
|
|
3365
|
+
);
|
|
3366
|
+
if (!hasChanges) {
|
|
3367
|
+
const tip = `${label}\uFF1A\u76F8\u5BF9\u57FA\u7EBF ${baseBranch} \u65E0\u4EE3\u7801\u53D8\u66F4\uFF0C\u65E0\u9700\u521B\u5EFA PR`;
|
|
3368
|
+
console.log(`[apm] WebIDE PR\uFF1A${tip}`);
|
|
3369
|
+
tips.push(tip);
|
|
3370
|
+
skippedNoChanges += 1;
|
|
3371
|
+
items.push({
|
|
3372
|
+
label,
|
|
3373
|
+
outcome: "skipped_no_changes",
|
|
3374
|
+
headBranch,
|
|
3375
|
+
baseBranch,
|
|
3376
|
+
detail: tip
|
|
3377
|
+
});
|
|
3146
3378
|
continue;
|
|
3147
3379
|
}
|
|
3148
3380
|
const pr = await api.cli.createWebIdeDraftPullRequest({
|
|
3149
3381
|
taskId,
|
|
3150
|
-
repositoryId
|
|
3382
|
+
repositoryId,
|
|
3383
|
+
headBranch,
|
|
3384
|
+
baseBranch
|
|
3151
3385
|
});
|
|
3152
3386
|
ensured += 1;
|
|
3387
|
+
items.push({
|
|
3388
|
+
label,
|
|
3389
|
+
outcome: "created",
|
|
3390
|
+
headBranch,
|
|
3391
|
+
baseBranch,
|
|
3392
|
+
number: pr.number,
|
|
3393
|
+
state: pr.state,
|
|
3394
|
+
url: pr.url,
|
|
3395
|
+
detail: `\u5DF2\u521B\u5EFA #${pr.number} ${headBranch} \u2192 ${baseBranch}`
|
|
3396
|
+
});
|
|
3153
3397
|
console.log(
|
|
3154
|
-
`[apm] WebIDE PR\uFF1A${label} \u2192 #${pr.number} ${pr.state} ${pr.url || ""}`
|
|
3398
|
+
`[apm] WebIDE PR\uFF1A${label} \u2192 #${pr.number} ${pr.state} ${headBranch} \u2192 ${baseBranch} ${pr.url || ""}`
|
|
3155
3399
|
);
|
|
3156
3400
|
} catch (err) {
|
|
3157
3401
|
failed += 1;
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3402
|
+
const tip = `${label}\uFF1A${err instanceof Error ? err.message : err}`;
|
|
3403
|
+
console.warn(`[apm] WebIDE PR\uFF1A\u5931\u8D25 ${tip}`);
|
|
3404
|
+
tips.push(tip);
|
|
3405
|
+
items.push({
|
|
3406
|
+
label,
|
|
3407
|
+
outcome: "failed",
|
|
3408
|
+
detail: tip
|
|
3409
|
+
});
|
|
3162
3410
|
}
|
|
3163
3411
|
}
|
|
3164
|
-
return { ensured, skipped, failed };
|
|
3412
|
+
return { ensured, skipped, skippedNoChanges, failed, items, tips };
|
|
3165
3413
|
}
|
|
3166
3414
|
|
|
3167
3415
|
// src/version.ts
|
|
@@ -3687,9 +3935,38 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3687
3935
|
);
|
|
3688
3936
|
}
|
|
3689
3937
|
const prResult = await ensureWebIdePullRequests(cfg, taskId, workdir);
|
|
3938
|
+
if (prResult.tips.length > 0) {
|
|
3939
|
+
for (const tip of prResult.tips) {
|
|
3940
|
+
console.log(`[apm] webide create-pr \u63D0\u793A: ${tip}`);
|
|
3941
|
+
}
|
|
3942
|
+
}
|
|
3943
|
+
try {
|
|
3944
|
+
await appendContent(
|
|
3945
|
+
cfg,
|
|
3946
|
+
messageId,
|
|
3947
|
+
formatWebIdePullRequestSummary(prResult)
|
|
3948
|
+
);
|
|
3949
|
+
} catch (appendErr) {
|
|
3950
|
+
console.warn(
|
|
3951
|
+
"[apm] webide create-pr \u8FFD\u52A0 PR \u7ED3\u679C\u5931\u8D25:",
|
|
3952
|
+
appendErr instanceof Error ? appendErr.message : appendErr
|
|
3953
|
+
);
|
|
3954
|
+
}
|
|
3690
3955
|
if (prResult.ensured === 0) {
|
|
3691
|
-
|
|
3692
|
-
|
|
3956
|
+
if (prResult.failed > 0) {
|
|
3957
|
+
throw new Error(
|
|
3958
|
+
`\u521B\u5EFA PR \u5931\u8D25\uFF08${prResult.failed} \u4E2A\u4ED3\u5E93\u51FA\u9519\uFF09${prResult.tips[0] ? `\uFF1A${prResult.tips[0]}` : ""}`
|
|
3959
|
+
);
|
|
3960
|
+
}
|
|
3961
|
+
if (prResult.skippedNoChanges > 0 && prResult.skipped === 0) {
|
|
3962
|
+
console.log(
|
|
3963
|
+
"[apm] webide create-pr\uFF1A\u5404\u4ED3\u5E93\u76F8\u5BF9\u63A8\u65AD\u57FA\u7EBF\u5747\u65E0\u53D8\u66F4\uFF0C\u8DF3\u8FC7\u521B\u5EFA PR"
|
|
3964
|
+
);
|
|
3965
|
+
} else {
|
|
3966
|
+
throw new Error(
|
|
3967
|
+
prResult.tips[0] || "\u672A\u80FD\u521B\u5EFA PR\uFF1A\u8BF7\u786E\u8BA4\u5404\u4ED3\u5F53\u524D\u4F4D\u4E8E feat/task-* \u5206\u652F\uFF0C\u4E14 remote \u5DF2\u5728\u5E73\u53F0\u767B\u8BB0"
|
|
3968
|
+
);
|
|
3969
|
+
}
|
|
3693
3970
|
}
|
|
3694
3971
|
}
|
|
3695
3972
|
if (projectId) {
|
package/package.json
CHANGED
package/template/AGENTS.md
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
- reply.md:当需要回复消息时需要读取这个文档,记住回复规则
|
|
31
31
|
- write_doc.md:当需要写文档时需要读取这个文档,记住写文档的规则
|
|
32
32
|
- webide_git_commit.md:WebIDE 开发/修码时读取,按规范分轮 commit,结束前 push
|
|
33
|
+
- webide_sql_change.md:WebIDE 开发/修码时读取;若有数据表或 SQL 变更,须在 AppendMessage 中醒目提示
|
|
33
34
|
- webide_testcase.md:WebIDE 生成测试用例时读取,按规范编写并提交用例
|
|
34
35
|
- webide_merge.md:WebIDE 验收通过后读取;直接调用 MergeWebIdePullRequests 合并代码
|
|
35
36
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## WebIDE 数据表 / SQL 变更提示
|
|
2
|
+
|
|
3
|
+
适用场景:WebIDE 开发(`skip-plan` / `start-develop`)与修码(`fix-and-retest` / `report-defect`)。
|
|
4
|
+
|
|
5
|
+
### 何时必须提示
|
|
6
|
+
|
|
7
|
+
本轮若涉及任一情况,结束前的 **AppendMessage 必须单独醒目提示**:
|
|
8
|
+
|
|
9
|
+
- 数据表结构变更(建表、改字段、删字段、索引、约束等)
|
|
10
|
+
- 需在目标库执行的 SQL(DDL / DML、数据修复脚本)
|
|
11
|
+
- 后端新增或修改了 migration、Mapper/XML、手写 SQL 脚本等可落地的 SQL 产物
|
|
12
|
+
|
|
13
|
+
### AppendMessage 怎么写
|
|
14
|
+
|
|
15
|
+
在回复中增加小节(标题可用「数据表 / SQL 变更」),至少包含:
|
|
16
|
+
|
|
17
|
+
1. **涉及表**:表名列表与变更类型(如新增列、建表)
|
|
18
|
+
2. **SQL 产物路径**:仓库内相关文件路径(若有)
|
|
19
|
+
3. **待执行 SQL**:完整、可复制执行的语句,放在 ` ```sql ` 代码块中,按执行顺序列出;禁止用 `...` 省略表名/字段名
|
|
20
|
+
4. **执行提醒**:明确告知用户需在对应环境数据库执行(若本轮未自动执行)
|
|
21
|
+
|
|
22
|
+
多仓时注明 SQL 属于哪个仓库(如后端仓)。
|
|
23
|
+
|
|
24
|
+
### 无变更时
|
|
25
|
+
|
|
26
|
+
未触及数据表与 SQL 时,**不要**硬凑该小节。
|