feat: 上架版本号按分支拆分,master / develop 各自独立
原来 master 与 develop 共用一条 release 轨,版本号和构建号绑在一起。 现改为每个上架分支各有一条轨道(轨道名即分支名),自测分支仍共用 feature 轨。 - 轨道记录新增 kind(release/feature),branch_track 存轨道名 - 旧的共用 release 轨及更早的单轨结构,加载时自动按上架分支拆开, 已用构建号原样复制,拆分后各分支从原来的号继续递增 - 构建号递增时跨上架轨取同一 App_Ver 的最大值 +1:App Store 的构建号 唯一性按 MARKETING_VERSION 全局判定,避免两分支同版本号时重号被拒 - 分支管理页轨道选择改为「上架(本分支独立版本号)/ 自测(共用)」, 打包设置页按上架分支分块填写版本号 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BJaZ913U5GVdTkYHiRpvDU
This commit is contained in:
@@ -27,11 +27,13 @@ function mockFetch(url) {
|
||||
'/api/config/versions': {
|
||||
app_ver: '2.195.0',
|
||||
build_ver: '2.195.0.0',
|
||||
primary_track: 'main',
|
||||
tracks: {
|
||||
release: { app_ver: '2.195.0', build_ver: '2.195.0.0', build_map: {} },
|
||||
feature: { app_ver: '2.100.0', build_ver: '2.100.0.0', build_map: {} },
|
||||
main: { kind: 'release', app_ver: '2.195.0', build_ver: '2.195.0.0', build_map: {} },
|
||||
dev: { kind: 'release', app_ver: '2.196.0', build_ver: '2.196.0.0', build_map: {} },
|
||||
feature: { kind: 'feature', app_ver: '2.100.0', build_ver: '2.100.0.0', build_map: {} },
|
||||
},
|
||||
branch_track: { main: 'release', dev: 'release' },
|
||||
branch_track: { main: 'main', dev: 'dev' },
|
||||
},
|
||||
'/api/config': { apps: {}, schemes: {}, branches: ['main'] },
|
||||
}
|
||||
@@ -191,7 +193,7 @@ describe('ConfigView.vue', () => {
|
||||
expect(fetch.mock.calls.map(c => c[0])).toEqual(['/api/config/apps'])
|
||||
})
|
||||
|
||||
it('两条版本轨道各自独立展示与保存', async () => {
|
||||
it('每个上架分支与自测轨各自独立展示与保存', async () => {
|
||||
const calls = []
|
||||
fetch.mockImplementation((url, opts) => {
|
||||
if (url === '/api/config/versions' && opts?.method === 'PUT') {
|
||||
@@ -213,10 +215,11 @@ describe('ConfigView.vue', () => {
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
const inputs = wrapper.findAll('input[type="text"]')
|
||||
expect(inputs[0].element.value).toBe('2.195.0') // release App_Ver
|
||||
expect(inputs[2].element.value).toBe('2.100.0') // feature App_Ver
|
||||
expect(inputs[0].element.value).toBe('2.195.0') // main(上架)App_Ver
|
||||
expect(inputs[2].element.value).toBe('2.196.0') // dev(上架)App_Ver
|
||||
expect(inputs[4].element.value).toBe('2.100.0') // feature App_Ver
|
||||
|
||||
await inputs[2].setValue('2.101.0')
|
||||
await inputs[4].setValue('2.101.0')
|
||||
const saveBtn = wrapper.findAll('.btn-primary').find(b => b.text() === '保存自测版本号')
|
||||
await saveBtn.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
@@ -171,9 +171,9 @@
|
||||
<tr v-for="b in branches" :key="b">
|
||||
<td><strong>{{ b }}</strong></td>
|
||||
<td>
|
||||
<select :value="branchTrack[b] || 'feature'" style="width: auto; padding: 4px 8px;" @change="setBranchTrack(b, $event.target.value)">
|
||||
<option value="release">上架(master/develop)</option>
|
||||
<option value="feature">自测(feature)</option>
|
||||
<select :value="branchKind(b)" style="width: auto; padding: 4px 8px;" @change="setBranchTrack(b, $event.target.value)">
|
||||
<option value="release">上架(本分支独立版本号)</option>
|
||||
<option value="feature">自测(共用 feature 版本号)</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="action-btns">
|
||||
@@ -289,36 +289,40 @@
|
||||
<div v-if="tab === 'build'">
|
||||
<h2>打包设置</h2>
|
||||
<div style="max-width: 500px;">
|
||||
<h4 class="section-title">上架版本号(master / develop)</h4>
|
||||
<div class="form-group">
|
||||
<label>App_Ver(应用版本)</label>
|
||||
<input type="text" v-model="versions.release.app_ver" placeholder="2.180.0" @input="onAppVerInput('release')">
|
||||
<div style="font-size: 12px; color: #999; margin-top: 4px;">格式:主版本.次版本.修订号。master 与 develop 共用这一套版本号。</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Build_Ver(构建号)</label>
|
||||
<input type="text" v-model="versions.release.build_ver" placeholder="2.180.0.0">
|
||||
<div style="font-size: 12px; color: #999; margin-top: 4px;">
|
||||
四段数字,前三位须与 App_Ver 一致。修改 App_Ver 会自动切换为该版本号已记录的构建号;
|
||||
每个版本号的构建号独立递增,App_Store 打包时自动 +1。一般无需手动修改。
|
||||
<template v-for="t in releaseTracks" :key="t.name">
|
||||
<h4 class="section-title">上架版本号({{ t.branches.join(' / ') }})</h4>
|
||||
<div class="form-group">
|
||||
<label>App_Ver(应用版本)</label>
|
||||
<input type="text" v-model="versions[t.name].app_ver" placeholder="2.180.0" @input="onAppVerInput(t.name)">
|
||||
<div style="font-size: 12px; color: #999; margin-top: 4px;">格式:主版本.次版本.修订号。该版本号只用于 {{ t.branches.join(' / ') }} 分支,与其它分支互不影响。</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary" style="width: auto; padding: 10px 32px; margin-bottom: 24px;" @click="saveVersions('release')">保存上架版本号</button>
|
||||
<div class="form-group">
|
||||
<label>Build_Ver(构建号)</label>
|
||||
<input type="text" v-model="versions[t.name].build_ver" placeholder="2.180.0.0">
|
||||
<div style="font-size: 12px; color: #999; margin-top: 4px;">
|
||||
四段数字,前三位须与 App_Ver 一致。修改 App_Ver 会自动切换为该版本号已记录的构建号;
|
||||
每个版本号的构建号独立递增,App_Store 打包时自动 +1。一般无需手动修改。
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary" style="width: auto; padding: 10px 32px; margin-bottom: 24px;" @click="saveVersions(t.name)">保存 {{ t.name }} 版本号</button>
|
||||
</template>
|
||||
|
||||
<h4 class="section-title">自测版本号(feature 分支)</h4>
|
||||
<div class="form-group">
|
||||
<label>App_Ver(应用版本)</label>
|
||||
<input type="text" v-model="versions.feature.app_ver" placeholder="2.180.0" @input="onAppVerInput('feature')">
|
||||
<div style="font-size: 12px; color: #999; margin-top: 4px;">与上架版本号各自独立,互不影响。</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Build_Ver(构建号)</label>
|
||||
<input type="text" v-model="versions.feature.build_ver" placeholder="2.180.0.0">
|
||||
<div style="font-size: 12px; color: #999; margin-top: 4px;">
|
||||
仅供自测,打包时<strong>不会自动递增</strong>,始终使用这里填写的值(默认 .0)。需要区分时请手动修改。
|
||||
<template v-if="versions.feature">
|
||||
<h4 class="section-title">自测版本号(feature 分支)</h4>
|
||||
<div class="form-group">
|
||||
<label>App_Ver(应用版本)</label>
|
||||
<input type="text" v-model="versions.feature.app_ver" placeholder="2.180.0" @input="onAppVerInput('feature')">
|
||||
<div style="font-size: 12px; color: #999; margin-top: 4px;">所有自测分支共用,与上架版本号各自独立,互不影响。</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary" style="width: auto; padding: 10px 32px; margin-bottom: 24px;" @click="saveVersions('feature')">保存自测版本号</button>
|
||||
<div class="form-group">
|
||||
<label>Build_Ver(构建号)</label>
|
||||
<input type="text" v-model="versions.feature.build_ver" placeholder="2.180.0.0">
|
||||
<div style="font-size: 12px; color: #999; margin-top: 4px;">
|
||||
仅供自测,打包时<strong>不会自动递增</strong>,始终使用这里填写的值(默认 .0)。需要区分时请手动修改。
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary" style="width: auto; padding: 10px 32px; margin-bottom: 24px;" @click="saveVersions('feature')">保存自测版本号</button>
|
||||
</template>
|
||||
|
||||
<template v-if="isAdmin">
|
||||
<h4 class="section-title">打包参数</h4>
|
||||
@@ -654,27 +658,47 @@ const servers = ref({})
|
||||
const branches = ref([])
|
||||
const newBranch = ref('')
|
||||
const buildSettings = ref({})
|
||||
// 两条版本轨道:release(master/develop,上架用)与 feature(自测用),各自独立
|
||||
const versions = ref({
|
||||
release: { app_ver: '', build_ver: '' },
|
||||
feature: { app_ver: '', build_ver: '' },
|
||||
})
|
||||
const buildMap = ref({ release: {}, feature: {} })
|
||||
const branchTrack = ref({})
|
||||
// 版本轨道:每个上架分支(master、develop 等)一条独立轨道,轨道名即分支名;
|
||||
// 自测分支共用固定的 feature 轨。各轨道的版本号互不影响。
|
||||
const versions = ref({}) // 轨道名 -> { app_ver, build_ver }
|
||||
const buildMap = ref({}) // 轨道名 -> { App_Ver: 已用构建号 }
|
||||
const trackKind = ref({}) // 轨道名 -> release | feature
|
||||
const branchTrack = ref({}) // 分支名 -> 轨道名
|
||||
|
||||
const applyVersions = (data) => {
|
||||
const tracks = data.tracks || {}
|
||||
for (const track of ['release', 'feature']) {
|
||||
const item = tracks[track] || {}
|
||||
buildMap.value[track] = item.build_map || {}
|
||||
versions.value[track] = { app_ver: item.app_ver || '', build_ver: item.build_ver || '' }
|
||||
const nextVersions = {}
|
||||
const nextMap = {}
|
||||
const nextKind = {}
|
||||
for (const [name, item] of Object.entries(tracks)) {
|
||||
nextVersions[name] = { app_ver: item.app_ver || '', build_ver: item.build_ver || '' }
|
||||
nextMap[name] = item.build_map || {}
|
||||
nextKind[name] = item.kind || 'release'
|
||||
}
|
||||
versions.value = nextVersions
|
||||
buildMap.value = nextMap
|
||||
trackKind.value = nextKind
|
||||
branchTrack.value = data.branch_track || {}
|
||||
}
|
||||
|
||||
// 分支所属轨道的类型(供分支管理里的下拉框显示)
|
||||
const branchKind = (branch) => trackKind.value[branchTrack.value[branch]] || 'feature'
|
||||
|
||||
// 打包设置里按上架轨道分块展示;多个分支共用一条轨道时只显示一块
|
||||
const releaseTracks = computed(() => {
|
||||
const seen = new Set()
|
||||
return branches.value
|
||||
.map(b => branchTrack.value[b])
|
||||
.filter(name => name && trackKind.value[name] === 'release' && !seen.has(name) && seen.add(name))
|
||||
.map(name => ({
|
||||
name,
|
||||
branches: branches.value.filter(b => branchTrack.value[b] === name),
|
||||
}))
|
||||
})
|
||||
|
||||
// 修改 App_Ver 时,自动把 Build_Ver 切换为该版本号已记录的构建号(新版本号则为 .0)
|
||||
const onAppVerInput = (track) => {
|
||||
const appVer = (versions.value[track].app_ver || '').trim()
|
||||
const appVer = (versions.value[track]?.app_ver || '').trim()
|
||||
if (/^\d+\.\d+\.\d+$/.test(appVer)) {
|
||||
const n = Number((buildMap.value[track] || {})[appVer] || 0)
|
||||
versions.value[track].build_ver = `${appVer}.${n}`
|
||||
@@ -1194,7 +1218,8 @@ const setBranchTrack = async (name, track) => {
|
||||
const err = await res.json()
|
||||
throw new Error(err.detail || '修改失败')
|
||||
}
|
||||
branchTrack.value = { ...branchTrack.value, [name]: track }
|
||||
// 切到上架轨可能新建了轨道,重新拉取版本号
|
||||
applyVersions(await (await authFetch('/api/config/versions')).json())
|
||||
} catch (e) {
|
||||
alert('修改失败: ' + e.message)
|
||||
await loadData()
|
||||
@@ -1222,7 +1247,7 @@ const saveBuildSettings = async () => {
|
||||
alert('设置已保存')
|
||||
}
|
||||
|
||||
const saveVersions = async (track = 'release') => {
|
||||
const saveVersions = async (track) => {
|
||||
try {
|
||||
const res = await authFetch('/api/config/versions', {
|
||||
method: 'PUT',
|
||||
|
||||
Reference in New Issue
Block a user