♻️ refactor(vscode): 设置项 autoBuildBranch 换成发布分支前缀与 Jenkins 任务

Claude-Session: https://claude.ai/code/session_01HTMgwaE3woqM5yvsHiuSAa
This commit is contained in:
cruldra committed 2026-08-31 23:38:53 +08:00
1 parent fa32d4a88b
commit 6f59b4f3fd
13 files changed
+149 -66

No files matched your search

+6 -2
View File
@@ -865,7 +865,9 @@ export class KanbanWebviewPanel {
autoReview: s.autoReview, autoReview: s.autoReview,
reviewPrompt: s.reviewPrompt, reviewPrompt: s.reviewPrompt,
devBranch: s.devBranch, devBranch: s.devBranch,
autoBuildBranch: s.autoBuildBranch, releaseBranchPrefix: s.releaseBranchPrefix,
jenkinsJob: s.jenkinsJob,
jenkinsProdHost: s.jenkinsProdHost,
worktreeDirectory: s.worktreeDirectory, worktreeDirectory: s.worktreeDirectory,
worktreeOpenWith: s.worktreeOpenWith, worktreeOpenWith: s.worktreeOpenWith,
pycharmCommand: s.pycharmCommand, pycharmCommand: s.pycharmCommand,
@@ -945,7 +947,9 @@ export class KanbanWebviewPanel {
autoReview: s.autoReview, autoReview: s.autoReview,
reviewPrompt: s.reviewPrompt, reviewPrompt: s.reviewPrompt,
devBranch: s.devBranch, devBranch: s.devBranch,
autoBuildBranch: s.autoBuildBranch, releaseBranchPrefix: s.releaseBranchPrefix,
jenkinsJob: s.jenkinsJob,
jenkinsProdHost: s.jenkinsProdHost,
worktreeDirectory: s.worktreeDirectory, worktreeDirectory: s.worktreeDirectory,
worktreeOpenWith: s.worktreeOpenWith, worktreeOpenWith: s.worktreeOpenWith,
pycharmCommand: s.pycharmCommand, pycharmCommand: s.pycharmCommand,
+3 -4
View File
@@ -5,7 +5,7 @@ import { logger } from '../../logging/logger'
/** /**
* 清理一个 feature 分支(远程 + 本地),供「拖到完成」和「手动删除 worktree」两处共用。 * 清理一个 feature 分支(远程 + 本地),供「拖到完成」和「手动删除 worktree」两处共用。
* *
* - 受保护分支(main/master/devBranch/autoBuildBranch)直接跳过,绝不删。 * - 受保护分支(main/master/devBranch)直接跳过,绝不删。
* - 远程删除走 gitea API,需 remote + token;缺任一则只删本地,不阻断。 * - 远程删除走 gitea API,需 remote + token;缺任一则只删本地,不阻断。
* - 本地删除是强删(deleteLocalBranch 内部 `git branch -D`):调用方语义是「连分支一起删」, * - 本地删除是强删(deleteLocalBranch 内部 `git branch -D`):调用方语义是「连分支一起删」,
* 未合并也照删。 * 未合并也照删。
@@ -20,17 +20,16 @@ export async function cleanupFeatureBranch(opts: {
branch: string branch: string
issueNumber: number issueNumber: number
devBranch?: string devBranch?: string
autoBuildBranch?: string
/** 缺 remote 或 token 时跳过远程删除,只删本地。 */ /** 缺 remote 或 token 时跳过远程删除,只删本地。 */
remote?: { host: string, owner: string, repo: string } remote?: { host: string, owner: string, repo: string }
token?: string token?: string
}): Promise<void> { }): Promise<void> {
const { workspaceRoot, branch, issueNumber, devBranch, autoBuildBranch, remote, token } = opts const { workspaceRoot, branch, issueNumber, devBranch, remote, token } = opts
if (!branch) if (!branch)
return return
const protectedBranches = new Set( const protectedBranches = new Set(
['main', 'master', devBranch, autoBuildBranch].filter((b): b is string => Boolean(b)), ['main', 'master', devBranch].filter((b): b is string => Boolean(b)),
) )
if (protectedBranches.has(branch)) { if (protectedBranches.has(branch)) {
logger.add({ level: 'warn', source: 'panel', message: `跳过受保护分支清理 ${branch} (issue #${issueNumber})` }) logger.add({ level: 'warn', source: 'panel', message: `跳过受保护分支清理 ${branch} (issue #${issueNumber})` })
+1 -1
View File
@@ -342,7 +342,7 @@ export async function handleHandoffStart(panel: KanbanWebviewPanel, issueNumber:
} }
if (branch) { if (branch) {
const settings = getSettings(panel.context) const settings = getSettings(panel.context)
await cleanupFeatureBranch({ workspaceRoot, branch, issueNumber, devBranch: settings.devBranch, autoBuildBranch: settings.autoBuildBranch }) await cleanupFeatureBranch({ workspaceRoot, branch, issueNumber, devBranch: settings.devBranch })
} }
// ⑦ 本机墓碑:sid/profile/worktreePath 归零。worktree 没删掉时保留 // ⑦ 本机墓碑:sid/profile/worktreePath 归零。worktree 没删掉时保留
-2
View File
@@ -506,7 +506,6 @@ export async function handleColumnChange(panel: KanbanWebviewPanel, issueNumber:
branch: featureBranch, branch: featureBranch,
issueNumber, issueNumber,
devBranch: settingsForBranchCleanup.devBranch, devBranch: settingsForBranchCleanup.devBranch,
autoBuildBranch: settingsForBranchCleanup.autoBuildBranch,
remote, remote,
token, token,
}) })
@@ -786,7 +785,6 @@ export async function handleResetToTodo(panel: KanbanWebviewPanel, issueNumber:
branch: featureBranch, branch: featureBranch,
issueNumber, issueNumber,
devBranch: settingsForBranchCleanup.devBranch, devBranch: settingsForBranchCleanup.devBranch,
autoBuildBranch: settingsForBranchCleanup.autoBuildBranch,
remote, remote,
token, token,
}) })
-1
View File
@@ -761,7 +761,6 @@ export async function handleImplement(
branch, branch,
issueNumber, issueNumber,
devBranch: settings.devBranch, devBranch: settings.devBranch,
autoBuildBranch: settings.autoBuildBranch,
remote, remote,
token, token,
}) })
+16 -8
View File
@@ -28,7 +28,9 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
autoReview: boolean autoReview: boolean
reviewPrompt: string reviewPrompt: string
devBranch: string devBranch: string
autoBuildBranch: string releaseBranchPrefix: string
jenkinsJob: string
jenkinsProdHost: string
worktreeDirectory: string worktreeDirectory: string
worktreeOpenWith: 'vscode' | 'pycharm' worktreeOpenWith: 'vscode' | 'pycharm'
pycharmCommand: string pycharmCommand: string
@@ -55,7 +57,10 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
const trimmedYtClose = payload.youtrackCloseCommand.trim() const trimmedYtClose = payload.youtrackCloseCommand.trim()
const trimmedYtToken = payload.youtrackToken.trim() const trimmedYtToken = payload.youtrackToken.trim()
const trimmedDevBranch = payload.devBranch.trim() const trimmedDevBranch = payload.devBranch.trim()
const trimmedAutoBuildBranch = payload.autoBuildBranch.trim() // 发布前缀 / Jenkins 任务 / 正式服 host:只 trim,空值回退在 getSettings 读时做。
const trimmedReleasePrefix = payload.releaseBranchPrefix.trim()
const trimmedJenkinsJob = payload.jenkinsJob.trim()
const trimmedJenkinsProdHost = payload.jenkinsProdHost.trim()
// worktree dir template: '' = "use default", so don't preserve blanks // worktree dir template: '' = "use default", so don't preserve blanks
// specially — getSettings falls back to the default at read time. // specially — getSettings falls back to the default at read time.
const trimmedWorktreeDir = payload.worktreeDirectory.trim() const trimmedWorktreeDir = payload.worktreeDirectory.trim()
@@ -101,7 +106,9 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
autoReview: payload.autoReview, autoReview: payload.autoReview,
reviewPrompt: payload.reviewPrompt || prev.reviewPrompt, reviewPrompt: payload.reviewPrompt || prev.reviewPrompt,
devBranch: trimmedDevBranch || prev.devBranch, devBranch: trimmedDevBranch || prev.devBranch,
autoBuildBranch: trimmedAutoBuildBranch, releaseBranchPrefix: trimmedReleasePrefix || prev.releaseBranchPrefix,
jenkinsJob: trimmedJenkinsJob,
jenkinsProdHost: trimmedJenkinsProdHost || prev.jenkinsProdHost,
worktreeDirectory: trimmedWorktreeDir || prev.worktreeDirectory, worktreeDirectory: trimmedWorktreeDir || prev.worktreeDirectory,
worktreeOpenWith: payload.worktreeOpenWith || prev.worktreeOpenWith, worktreeOpenWith: payload.worktreeOpenWith || prev.worktreeOpenWith,
pycharmCommand: trimmedPycharmCmd || prev.pycharmCommand, pycharmCommand: trimmedPycharmCmd || prev.pycharmCommand,
@@ -126,11 +133,10 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
implementPlanPrompt: payload.implementPlanPrompt, implementPlanPrompt: payload.implementPlanPrompt,
autoReview: payload.autoReview, autoReview: payload.autoReview,
reviewPrompt: payload.reviewPrompt, reviewPrompt: payload.reviewPrompt,
// Persist trimmed values; '' is meaningful for autoBuildBranch
// ("follow devBranch"), so don't coerce — getSettings handles the
// fallback at read time.
devBranch: trimmedDevBranch, devBranch: trimmedDevBranch,
autoBuildBranch: trimmedAutoBuildBranch, releaseBranchPrefix: trimmedReleasePrefix,
jenkinsJob: trimmedJenkinsJob,
jenkinsProdHost: trimmedJenkinsProdHost,
worktreeDirectory: trimmedWorktreeDir, worktreeDirectory: trimmedWorktreeDir,
worktreeOpenWith: payload.worktreeOpenWith, worktreeOpenWith: payload.worktreeOpenWith,
pycharmCommand: trimmedPycharmCmd, pycharmCommand: trimmedPycharmCmd,
@@ -233,7 +239,9 @@ export async function handleEditSettingsRequest(panel: KanbanWebviewPanel): Prom
autoReview: s.autoReview, autoReview: s.autoReview,
reviewPrompt: s.reviewPrompt, reviewPrompt: s.reviewPrompt,
devBranch: s.devBranch, devBranch: s.devBranch,
autoBuildBranch: s.autoBuildBranch, releaseBranchPrefix: s.releaseBranchPrefix,
jenkinsJob: s.jenkinsJob,
jenkinsProdHost: s.jenkinsProdHost,
worktreeDirectory: s.worktreeDirectory, worktreeDirectory: s.worktreeDirectory,
worktreeOpenWith: s.worktreeOpenWith, worktreeOpenWith: s.worktreeOpenWith,
pycharmCommand: s.pycharmCommand, pycharmCommand: s.pycharmCommand,
-1
View File
@@ -139,7 +139,6 @@ export async function handleDeleteWorktree(panel: KanbanWebviewPanel, issueNumbe
branch, branch,
issueNumber, issueNumber,
devBranch: settingsForHook.devBranch, devBranch: settingsForHook.devBranch,
autoBuildBranch: settingsForHook.autoBuildBranch,
remote: remote ? { host: remote.host, owner: remote.owner, repo: remote.repo } : undefined, remote: remote ? { host: remote.host, owner: remote.owner, repo: remote.repo } : undefined,
token, token,
}) })
+17 -9
View File
@@ -73,7 +73,9 @@ export type ExtensionToWebview
autoReview: boolean autoReview: boolean
reviewPrompt: string reviewPrompt: string
devBranch: string devBranch: string
autoBuildBranch: string releaseBranchPrefix: string
jenkinsJob: string
jenkinsProdHost: string
worktreeDirectory: string worktreeDirectory: string
worktreeOpenWith: 'vscode' | 'pycharm' worktreeOpenWith: 'vscode' | 'pycharm'
pycharmCommand: string pycharmCommand: string
@@ -109,13 +111,15 @@ export type ExtensionToWebview
| { type: 'logs/cleared' } | { type: 'logs/cleared' }
| { type: 'commit/state', running: boolean } | { type: 'commit/state', running: boolean }
| { type: 'commit/has-changes', value: boolean } | { type: 'commit/has-changes', value: boolean }
// 发布点状态:nextBranch 是今天要切的分支全名,由扩展侧算好,webview 不自己拼日期。
| { | {
type: 'branch-sync/status' type: 'release/status'
behind: number
devBranch: string devBranch: string
autoBuildBranch: string current?: string
unavailable?: boolean nextBranch: string
reason?: string unreleased: number
unavailable?: string
running: boolean
} }
| { type: 'env-lock/status', locked: boolean, fileCount: number, failedCount?: number } | { type: 'env-lock/status', locked: boolean, fileCount: number, failedCount?: number }
| { type: 'issue/remove', issueNumber: number } | { type: 'issue/remove', issueNumber: number }
@@ -145,7 +149,9 @@ export type WebviewToExtension
autoReview: boolean autoReview: boolean
reviewPrompt: string reviewPrompt: string
devBranch: string devBranch: string
autoBuildBranch: string releaseBranchPrefix: string
jenkinsJob: string
jenkinsProdHost: string
worktreeDirectory: string worktreeDirectory: string
worktreeOpenWith: 'vscode' | 'pycharm' worktreeOpenWith: 'vscode' | 'pycharm'
pycharmCommand: string pycharmCommand: string
@@ -200,8 +206,10 @@ export type WebviewToExtension
| { type: 'logs/clear' } | { type: 'logs/clear' }
| { type: 'commit/run' } | { type: 'commit/run' }
| { type: 'session/close-tab', issueNumber: number, kind: 'brainstorm' | 'implement' | 'review' | 'test' } | { type: 'session/close-tab', issueNumber: number, kind: 'brainstorm' | 'implement' | 'review' | 'test' }
| { type: 'branch-sync/check' } | { type: 'release/check' }
| { type: 'branch-sync/run' } | { type: 'release/cut' }
| { type: 'release/cherry-pick' }
| { type: 'release/deploy' }
| { type: 'env-lock/check' } | { type: 'env-lock/check' }
| { type: 'env-lock/toggle' } | { type: 'env-lock/toggle' }
| { type: 'issue/delete', issueNumber: number } | { type: 'issue/delete', issueNumber: number }
+25 -12
View File
@@ -15,6 +15,7 @@ import { readFileSync } from 'node:fs'
import path from 'node:path' import path from 'node:path'
import { seedCommitProfilePath } from '../cc/commitProfile' import { seedCommitProfilePath } from '../cc/commitProfile'
import { listClaudeProfiles } from '../cc/profiles' import { listClaudeProfiles } from '../cc/profiles'
import { normalizeReleasePrefix } from '../git/release'
/** /**
* Fallback prompt strings used when the on-disk markdown can't be read. * Fallback prompt strings used when the on-disk markdown can't be read.
@@ -88,11 +89,14 @@ export interface Settings {
/** Day-to-day development branch (e.g. `main`). Jenkins doesn't watch it. */ /** Day-to-day development branch (e.g. `main`). Jenkins doesn't watch it. */
devBranch: string devBranch: string
/** /**
* Branch the Gitea webhook → Jenkins job listens on. Empty string means * 发布分支名前缀(如 `release/`),远端该前缀下字典序最大的分支即当期发布点。
* "same as `devBranch`", in which case the branch-sync button stays * 读出时已归一化:trim、空回退默认、末尾补 `/`。
* disabled because there's nothing to fast-forward.
*/ */
autoBuildBranch: string releaseBranchPrefix: string
/** 正式服部署的 Jenkins 任务名;空串 = 不提供「部署到正式服」。 */
jenkinsJob: string
/** Jenkins 任务的 `REMOTE_HOST` 参数取值,空回退 `正式服`。 */
jenkinsProdHost: string
/** /**
* Directory template for the worktree created when implementing a plan. * Directory template for the worktree created when implementing a plan.
* Placeholders: `$project_root` (workspace abs path), `$project_name` (its * Placeholders: `$project_root` (workspace abs path), `$project_name` (its
@@ -215,7 +219,9 @@ function defaults(ctx: ExtensionContext): Settings {
autoReview: true, autoReview: true,
reviewPrompt: readDefaultPrompt(ctx.extensionPath, 'review'), reviewPrompt: readDefaultPrompt(ctx.extensionPath, 'review'),
devBranch: 'main', devBranch: 'main',
autoBuildBranch: '', releaseBranchPrefix: 'release/',
jenkinsJob: '',
jenkinsProdHost: '正式服',
worktreeDirectory: '~/Sources/worktree/$project_name/$feature_name', worktreeDirectory: '~/Sources/worktree/$project_name/$feature_name',
worktreeOpenWith: 'vscode', worktreeOpenWith: 'vscode',
pycharmCommand: 'pycharm', pycharmCommand: 'pycharm',
@@ -266,12 +272,17 @@ export function getSettings(ctx: ExtensionContext): Settings {
const devBranch = typeof stored.devBranch === 'string' && stored.devBranch.length > 0 const devBranch = typeof stored.devBranch === 'string' && stored.devBranch.length > 0
? stored.devBranch ? stored.devBranch
: base.devBranch : base.devBranch
// autoBuildBranch is kept as-is — '' is meaningful ("follow devBranch, sync // 发布前缀读出时归一化(空 → 默认、补尾 `/`),下游拼分支名不用再防御。
// disabled"), so we don't coerce to a default here. Anything non-string const releaseBranchPrefix = normalizeReleasePrefix(
// (legacy installs that never wrote it) collapses to ''. typeof stored.releaseBranchPrefix === 'string' ? stored.releaseBranchPrefix : base.releaseBranchPrefix,
const autoBuildBranch = typeof stored.autoBuildBranch === 'string' )
? stored.autoBuildBranch // jenkinsJob:'' 有意义(= 不提供部署动作),只认字符串类型。
: base.autoBuildBranch const jenkinsJob = typeof stored.jenkinsJob === 'string'
? stored.jenkinsJob.trim()
: base.jenkinsJob
const jenkinsProdHost = typeof stored.jenkinsProdHost === 'string' && stored.jenkinsProdHost.trim().length > 0
? stored.jenkinsProdHost.trim()
: base.jenkinsProdHost
// worktree dir template: empty/blank means "use the default template", so // worktree dir template: empty/blank means "use the default template", so
// fall back to base (unlike the hook paths below, where '' is meaningful). // fall back to base (unlike the hook paths below, where '' is meaningful).
const worktreeDirectory = typeof stored.worktreeDirectory === 'string' && stored.worktreeDirectory.length > 0 const worktreeDirectory = typeof stored.worktreeDirectory === 'string' && stored.worktreeDirectory.length > 0
@@ -349,7 +360,9 @@ export function getSettings(ctx: ExtensionContext): Settings {
autoReview, autoReview,
reviewPrompt, reviewPrompt,
devBranch, devBranch,
autoBuildBranch, releaseBranchPrefix,
jenkinsJob,
jenkinsProdHost,
worktreeDirectory, worktreeDirectory,
worktreeOpenWith, worktreeOpenWith,
pycharmCommand, pycharmCommand,
+3 -1
View File
@@ -523,7 +523,9 @@ export function App() {
initialAutoReview={settings?.autoReview ?? true} initialAutoReview={settings?.autoReview ?? true}
initialReviewPrompt={settings?.reviewPrompt ?? ''} initialReviewPrompt={settings?.reviewPrompt ?? ''}
initialDevBranch={settings?.devBranch ?? 'main'} initialDevBranch={settings?.devBranch ?? 'main'}
initialAutoBuildBranch={settings?.autoBuildBranch ?? ''} initialReleaseBranchPrefix={settings?.releaseBranchPrefix ?? 'release/'}
initialJenkinsJob={settings?.jenkinsJob ?? ''}
initialJenkinsProdHost={settings?.jenkinsProdHost ?? '正式服'}
initialWorktreeDirectory={settings?.worktreeDirectory ?? ''} initialWorktreeDirectory={settings?.worktreeDirectory ?? ''}
initialWorktreeOpenWith={settings?.worktreeOpenWith ?? 'vscode'} initialWorktreeOpenWith={settings?.worktreeOpenWith ?? 'vscode'}
initialPycharmCommand={settings?.pycharmCommand ?? 'pycharm'} initialPycharmCommand={settings?.pycharmCommand ?? 'pycharm'}
@@ -26,7 +26,9 @@ interface SubmitValues {
autoReview: boolean autoReview: boolean
reviewPrompt: string reviewPrompt: string
devBranch: string devBranch: string
autoBuildBranch: string releaseBranchPrefix: string
jenkinsJob: string
jenkinsProdHost: string
worktreeDirectory: string worktreeDirectory: string
worktreeOpenWith: 'vscode' | 'pycharm' worktreeOpenWith: 'vscode' | 'pycharm'
pycharmCommand: string pycharmCommand: string
@@ -73,7 +75,9 @@ export interface SettingsModalProps {
initialAutoReview: boolean initialAutoReview: boolean
initialReviewPrompt: string initialReviewPrompt: string
initialDevBranch: string initialDevBranch: string
initialAutoBuildBranch: string initialReleaseBranchPrefix: string
initialJenkinsJob: string
initialJenkinsProdHost: string
initialWorktreeDirectory: string initialWorktreeDirectory: string
initialWorktreeOpenWith: 'vscode' | 'pycharm' initialWorktreeOpenWith: 'vscode' | 'pycharm'
initialPycharmCommand: string initialPycharmCommand: string
@@ -156,7 +160,9 @@ export function SettingsModal({
initialAutoReview, initialAutoReview,
initialReviewPrompt, initialReviewPrompt,
initialDevBranch, initialDevBranch,
initialAutoBuildBranch, initialReleaseBranchPrefix,
initialJenkinsJob,
initialJenkinsProdHost,
initialWorktreeDirectory, initialWorktreeDirectory,
initialWorktreeOpenWith, initialWorktreeOpenWith,
initialPycharmCommand, initialPycharmCommand,
@@ -191,7 +197,9 @@ export function SettingsModal({
const [autoReview, setAutoReview] = useState(initialAutoReview) const [autoReview, setAutoReview] = useState(initialAutoReview)
const [reviewPrompt, setReviewPrompt] = useState(initialReviewPrompt) const [reviewPrompt, setReviewPrompt] = useState(initialReviewPrompt)
const [devBranch, setDevBranch] = useState(initialDevBranch) const [devBranch, setDevBranch] = useState(initialDevBranch)
const [autoBuildBranch, setAutoBuildBranch] = useState(initialAutoBuildBranch) const [releaseBranchPrefix, setReleaseBranchPrefix] = useState(initialReleaseBranchPrefix)
const [jenkinsJob, setJenkinsJob] = useState(initialJenkinsJob)
const [jenkinsProdHost, setJenkinsProdHost] = useState(initialJenkinsProdHost)
const [worktreeDirectory, setWorktreeDirectory] = useState(initialWorktreeDirectory) const [worktreeDirectory, setWorktreeDirectory] = useState(initialWorktreeDirectory)
const [worktreeOpenWith, setWorktreeOpenWith] = useState(initialWorktreeOpenWith) const [worktreeOpenWith, setWorktreeOpenWith] = useState(initialWorktreeOpenWith)
const [pycharmCommand, setPycharmCommand] = useState(initialPycharmCommand) const [pycharmCommand, setPycharmCommand] = useState(initialPycharmCommand)
@@ -228,7 +236,9 @@ export function SettingsModal({
setAutoReview(initialAutoReview) setAutoReview(initialAutoReview)
setReviewPrompt(initialReviewPrompt) setReviewPrompt(initialReviewPrompt)
setDevBranch(initialDevBranch) setDevBranch(initialDevBranch)
setAutoBuildBranch(initialAutoBuildBranch) setReleaseBranchPrefix(initialReleaseBranchPrefix)
setJenkinsJob(initialJenkinsJob)
setJenkinsProdHost(initialJenkinsProdHost)
setWorktreeDirectory(initialWorktreeDirectory) setWorktreeDirectory(initialWorktreeDirectory)
setWorktreeOpenWith(initialWorktreeOpenWith) setWorktreeOpenWith(initialWorktreeOpenWith)
setPycharmCommand(initialPycharmCommand) setPycharmCommand(initialPycharmCommand)
@@ -313,7 +323,9 @@ export function SettingsModal({
autoReview, autoReview,
reviewPrompt, reviewPrompt,
devBranch: devBranch.trim(), devBranch: devBranch.trim(),
autoBuildBranch: autoBuildBranch.trim(), releaseBranchPrefix: releaseBranchPrefix.trim(),
jenkinsJob: jenkinsJob.trim(),
jenkinsProdHost: jenkinsProdHost.trim(),
// worktree 目录模板:trim 后留空 = 用默认模板(getSettings 读时回退) // worktree 目录模板:trim 后留空 = 用默认模板(getSettings 读时回退)
worktreeDirectory: worktreeDirectory.trim(), worktreeDirectory: worktreeDirectory.trim(),
worktreeOpenWith, worktreeOpenWith,
@@ -455,7 +467,7 @@ export function SettingsModal({
日常推送的分支,留空默认 日常推送的分支,留空默认
{' '} {' '}
<code>main</code> <code>main</code>
。同步按钮把这条分支的最新提交快进到下面的构建分支。 。发布按钮从这条分支切发布分支、统计未发布提交。
</> </>
)} )}
> >
@@ -469,18 +481,43 @@ export function SettingsModal({
</Field> </Field>
<Field <Field
label="自动化构建分支" label="发布分支前缀"
hint="线上跑的发布分支名前缀,默认 release/,按钮会自动取最新的一个"
>
<input
type="text"
value={releaseBranchPrefix}
onChange={e => setReleaseBranchPrefix(e.target.value)}
placeholder="release/"
className={inputClass}
/>
</Field>
<Field
label="Jenkins 任务名"
hint={( hint={(
<> <>
gitea webhook → Jenkins 监听的分支。留空表示与开发分支相同,同步按钮会一直禁用。 留空则不显示「部署到正式服」;触发时执行
{' '}
<code>opencli jks build &lt;任务名&gt; -p REF=… -p REMOTE_HOST=…</code>
</> </>
)} )}
> >
<input <input
type="text" type="text"
value={autoBuildBranch} value={jenkinsJob}
onChange={e => setAutoBuildBranch(e.target.value)} onChange={e => setJenkinsJob(e.target.value)}
placeholder="留空 = 与开发分支相同" placeholder="留空 = 不提供部署"
className={inputClass}
/>
</Field>
<Field label="正式服 REMOTE_HOST 值">
<input
type="text"
value={jenkinsProdHost}
onChange={e => setJenkinsProdHost(e.target.value)}
placeholder="正式服"
className={inputClass} className={inputClass}
/> />
</Field> </Field>
+12 -4
View File
@@ -44,7 +44,9 @@ export interface SettingsValues {
autoReview: boolean autoReview: boolean
reviewPrompt: string reviewPrompt: string
devBranch: string devBranch: string
autoBuildBranch: string releaseBranchPrefix: string
jenkinsJob: string
jenkinsProdHost: string
worktreeDirectory: string worktreeDirectory: string
worktreeOpenWith: 'vscode' | 'pycharm' worktreeOpenWith: 'vscode' | 'pycharm'
pycharmCommand: string pycharmCommand: string
@@ -77,7 +79,9 @@ export interface SettingsOverlayState {
autoReview: boolean autoReview: boolean
reviewPrompt: string reviewPrompt: string
devBranch: string devBranch: string
autoBuildBranch: string releaseBranchPrefix: string
jenkinsJob: string
jenkinsProdHost: string
worktreeDirectory: string worktreeDirectory: string
worktreeOpenWith: 'vscode' | 'pycharm' worktreeOpenWith: 'vscode' | 'pycharm'
pycharmCommand: string pycharmCommand: string
@@ -369,7 +373,9 @@ export function useIssues(): UseIssuesResult {
autoReview: values.autoReview, autoReview: values.autoReview,
reviewPrompt: values.reviewPrompt, reviewPrompt: values.reviewPrompt,
devBranch: values.devBranch, devBranch: values.devBranch,
autoBuildBranch: values.autoBuildBranch, releaseBranchPrefix: values.releaseBranchPrefix,
jenkinsJob: values.jenkinsJob,
jenkinsProdHost: values.jenkinsProdHost,
worktreeDirectory: values.worktreeDirectory, worktreeDirectory: values.worktreeDirectory,
worktreeOpenWith: values.worktreeOpenWith, worktreeOpenWith: values.worktreeOpenWith,
pycharmCommand: values.pycharmCommand, pycharmCommand: values.pycharmCommand,
@@ -756,7 +762,9 @@ export function useIssues(): UseIssuesResult {
autoReview: msg.autoReview, autoReview: msg.autoReview,
reviewPrompt: msg.reviewPrompt, reviewPrompt: msg.reviewPrompt,
devBranch: msg.devBranch, devBranch: msg.devBranch,
autoBuildBranch: msg.autoBuildBranch, releaseBranchPrefix: msg.releaseBranchPrefix,
jenkinsJob: msg.jenkinsJob,
jenkinsProdHost: msg.jenkinsProdHost,
worktreeDirectory: msg.worktreeDirectory, worktreeDirectory: msg.worktreeDirectory,
worktreeOpenWith: msg.worktreeOpenWith, worktreeOpenWith: msg.worktreeOpenWith,
pycharmCommand: msg.pycharmCommand, pycharmCommand: msg.pycharmCommand,
+17 -9
View File
@@ -88,7 +88,9 @@ export type ExtensionToWebview
autoReview: boolean autoReview: boolean
reviewPrompt: string reviewPrompt: string
devBranch: string devBranch: string
autoBuildBranch: string releaseBranchPrefix: string
jenkinsJob: string
jenkinsProdHost: string
worktreeDirectory: string worktreeDirectory: string
worktreeOpenWith: 'vscode' | 'pycharm' worktreeOpenWith: 'vscode' | 'pycharm'
pycharmCommand: string pycharmCommand: string
@@ -124,13 +126,15 @@ export type ExtensionToWebview
| { type: 'logs/cleared' } | { type: 'logs/cleared' }
| { type: 'commit/state', running: boolean } | { type: 'commit/state', running: boolean }
| { type: 'commit/has-changes', value: boolean } | { type: 'commit/has-changes', value: boolean }
// 发布点状态:nextBranch 是今天要切的分支全名,由扩展侧算好,webview 不自己拼日期。
| { | {
type: 'branch-sync/status' type: 'release/status'
behind: number
devBranch: string devBranch: string
autoBuildBranch: string current?: string
unavailable?: boolean nextBranch: string
reason?: string unreleased: number
unavailable?: string
running: boolean
} }
| { type: 'env-lock/status', locked: boolean, fileCount: number, failedCount?: number } | { type: 'env-lock/status', locked: boolean, fileCount: number, failedCount?: number }
| { type: 'issue/remove', issueNumber: number } | { type: 'issue/remove', issueNumber: number }
@@ -160,7 +164,9 @@ export type WebviewToExtension
autoReview: boolean autoReview: boolean
reviewPrompt: string reviewPrompt: string
devBranch: string devBranch: string
autoBuildBranch: string releaseBranchPrefix: string
jenkinsJob: string
jenkinsProdHost: string
worktreeDirectory: string worktreeDirectory: string
worktreeOpenWith: 'vscode' | 'pycharm' worktreeOpenWith: 'vscode' | 'pycharm'
pycharmCommand: string pycharmCommand: string
@@ -215,8 +221,10 @@ export type WebviewToExtension
| { type: 'logs/clear' } | { type: 'logs/clear' }
| { type: 'commit/run' } | { type: 'commit/run' }
| { type: 'session/close-tab', issueNumber: number, kind: 'brainstorm' | 'implement' | 'review' | 'test' } | { type: 'session/close-tab', issueNumber: number, kind: 'brainstorm' | 'implement' | 'review' | 'test' }
| { type: 'branch-sync/check' } | { type: 'release/check' }
| { type: 'branch-sync/run' } | { type: 'release/cut' }
| { type: 'release/cherry-pick' }
| { type: 'release/deploy' }
| { type: 'env-lock/check' } | { type: 'env-lock/check' }
| { type: 'env-lock/toggle' } | { type: 'env-lock/toggle' }
| { type: 'issue/delete', issueNumber: number } | { type: 'issue/delete', issueNumber: number }