Merge remote-tracking branch 'origin/master' into feat/pixel_art
This commit is contained in:
@@ -47,6 +47,10 @@ pipeline {
|
||||
steps {
|
||||
sh '''
|
||||
set -euo pipefail
|
||||
ACTION="${ACTION:-}"
|
||||
SOURCE_BRANCH="${SOURCE_BRANCH:-}"
|
||||
COMMIT_HASH="${COMMIT_HASH:-}"
|
||||
DEPLOYMENT_ID="${DEPLOYMENT_ID:-}"
|
||||
case "${ACTION}" in DEPLOY|STATUS|UNINSTALL) ;; *) exit 1 ;; esac
|
||||
if [ -n "${SOURCE_BRANCH}" ]; then
|
||||
git check-ref-format --branch "${SOURCE_BRANCH}" >/dev/null
|
||||
@@ -89,13 +93,13 @@ pipeline {
|
||||
withCredentials([sshUserPrivateKey(credentialsId: env.GIT_REMOTE_CREDENTIAL_ID, keyFileVariable: 'GENARRATIVE_GIT_SSH_KEY')]) {
|
||||
sh '''
|
||||
set -euo pipefail
|
||||
SOURCE_BRANCH="${SOURCE_BRANCH}" \
|
||||
COMMIT_HASH="${COMMIT_HASH}" \
|
||||
GIT_REMOTE_URL="${GIT_REMOTE_URL}" \
|
||||
SOURCE_BRANCH="${SOURCE_BRANCH:-}" \
|
||||
COMMIT_HASH="${COMMIT_HASH:-}" \
|
||||
GIT_REMOTE_URL="${GIT_REMOTE_URL:-}" \
|
||||
SOURCE_COMMIT_FILE=".jenkins-source-commit" \
|
||||
GENARRATIVE_JENKINS_REUSE_EXISTING_CHECKOUT="true" \
|
||||
GIT_SSH_COMMAND="ssh -i ${GENARRATIVE_GIT_SSH_KEY} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new" \
|
||||
"${WORKSPACE}/scripts/jenkins-checkout-source.sh"
|
||||
bash "${WORKSPACE}/scripts/jenkins-checkout-source.sh"
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,37 @@
|
||||
<keepDependencies>false</keepDependencies>
|
||||
<properties>
|
||||
<hudson.model.ParametersDefinitionProperty>
|
||||
<parameterDefinitions/>
|
||||
<parameterDefinitions>
|
||||
<hudson.model.ChoiceParameterDefinition>
|
||||
<name>ACTION</name>
|
||||
<description>部署、查询状态或卸载分支预览容器</description>
|
||||
<choices class="java.util.Arrays$ArrayList">
|
||||
<a class="string-array">
|
||||
<string>DEPLOY</string>
|
||||
<string>STATUS</string>
|
||||
<string>UNINSTALL</string>
|
||||
</a>
|
||||
</choices>
|
||||
</hudson.model.ChoiceParameterDefinition>
|
||||
<hudson.model.StringParameterDefinition>
|
||||
<name>SOURCE_BRANCH</name>
|
||||
<description>源码分支;DEPLOY 和 UNINSTALL 必填</description>
|
||||
<defaultValue></defaultValue>
|
||||
<trim>true</trim>
|
||||
</hudson.model.StringParameterDefinition>
|
||||
<hudson.model.StringParameterDefinition>
|
||||
<name>COMMIT_HASH</name>
|
||||
<description>可选;必须是 SOURCE_BRANCH 历史中的 commit</description>
|
||||
<defaultValue></defaultValue>
|
||||
<trim>true</trim>
|
||||
</hudson.model.StringParameterDefinition>
|
||||
<hudson.model.StringParameterDefinition>
|
||||
<name>DEPLOYMENT_ID</name>
|
||||
<description>预览实例稳定 ID</description>
|
||||
<defaultValue></defaultValue>
|
||||
<trim>true</trim>
|
||||
</hudson.model.StringParameterDefinition>
|
||||
</parameterDefinitions>
|
||||
</hudson.model.ParametersDefinitionProperty>
|
||||
</properties>
|
||||
<definition class="org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition" plugin="workflow-cps">
|
||||
|
||||
@@ -70,6 +70,21 @@ assertIncludes(
|
||||
'disableConcurrentBuilds()',
|
||||
'Jenkins Job 必须禁止并发构建。',
|
||||
);
|
||||
assertIncludes(
|
||||
jenkinsfile,
|
||||
'COMMIT_HASH="${COMMIT_HASH:-}"',
|
||||
'Jenkins Checkout 阶段必须允许 COMMIT_HASH 未导出或为空。',
|
||||
);
|
||||
assertIncludes(
|
||||
jenkinsfile,
|
||||
'bash "${WORKSPACE}/scripts/jenkins-checkout-source.sh"',
|
||||
'Jenkins Checkout 阶段必须显式使用 bash 执行源码检出脚本。',
|
||||
);
|
||||
assertExcludes(
|
||||
jenkinsfile,
|
||||
'COMMIT_HASH="${COMMIT_HASH}"',
|
||||
'Jenkins Checkout 阶段不得在 set -u 下直接展开未导出的 COMMIT_HASH。',
|
||||
);
|
||||
assertIncludes(deployer, 'flock -x 9', '部署脚本必须使用跨进程独占锁。');
|
||||
assertIncludes(
|
||||
deployer,
|
||||
@@ -132,6 +147,11 @@ assertIncludes(
|
||||
'<scriptPath>jenkins/Jenkinsfile.preview-deployer</scriptPath>',
|
||||
'Jenkins Job 必须从受保护 master 读取固定流水线。',
|
||||
);
|
||||
assertIncludes(
|
||||
jobConfig,
|
||||
'<hudson.model.ChoiceParameterDefinition>',
|
||||
'Jenkins Job 首次触发前必须已经声明 buildWithParameters 参数。',
|
||||
);
|
||||
assertIncludes(
|
||||
nginx,
|
||||
'location ^~ /api/preview-deployer/',
|
||||
|
||||
@@ -274,11 +274,27 @@ impl JenkinsClient {
|
||||
}
|
||||
|
||||
fn resolve_trusted_url(&self, value: &str) -> Result<Url, String> {
|
||||
let url = Url::parse(value)
|
||||
let returned = Url::parse(value)
|
||||
.or_else(|_| self.job_url.join(value))
|
||||
.map_err(|_| "Jenkins 返回了无效 URL".to_string())?;
|
||||
self.ensure_same_origin(&url)?;
|
||||
Ok(url)
|
||||
if !returned.username().is_empty()
|
||||
|| returned.password().is_some()
|
||||
|| !returned.path().starts_with(self.root_url.path())
|
||||
{
|
||||
return Err("Jenkins 返回了非受信源 URL".to_string());
|
||||
}
|
||||
let relative_path = returned
|
||||
.path()
|
||||
.strip_prefix(self.root_url.path())
|
||||
.ok_or_else(|| "Jenkins 返回了非受信路径".to_string())?;
|
||||
let mut trusted = self
|
||||
.root_url
|
||||
.join(relative_path)
|
||||
.map_err(|_| "Jenkins 返回了无效 URL".to_string())?;
|
||||
trusted.set_query(returned.query());
|
||||
trusted.set_fragment(None);
|
||||
self.ensure_same_origin(&trusted)?;
|
||||
Ok(trusted)
|
||||
}
|
||||
|
||||
fn ensure_same_origin(&self, url: &Url) -> Result<(), String> {
|
||||
|
||||
@@ -95,7 +95,7 @@ async fn mock_trigger(
|
||||
|
||||
async fn mock_queue(axum::extract::Path(id): axum::extract::Path<u64>) -> Json<Value> {
|
||||
Json(
|
||||
json!({"cancelled": false, "executable": {"url": format!("/jenkins/job/shared/job/Genarrative-Preview-Deployer/{id}/")}}),
|
||||
json!({"cancelled": false, "executable": {"url": format!("http://192.168.35.82:8080/jenkins/job/shared/job/Genarrative-Preview-Deployer/{id}/")}}),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user