mirror of
https://github.com/status-im/status-app.git
synced 2026-08-27 07:01:14 +00:00
355 lines
12 KiB
Groovy
355 lines
12 KiB
Groovy
#!/usr/bin/env groovy
|
|
library 'status-jenkins-lib@v1.9.46'
|
|
|
|
/* Windows benchmarks for nightly, pull requests, and release candidates.
|
|
*
|
|
* Two Jenkins jobs share this file:
|
|
* - nightly-benchmark-windows-master — cron; empty CHANGE_ID/RELEASE_VERSION
|
|
* - status-app/e2e/manual-benchmark-windows — parameterized PR/RC runs
|
|
*/
|
|
|
|
QT_VERSION = "6.11.0"
|
|
NIGHTLY_BUILD_SOURCE = 'status-app/systems/windows/x86_64/package'
|
|
|
|
pipeline {
|
|
agent {
|
|
label "windows && x86_64 && qt-${QT_VERSION} && windows-e2e-benchmark"
|
|
}
|
|
|
|
parameters {
|
|
string(
|
|
name: 'GIT_REF',
|
|
description: 'Git branch to checkout.',
|
|
defaultValue: 'master'
|
|
)
|
|
string(
|
|
name: 'BUILD_SOURCE',
|
|
description: 'URL to tar.gz file OR path to Jenkins build.',
|
|
defaultValue: 'status-app/systems/windows/x86_64/package'
|
|
)
|
|
string(
|
|
name: 'CHANGE_ID',
|
|
description: 'PR number. Set this for a pull-request run.',
|
|
defaultValue: ''
|
|
)
|
|
string(
|
|
name: 'RELEASE_VERSION',
|
|
description: 'Release or RC version, for example 2.39.0-rc.1. Set this for a release run.',
|
|
defaultValue: ''
|
|
)
|
|
string(
|
|
name: 'TEST_NAME',
|
|
description: 'Paste test name/part of test name to run specific test.',
|
|
defaultValue: ''
|
|
)
|
|
string(
|
|
name: 'TEST_SCOPE_FLAG',
|
|
description: 'Paste a known mark to run tests labeled with this mark',
|
|
defaultValue: ''
|
|
)
|
|
string(
|
|
name: 'TESTRAIL_RUN_NAME',
|
|
description: 'Test run name in Test Rail.',
|
|
defaultValue: ''
|
|
)
|
|
choice(
|
|
name: 'LOG_LEVEL',
|
|
description: 'Log level for pytest.',
|
|
choices: ['INFO', 'DEBUG', 'TRACE', 'WARNING', 'CRITICAL']
|
|
)
|
|
booleanParam(
|
|
name: 'PUBLISH_RESULTS',
|
|
description: 'Publish CSV/dashboard for PR/release runs. Nightly always publishes. Off by default for dry-runs.',
|
|
defaultValue: false
|
|
)
|
|
}
|
|
|
|
options {
|
|
timestamps()
|
|
/* Prevent Jenkins jobs from running forever */
|
|
timeout(time: 120, unit: 'MINUTES')
|
|
disableConcurrentBuilds()
|
|
disableRestartFromStage()
|
|
/* manage how many builds we keep */
|
|
buildDiscarder(logRotator(
|
|
numToKeepStr: '10',
|
|
daysToKeepStr: '30',
|
|
artifactNumToKeepStr: '1',
|
|
))
|
|
}
|
|
|
|
environment {
|
|
// ghcmgr platform max length is 20 characters
|
|
PLATFORM = 'tests/win-benchmark'
|
|
CHANGE_ID = "${params.CHANGE_ID}"
|
|
RELEASE_VERSION = "${params.RELEASE_VERSION}"
|
|
|
|
SQUISH_DIR = 'C:\\squish-runner-9.2.2-qt-6.11'
|
|
PYTHONPATH = "${SQUISH_DIR}\\lib;${SQUISH_DIR}\\bin;${SQUISH_DIR}\\lib\\python;${PYTHONPATH}"
|
|
|
|
/* To stop e2e tests using port 8545 */
|
|
STATUS_RUNTIME_HTTP_API = 'False'
|
|
STATUS_RUNTIME_WS_API = 'False'
|
|
|
|
/* Avoid race conditions with other builds using virtualenv. */
|
|
VIRTUAL_ENV = "${WORKSPACE_TMP}\\venv"
|
|
PATH = "${VIRTUAL_ENV}\\bin;C:\\Qt\\${QT_VERSION}\\msvc2022_64\\bin;${PATH}"
|
|
|
|
/* To store user configuratiin files in temp dir */
|
|
XDG_CONFIG_HOME = "${WORKSPACE_TMP}/config"
|
|
BENCHMARK_RESULTS_DIR = "${WORKSPACE}\\test\\e2e\\benchmark-results"
|
|
|
|
TESTRAIL_URL = 'https://ethstatus.testrail.net'
|
|
TESTRAIL_PROJECT_ID = 18
|
|
|
|
/* Runtime flag to make testing of the app easier. Switched off: unpredictable app behavior under new tests */
|
|
STATUS_RUNTIME_TEST_MODE = 1
|
|
|
|
/*To enable Home tab */
|
|
FLAG_HOMEPAGE_ENABLED = 1
|
|
|
|
/* Hack fix for params not being set in job on first run */
|
|
BUILD_SOURCE = "${params.BUILD_SOURCE}"
|
|
TEST_NAME = "${params.TEST_NAME}"
|
|
TEST_SCOPE_FLAG = "${params.TEST_SCOPE_FLAG}"
|
|
TESTRAIL_RUN_NAME = "${params.TESTRAIL_RUN_NAME}"
|
|
LOG_LEVEL = "${params.LOG_LEVEL}"
|
|
|
|
/* Forces QT to use OpenGL for rendering instead of default Direct3D 11 */
|
|
QSG_RHI_BACKEND = 'opengl'
|
|
}
|
|
|
|
|
|
stages {
|
|
stage('Validate Parameters') {
|
|
steps {
|
|
script {
|
|
def hasPr = params.CHANGE_ID?.trim() as boolean
|
|
def hasRelease = params.RELEASE_VERSION?.trim() as boolean
|
|
def isManualJob = env.JOB_NAME.toLowerCase().contains('manual-benchmark')
|
|
|
|
if (hasPr && hasRelease) {
|
|
error('Set CHANGE_ID or RELEASE_VERSION, not both')
|
|
}
|
|
if (hasPr && !(params.CHANGE_ID ==~ /^[0-9]+$/)) {
|
|
error('CHANGE_ID must be the PR number')
|
|
}
|
|
if (isManualJob && !hasPr && !hasRelease) {
|
|
error('Manual benchmarks job requires CHANGE_ID for a PR run, or RELEASE_VERSION for a release run')
|
|
}
|
|
if (hasPr || hasRelease) {
|
|
def buildSource = params.BUILD_SOURCE?.trim()
|
|
if (!buildSource || buildSource == NIGHTLY_BUILD_SOURCE) {
|
|
error('For PR/release runs, set BUILD_SOURCE to the package URL or Jenkins project for that build')
|
|
}
|
|
}
|
|
|
|
if (hasPr) {
|
|
env.CHANNEL = 'pr'
|
|
} else if (hasRelease) {
|
|
env.CHANNEL = 'release'
|
|
} else {
|
|
env.CHANNEL = 'nightly'
|
|
}
|
|
echo "Benchmark channel: ${env.CHANNEL}"
|
|
}
|
|
}
|
|
}
|
|
|
|
stage('Cleanup Workspace') {
|
|
steps {
|
|
sh './scripts/clean-git.sh'
|
|
}
|
|
}
|
|
|
|
stage('Deps') {
|
|
steps { script { dir('test/e2e') {
|
|
bat """
|
|
python310 -m venv ${VIRTUAL_ENV}
|
|
${VIRTUAL_ENV}\\Scripts\\python.exe -m pip install --upgrade pip
|
|
${VIRTUAL_ENV}\\Scripts\\python.exe -m pip install -r requirements.txt
|
|
"""
|
|
} } }
|
|
}
|
|
|
|
stage('Download') {
|
|
when { expression { params.BUILD_SOURCE.startsWith('http') } }
|
|
steps { timeout(5) { script { dir('test/e2e') {
|
|
sh 'mkdir -p ./pkg/'
|
|
setBuildDescFromFile(params.BUILD_SOURCE)
|
|
fileOperations([
|
|
fileDownloadOperation(
|
|
url: params.BUILD_SOURCE,
|
|
targetFileName: 'StatusIm-Desktop.7z',
|
|
targetLocation: './pkg/',
|
|
userName: '',
|
|
password: '',
|
|
)
|
|
])
|
|
} } } }
|
|
}
|
|
|
|
stage('Copy') {
|
|
when { expression { ! params.BUILD_SOURCE.startsWith('http') } }
|
|
steps { timeout(5) { script { dir('test/e2e') {
|
|
copyArtifacts(
|
|
projectName: params.BUILD_SOURCE,
|
|
filter: 'pkg/*-x86_64.7z',
|
|
selector: lastWithArtifacts(),
|
|
target: './'
|
|
)
|
|
setBuildDescFromFile(utils.findFile('pkg/*7z'))
|
|
} } } }
|
|
}
|
|
|
|
stage('Unpack') {
|
|
steps { timeout(5) { script { dir('test/e2e') {
|
|
sh 'mkdir aut'
|
|
sh "7z x '${utils.findFile('pkg/*.7z')}' -o'./aut'"
|
|
env.AUT_PATH = utils.findFile('aut/Status/bin/Status.exe').replace('\\','/')
|
|
} } } }
|
|
}
|
|
|
|
stage('Test') {
|
|
steps {
|
|
timeout(time: 120) {
|
|
dir('test/e2e') {
|
|
/* Lock the agent so we run only one e2e build at a time */
|
|
lock(resource: "e2e-windows-${env.NODE_NAME}", quantity: 1) {
|
|
script {
|
|
def flags = []
|
|
if (params.TEST_NAME) { flags.add("-k=${params.TEST_NAME}") }
|
|
if (params.TEST_SCOPE_FLAG) { flags.add(params.TEST_SCOPE_FLAG) }
|
|
if (params.LOG_LEVEL) { flags.addAll(["--log-level=${params.LOG_LEVEL}", "--log-cli-level=${params.LOG_LEVEL}"]) }
|
|
def flagStr = flags.join(' ')
|
|
|
|
withCredentials([
|
|
usernamePassword(credentialsId: 'test-rail-api-devops', usernameVariable: 'TESTRAIL_USR', passwordVariable: 'TESTRAIL_PSW'),
|
|
string(credentialsId: 'wallet-test-user-seed', variable: 'WALLET_TEST_USER_SEED')
|
|
]) {
|
|
sh"""
|
|
pushd configs
|
|
ln -sf _local.ci.py _local.py || cp _local.ci.py _local.py
|
|
popd
|
|
|
|
"""
|
|
bat"""
|
|
${VIRTUAL_ENV}\\Scripts\\python.exe -m pytest -m benchmark -v --reruns=1 --timeout=300 ${flagStr} --disable-warnings --alluredir=./allure-results -o timeout_func_only=true
|
|
"""
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
post {
|
|
always {
|
|
script {
|
|
dir('test/e2e') {
|
|
archiveArtifacts(
|
|
artifacts: 'local_run_results/*.log,benchmark-results/*.json',
|
|
allowEmptyArchive: true,
|
|
)
|
|
|
|
if (fileExists('allure-results')) {
|
|
sh 'cp ext/allure_files/categories.json allure-results'
|
|
sh 'cp ext/allure_files/environment.properties allure-results'
|
|
|
|
allure([
|
|
results: [[path: 'allure-results']],
|
|
reportBuildPolicy: 'ALWAYS',
|
|
properties: [],
|
|
jdk: '',
|
|
])
|
|
} else {
|
|
echo 'No allure-results directory; skipping Allure report'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
success { script {
|
|
def publishResults = params.PUBLISH_RESULTS == true || "${params.PUBLISH_RESULTS}" == 'true'
|
|
def shouldPublish = (env.CHANNEL == 'nightly') || publishResults
|
|
if (!shouldPublish) {
|
|
echo 'PUBLISH_RESULTS=false; benchmark artifacts will not be committed'
|
|
} else {
|
|
/* Serialize publish across nightly + manual jobs (disableConcurrentBuilds is per-job). */
|
|
lock(resource: 'status-app-benchmarks-publish') {
|
|
withCredentials([sshUserPrivateKey(
|
|
credentialsId: 'status-app-benchmarks-deploy-key',
|
|
keyFileVariable: 'SSH_KEY_FILE'
|
|
)]) {
|
|
sh '''
|
|
eval $(ssh-agent -s)
|
|
ssh-add $SSH_KEY_FILE
|
|
./scripts/push_benchmark.sh
|
|
'''
|
|
}
|
|
}
|
|
}
|
|
if (params.CHANGE_ID ==~ /^[0-9]+$/) {
|
|
env.CHANGE_ID = params.CHANGE_ID
|
|
env.PKG_URL = shouldPublish
|
|
? "https://status-im.github.io/status-app-benchmarks/desktop/pr/${params.CHANGE_ID}/"
|
|
: "${env.BUILD_URL}consoleText"
|
|
echo "Notifying PR ${env.CHANGE_ID}: PLATFORM=${env.PLATFORM} PKG_URL=${env.PKG_URL}"
|
|
github.notifyPR(true)
|
|
}
|
|
} }
|
|
failure { script {
|
|
if (params.CHANGE_ID ==~ /^[0-9]+$/) {
|
|
env.CHANGE_ID = params.CHANGE_ID
|
|
env.PKG_URL = "${env.BUILD_URL}consoleText"
|
|
echo "Notifying PR ${env.CHANGE_ID} of failure: PLATFORM=${env.PLATFORM} PKG_URL=${env.PKG_URL}"
|
|
github.notifyPR(false)
|
|
}
|
|
} }
|
|
cleanup {
|
|
script {
|
|
powershell '''
|
|
if (Test-Path "C:\\Users\\jenkins\\AppData\\Local\\Status") {
|
|
Remove-Item "C:\\Users\\jenkins\\AppData\\Local\\Status" -Recurse -Force -ErrorAction SilentlyContinue
|
|
}
|
|
# Clean-up registry entries
|
|
$registryPath = "HKCU:\\Software\\Status\\Status Desktop"
|
|
if (Test-Path $registryPath) {
|
|
Remove-Item $registryPath -Recurse -Force -ErrorAction SilentlyContinue
|
|
}
|
|
'''
|
|
}
|
|
cleanWs(disableDeferredWipeout: true)
|
|
powershell "Remove-Item -Path '${env.WORKSPACE_TMP}' -Recurse -Force"
|
|
}
|
|
}
|
|
}
|
|
|
|
def setBuildDescFromFile(fileNameOrPath) {
|
|
def tokens = utils.parseFilename(utils.baseName(fileNameOrPath))
|
|
if (tokens == null) { /* Fallback for regex fail. */
|
|
currentBuild.description = utils.baseName(fileNameOrPath)
|
|
return
|
|
}
|
|
if (tokens.commit) {
|
|
env.SOURCE_COMMIT = tokens.commit
|
|
}
|
|
if (tokens.build && tokens.build.startsWith('pr')) {
|
|
currentBuild.displayName = tokens.build.replace(/^pr/, 'PR-')
|
|
}
|
|
currentBuild.description = formatMap([
|
|
Node: NODE_NAME,
|
|
Build: tokens.build,
|
|
Commit: tokens.commit,
|
|
Version: (tokens.tstamp ?: tokens.version),
|
|
])
|
|
}
|
|
|
|
def formatMap(Map data=[:]) {
|
|
def text = ''
|
|
data.each { key, val -> text += "<b>${key}</b>: ${val}</a><br>\n" }
|
|
return text
|
|
}
|