Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
test
autotest-playwright-web-spd
Commits
a238d36b
Commit
a238d36b
authored
Oct 24, 2026
by
liguangyu06
Browse files
补充 spd-ui-verify 文档与 Jenkins 建任务脚本,明确不发邮件
parent
a9af67a1
Changes
4
Hide whitespace changes
Inline
Side-by-side
docs/Jenkins配置指南.md
View file @
a238d36b
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
不要选「自由风格」里的
**Execute Windows batch command**
手写一长串命令。
不要选「自由风格」里的
**Execute Windows batch command**
手写一长串命令。
选
**Pipeline**
,它会自动读仓库里的
`Jenkinsfile`
。流水线已改成
**Windows 的 cmd**
,不用 Git Bash。
选
**Pipeline**
,它会自动读仓库里的
`Jenkinsfile`
。流水线已改成
**Windows 的 cmd**
,不用 Git Bash。
首页原来的
`spd3.0`
、电解任务不要动。
日常验证新建
**`spd-ui-verify`**
(见
[
jenkins-job-spd-ui-verify.md
](
./jenkins-job-spd-ui-verify.md
)
)
;定时冒烟可另建
`spd-ui-smoke`
。
首页原来的
`spd3.0`
、电解任务不要动。
与现有
**`SPD`**
同一 Jenkins:日常验证复制
`SPD`
建
**`spd-ui-verify`**
,Script Path 改为
`Jenkinsfile.verify`
(见
[
jenkins-job-spd-ui-verify.md
](
./jenkins-job-spd-ui-verify.md
)
)。
---
---
...
...
docs/jenkins-job-spd-ui-verify.md
View file @
a238d36b
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
用于
**手工触发**
的冒烟/单模块验证;夜间
**`SPD`**
仍用
`Jenkinsfile`
跑 full/nightly 并
**照常发邮件**
。
用于
**手工触发**
的冒烟/单模块验证;夜间
**`SPD`**
仍用
`Jenkinsfile`
跑 full/nightly 并
**照常发邮件**
。
**不要**
给
`spd-ui-verify`
配 Build periodically;需要时点
**Build with Parameters**
。
**不要**
给
`spd-ui-verify`
配 Build periodically;需要时点
**Build with Parameters**
。
**不发邮件**
(验证流水线已去掉邮件步骤;
报告只看
本任务
**Playwright Report**
)
。
**不发邮件**
:
`Jenkinsfile.verify`
无 SMTP/摘要邮件步骤;任务里勿保留
`REPORT_EMAIL_*`
参数或「构建后发邮件」。
报告只看
**Playwright Report**
。
## 1. 新建任务(推荐:复制 SPD)
## 1. 新建任务(推荐:复制 SPD)
...
...
package.json
View file @
a238d36b
...
@@ -28,6 +28,7 @@
...
@@ -28,6 +28,7 @@
"quarantine:sync"
:
"node scripts/sync-quarantine.mjs"
,
"quarantine:sync"
:
"node scripts/sync-quarantine.mjs"
,
"quarantine:apply"
:
"node scripts/sync-quarantine.mjs --write"
,
"quarantine:apply"
:
"node scripts/sync-quarantine.mjs --write"
,
"email:summary"
:
"node scripts/ci-email-summary.mjs"
,
"email:summary"
:
"node scripts/ci-email-summary.mjs"
,
"jenkins:create-verify"
:
"node scripts/jenkins/create-spd-ui-verify-job.mjs"
,
"test:quarantine"
:
"node scripts/run-ci.mjs --suite=quarantine"
,
"test:quarantine"
:
"node scripts/run-ci.mjs --suite=quarantine"
,
"test:smoke"
:
"playwright test tests/spd/login.spec.ts tests/spd/home.spec.ts --grep @smoke"
,
"test:smoke"
:
"playwright test tests/spd/login.spec.ts tests/spd/home.spec.ts --grep @smoke"
,
"test:smoke:allure"
:
"ALLURE=1 npm run test:smoke && npm run allure:generate"
,
"test:smoke:allure"
:
"ALLURE=1 npm run test:smoke && npm run allure:generate"
,
...
...
scripts/jenkins/create-spd-ui-verify-job.mjs
0 → 100644
View file @
a238d36b
#!/usr/bin/env node
/**
* 在 Jenkins 上复制 SPD 任务为 spd-ui-verify,并改 Script Path、去掉定时与构建后邮件。
*
* 用法(凭据勿写入仓库,用环境变量):
* JENKINS_URL=http://10.17.65.19:8080 \
* JENKINS_USER=你的账号 \
* JENKINS_TOKEN=API_Token \
* node scripts/jenkins/create-spd-ui-verify-job.mjs
*
* 需要具备「创建任务 / 配置任务」权限(只读报告账号通常不够)。
*/
import
process
from
'
node:process
'
;
const
JENKINS_URL
=
(
process
.
env
.
JENKINS_URL
||
'
http://10.17.65.19:8080
'
).
replace
(
/
\/
$/
,
''
);
const
USER
=
process
.
env
.
JENKINS_USER
||
process
.
env
.
JENKINS_USERNAME
||
''
;
const
TOKEN
=
process
.
env
.
JENKINS_TOKEN
||
process
.
env
.
JENKINS_API_TOKEN
||
process
.
env
.
JENKINS_PASSWORD
||
''
;
const
SOURCE
=
process
.
env
.
JENKINS_COPY_FROM
||
'
SPD
'
;
const
TARGET
=
process
.
env
.
JENKINS_VERIFY_JOB
||
'
spd-ui-verify
'
;
const
SCRIPT_PATH
=
process
.
env
.
JENKINS_VERIFY_SCRIPT
||
'
Jenkinsfile.verify
'
;
function
authHeader
()
{
if
(
!
USER
||
!
TOKEN
)
{
console
.
error
(
'
[jenkins] 请设置 JENKINS_USER 与 JENKINS_TOKEN(或 JENKINS_API_TOKEN)
'
);
process
.
exit
(
2
);
}
const
basic
=
Buffer
.
from
(
`
${
USER
}
:
${
TOKEN
}
`
,
'
utf8
'
).
toString
(
'
base64
'
);
return
`Basic
${
basic
}
`
;
}
async
function
jenkinsFetch
(
path
,
{
method
=
'
GET
'
,
headers
=
{},
body
}
=
{})
{
const
url
=
`
${
JENKINS_URL
}${
path
.
startsWith
(
'
/
'
)
?
path
:
`/
${
path
}
`
}
`
;
const
res
=
await
fetch
(
url
,
{
method
,
headers
:
{
Authorization
:
authHeader
(),
...
headers
,
},
body
,
});
const
text
=
await
res
.
text
();
return
{
res
,
text
};
}
async
function
getCrumb
()
{
const
{
res
,
text
}
=
await
jenkinsFetch
(
'
/crumbIssuer/api/json
'
);
if
(
!
res
.
ok
)
{
return
{
field
:
null
,
value
:
null
};
}
try
{
const
j
=
JSON
.
parse
(
text
);
return
{
field
:
j
.
crumbRequestField
,
value
:
j
.
crumb
};
}
catch
{
return
{
field
:
null
,
value
:
null
};
}
}
async
function
jobExists
(
name
)
{
const
{
res
}
=
await
jenkinsFetch
(
`/job/
${
encodeURIComponent
(
name
)}
/api/json`
);
return
res
.
status
===
200
;
}
function
patchConfigXml
(
xml
)
{
let
out
=
xml
;
out
=
out
.
replace
(
/<scriptPath>Jenkinsfile<
\/
scriptPath>/
,
`<scriptPath>
${
SCRIPT_PATH
}
</scriptPath>`
);
out
=
out
.
replace
(
/<scriptPath>.*
?
<
\/
scriptPath>/
,
`<scriptPath>
${
SCRIPT_PATH
}
</scriptPath>`
);
out
=
out
.
replace
(
/<triggers>
[\s\S]
*
?
<
\/
triggers>
\s
*/g
,
''
);
out
=
out
.
replace
(
/<hudson
\.
tasks
\.
Mailer
[\s\S]
*
?
<
\/
hudson
\.
tasks
\.
Mailer>/g
,
''
);
out
=
out
.
replace
(
/<hudson
\.
plugins
\.
emailext
[\s\S]
*
?
<
\/
hudson
\.
plugins
\.
emailext>/g
,
''
,
);
if
(
!
out
.
includes
(
'
<description>
'
))
{
out
=
out
.
replace
(
/<description
\/
>/
,
'
<description>日常验证(smoke/单模块),手工触发,不发邮件。Script: Jenkinsfile.verify</description>
'
,
);
}
return
out
;
}
async
function
createFromCopy
(
crumb
)
{
const
qs
=
new
URLSearchParams
({
name
:
TARGET
,
mode
:
'
copy
'
,
from
:
SOURCE
});
const
headers
=
{
'
Content-Type
'
:
'
application/xml; charset=UTF-8
'
};
if
(
crumb
.
field
&&
crumb
.
value
)
{
headers
[
crumb
.
field
]
=
crumb
.
value
;
}
const
{
res
,
text
}
=
await
jenkinsFetch
(
`/createItem?
${
qs
}
`
,
{
method
:
'
POST
'
,
headers
,
body
:
''
,
});
if
(
res
.
status
===
200
||
res
.
status
===
302
)
{
return
true
;
}
console
.
error
(
`[jenkins] 复制任务失败 HTTP
${
res
.
status
}
:
${
text
.
slice
(
0
,
500
)}
`
);
return
false
;
}
async
function
updateConfig
(
crumb
)
{
const
{
res
,
text
}
=
await
jenkinsFetch
(
`/job/
${
encodeURIComponent
(
TARGET
)}
/config.xml`
);
if
(
!
res
.
ok
)
{
console
.
error
(
`[jenkins] 读取 config.xml 失败 HTTP
${
res
.
status
}
`
);
process
.
exit
(
1
);
}
const
patched
=
patchConfigXml
(
text
);
const
headers
=
{
'
Content-Type
'
:
'
text/xml; charset=UTF-8
'
,
};
if
(
crumb
.
field
&&
crumb
.
value
)
{
headers
[
crumb
.
field
]
=
crumb
.
value
;
}
const
post
=
await
jenkinsFetch
(
`/job/
${
encodeURIComponent
(
TARGET
)}
/config.xml`
,
{
method
:
'
POST
'
,
headers
,
body
:
patched
,
});
if
(
!
post
.
res
.
ok
)
{
console
.
error
(
`[jenkins] 更新 config.xml 失败 HTTP
${
post
.
res
.
status
}
:
${
post
.
text
.
slice
(
0
,
500
)}
`
);
process
.
exit
(
1
);
}
}
async
function
main
()
{
console
.
log
(
`[jenkins]
${
JENKINS_URL
}
source=
${
SOURCE
}
target=
${
TARGET
}
script=
${
SCRIPT_PATH
}
`
);
const
me
=
await
jenkinsFetch
(
'
/me/api/json
'
);
if
(
!
me
.
res
.
ok
)
{
console
.
error
(
`[jenkins] 登录失败 HTTP
${
me
.
res
.
status
}
(检查账号、API Token、权限)`
);
process
.
exit
(
1
);
}
const
crumb
=
await
getCrumb
();
if
(
await
jobExists
(
TARGET
))
{
console
.
log
(
`[jenkins] 任务
${
TARGET
}
已存在,仅更新 config.xml`
);
}
else
{
const
ok
=
await
createFromCopy
(
crumb
);
if
(
!
ok
)
{
process
.
exit
(
1
);
}
console
.
log
(
`[jenkins] 已从
${
SOURCE
}
复制为
${
TARGET
}
`
);
}
await
updateConfig
(
crumb
);
console
.
log
(
`[jenkins] 完成:
${
JENKINS_URL
}
/job/
${
TARGET
}
/`
);
console
.
log
(
'
[jenkins] 请在 Jenkins 点 Build with Parameters(默认 SUITE=smoke)试跑。
'
);
}
main
().
catch
((
err
)
=>
{
console
.
error
(
'
[jenkins]
'
,
err
);
process
.
exit
(
1
);
});
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment