#feature: Jenkins 构建入口与自动创建 release 分支
加入 crm-web/crm-opm 并可跳转 Jenkins 发布页;自动创建 release 时 commit 使用 release-版本号,并跳过本地 git hook,避免 agent-be 被拦下。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -80,7 +80,22 @@
|
||||
<span class="font-mono text-sm font-semibold text-gray-800 truncate">{{ project.slug }}</span>
|
||||
<span class="text-[11px] text-gray-500 truncate" :title="project.name">{{ project.name }}</span>
|
||||
</span>
|
||||
<span class="block font-mono text-[11px] text-gray-400 truncate" :title="project.jenkins_job_name">{{ project.jenkins_job_name }}</span>
|
||||
<a
|
||||
v-if="jenkinsPageUrl(project)"
|
||||
:href="jenkinsPageUrl(project)"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="mt-0.5 inline-flex max-w-full items-center gap-1 font-mono text-[11px] text-blue-600 hover:text-blue-800 hover:underline"
|
||||
:title="'打开 Jenkins 发布页:' + project.jenkins_job_name"
|
||||
@click.stop
|
||||
>
|
||||
<span class="truncate">{{ project.jenkins_job_name }}</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="h-3 w-3 shrink-0">
|
||||
<path fill-rule="evenodd" d="M4.25 5.5a.75.75 0 00-.75.75v8.5c0 .414.336.75.75.75h8.5a.75.75 0 00.75-.75v-4a.75.75 0 011.5 0v4A2.25 2.25 0 0112.75 17h-8.5A2.25 2.25 0 012 14.75v-8.5A2.25 2.25 0 014.25 4h5a.75.75 0 010 1.5h-5z" clip-rule="evenodd" />
|
||||
<path fill-rule="evenodd" d="M6.194 12.753a.75.75 0 001.06.053L16.5 4.44v2.81a.75.75 0 001.5 0v-4.5a.75.75 0 00-.75-.75h-4.5a.75.75 0 000 1.5h2.553l-9.056 8.194a.75.75 0 00-.053 1.06z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</a>
|
||||
<span v-else class="block font-mono text-[11px] text-gray-400 truncate" :title="project.jenkins_job_name">{{ project.jenkins_job_name }}</span>
|
||||
</span>
|
||||
</label>
|
||||
</td>
|
||||
@@ -174,12 +189,34 @@
|
||||
<div class="mt-1 flex items-center gap-1.5 text-xs text-gray-700 min-w-0">
|
||||
<span class="font-mono font-semibold truncate" :title="record.project_slug">{{ record.project_slug || '-' }}</span>
|
||||
<span class="text-[11px] text-gray-400 truncate" :title="record.project_name">{{ record.project_name }}</span>
|
||||
<a
|
||||
v-if="jenkinsPageUrl(record)"
|
||||
:href="jenkinsPageUrl(record)"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="ml-auto inline-flex shrink-0 items-center gap-0.5 text-[11px] text-blue-600 hover:text-blue-800 hover:underline"
|
||||
title="打开 Jenkins 发布页"
|
||||
>
|
||||
Jenkins
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="h-3 w-3">
|
||||
<path fill-rule="evenodd" d="M4.25 5.5a.75.75 0 00-.75.75v8.5c0 .414.336.75.75.75h8.5a.75.75 0 00.75-.75v-4a.75.75 0 011.5 0v4A2.25 2.25 0 0112.75 17h-8.5A2.25 2.25 0 012 14.75v-8.5A2.25 2.25 0 014.25 4h5a.75.75 0 010 1.5h-5z" clip-rule="evenodd" />
|
||||
<path fill-rule="evenodd" d="M6.194 12.753a.75.75 0 001.06.053L16.5 4.44v2.81a.75.75 0 001.5 0v-4.5a.75.75 0 00-.75-.75h-4.5a.75.75 0 000 1.5h2.553l-9.056 8.194a.75.75 0 00-.053 1.06z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="mt-0.5 grid grid-cols-[3.25rem_minmax(0,1fr)] gap-1 text-[11px] text-gray-500">
|
||||
<span class="text-gray-400">project</span>
|
||||
<span class="font-mono truncate" :title="record.project_parameter">{{ record.project_parameter || '-' }}</span>
|
||||
<span class="text-gray-400">构建号</span>
|
||||
<span class="font-mono truncate">{{ record.build_number ? `#${record.build_number}` : '-' }}</span>
|
||||
<a
|
||||
v-if="jenkinsBuildUrl(record)"
|
||||
:href="jenkinsBuildUrl(record)"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="font-mono truncate text-blue-600 hover:text-blue-800 hover:underline"
|
||||
:title="'打开 Jenkins 构建 #' + record.build_number"
|
||||
>#{{ record.build_number }}</a>
|
||||
<span v-else class="font-mono truncate">{{ record.build_number ? `#${record.build_number}` : '-' }}</span>
|
||||
</div>
|
||||
<div v-if="record.message" class="mt-1 text-[11px] text-gray-400 truncate" :title="record.message">
|
||||
{{ record.message }}
|
||||
@@ -298,7 +335,7 @@ export default {
|
||||
ParameterControl
|
||||
},
|
||||
preferenceKey: 'toolbox.jenkinsBuilds.preferences.v1',
|
||||
cacheKey: 'toolbox.jenkinsBuilds.projectsCache.v1',
|
||||
cacheKey: 'toolbox.jenkinsBuilds.projectsCache.v2',
|
||||
operationRecordsKey: 'toolbox.jenkinsBuilds.operationRecords.v1',
|
||||
hiddenParameterNames: ['sql', 'masterCheck'],
|
||||
data() {
|
||||
@@ -308,6 +345,7 @@ export default {
|
||||
triggering: false,
|
||||
statusChecking: false,
|
||||
statusPollingTimer: null,
|
||||
jenkinsHost: '',
|
||||
projects: [],
|
||||
operationRecords: [],
|
||||
primaryParameterOrder: ['env', 'branchName', 'deploy', 'deployVersion'],
|
||||
@@ -344,17 +382,16 @@ export default {
|
||||
if (freshCachedProjects) {
|
||||
cachedBuildProjects = freshCachedProjects;
|
||||
this.applyProjects(cachedBuildProjects);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cachedBuildProjects) {
|
||||
cachedBuildProjects = this.loadProjectsCache({ allowExpired: true });
|
||||
}
|
||||
|
||||
if (cachedBuildProjects) {
|
||||
this.applyProjects(cachedBuildProjects);
|
||||
} else {
|
||||
this.loading = true;
|
||||
if (!cachedBuildProjects) {
|
||||
cachedBuildProjects = this.loadProjectsCache({ allowExpired: true });
|
||||
}
|
||||
|
||||
if (cachedBuildProjects) {
|
||||
this.applyProjects(cachedBuildProjects);
|
||||
} else {
|
||||
this.loading = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.refreshProjects({ silent: Boolean(cachedBuildProjects) });
|
||||
@@ -384,6 +421,7 @@ export default {
|
||||
}
|
||||
|
||||
cachedBuildProjects = data.data.projects || [];
|
||||
this.jenkinsHost = data.data.jenkins_host || this.jenkinsHost;
|
||||
this.saveProjectsCache(cachedBuildProjects);
|
||||
this.applyProjects(cachedBuildProjects, { preserveCurrentValues: true });
|
||||
|
||||
@@ -431,6 +469,10 @@ export default {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (cache.jenkins_host) {
|
||||
this.jenkinsHost = cache.jenkins_host;
|
||||
}
|
||||
|
||||
return cache.projects;
|
||||
} catch (error) {
|
||||
return null;
|
||||
@@ -439,6 +481,7 @@ export default {
|
||||
saveProjectsCache(projects) {
|
||||
window.localStorage.setItem(this.$options.cacheKey, JSON.stringify({
|
||||
date: this.todayKey(),
|
||||
jenkins_host: this.jenkinsHost,
|
||||
projects
|
||||
}));
|
||||
},
|
||||
@@ -515,6 +558,46 @@ export default {
|
||||
preferenceProjectKey(project) {
|
||||
return project.jenkins_job_name || project.slug;
|
||||
},
|
||||
jenkinsPageUrl(item) {
|
||||
if (!item) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (item.jenkins_job_url) {
|
||||
return item.jenkins_job_url;
|
||||
}
|
||||
|
||||
return this.buildJenkinsUrl(item.jenkins_job_name || item.job_name);
|
||||
},
|
||||
jenkinsBuildUrl(record) {
|
||||
if (!record?.build_number) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (record.build_url) {
|
||||
return record.build_url;
|
||||
}
|
||||
|
||||
return this.buildJenkinsUrl(record.job_name || record.jenkins_job_name, record.build_number);
|
||||
},
|
||||
buildJenkinsUrl(jobName, buildNumber = null) {
|
||||
if (!jobName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const segments = String(jobName).split('/').map((segment) => segment.trim()).filter(Boolean);
|
||||
if (segments.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const host = (this.jenkinsHost || '').replace(/\/$/, '');
|
||||
if (!host) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const path = '/job/' + segments.map(encodeURIComponent).join('/job/') + '/';
|
||||
return buildNumber ? `${host}${path}${buildNumber}/` : `${host}${path}`;
|
||||
},
|
||||
isBooleanParameter(parameter) {
|
||||
return String(parameter.type || '').toLowerCase().includes('boolean');
|
||||
},
|
||||
@@ -690,11 +773,14 @@ export default {
|
||||
project_slug: result.project_slug || requested.project_slug || '',
|
||||
project_name: result.project_name || requested.project_name || '',
|
||||
job_name: result.job_name || requested.job_name || '',
|
||||
jenkins_job_url: result.jenkins_job_url || this.buildJenkinsUrl(result.job_name || requested.job_name),
|
||||
project_parameter: this.formatParameterValue(requested.parameters?.project),
|
||||
status: result.success ? (canTrackBuild ? 'PENDING' : 'UNKNOWN') : 'FAILURE',
|
||||
queue_url: result.queue_url || null,
|
||||
build_number: result.build_number || null,
|
||||
build_url: null,
|
||||
build_url: result.build_url || (result.build_number
|
||||
? this.buildJenkinsUrl(result.job_name || requested.job_name, result.build_number)
|
||||
: null),
|
||||
parameters: requested.parameters || {},
|
||||
message: result.success
|
||||
? (canTrackBuild ? '已提交 Jenkins,等待发布结果' : '已提交 Jenkins,但未返回队列地址,无法自动跟踪或取消')
|
||||
@@ -788,6 +874,7 @@ export default {
|
||||
status: nextStatus,
|
||||
build_number: status.build_number || record.build_number,
|
||||
build_url: status.build_url || record.build_url,
|
||||
jenkins_job_url: status.jenkins_job_url || record.jenkins_job_url,
|
||||
message: status.message || null,
|
||||
cancelling: false
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user