mirror of
https://github.com/status-im/status-app.git
synced 2026-08-27 07:01:14 +00:00
* ci(e2e-android): provide the wallet test seed to the e2e job The wallet-send smoke (#21420) skips unless WALLET_TEST_USER_SEED is set, and the Android job never sets it. Bind the existing wallet-test-user-seed credential, as the desktop e2e jobs already do. Assisted-by: Claude (Anthropic)
212 lines
6.2 KiB
Groovy
212 lines
6.2 KiB
Groovy
#!/usr/bin/env groovy
|
|
library 'status-jenkins-lib@v1.9.46'
|
|
|
|
pipeline {
|
|
agent {
|
|
dockerfile {
|
|
label 'linuxcontainer'
|
|
filename 'tests.Dockerfile'
|
|
dir 'ci'
|
|
args '--user jenkins'
|
|
}
|
|
}
|
|
|
|
parameters {
|
|
string(
|
|
name: 'CHANGE_ID',
|
|
description: 'Passed from PR CI Job, optional',
|
|
defaultValue: ''
|
|
)
|
|
string(
|
|
name: 'GIT_REF',
|
|
description: 'Git branch to checkout.',
|
|
defaultValue: 'master'
|
|
)
|
|
string(
|
|
name: 'BUILD_SOURCE',
|
|
description: 'URL to APK OR path to Jenkins build.',
|
|
defaultValue: ''
|
|
)
|
|
string(
|
|
name: 'BROWSERSTACK_APP_ID',
|
|
description: 'Existing BrowserStack app identifier (bs://...). Leave empty to upload from BUILD_SOURCE.',
|
|
defaultValue: ''
|
|
)
|
|
choice(
|
|
name: 'TEST_DEVICE_ID',
|
|
description: 'BrowserStack device id to run on (leave empty to use the environment default).',
|
|
choices: ['', 'galaxy_tab_s10p_android_15', 'pixel_8_android_14', 'pixel_7_android_13', 'samsung_s23_android_13']
|
|
)
|
|
string(
|
|
name: 'PYTEST_ARGS',
|
|
description: 'Pytest flags. Default runs gate tests for PRs. Use "-n=2 -m smoke tests" for nightly/full runs.',
|
|
defaultValue: '-n=2 -m gate tests'
|
|
)
|
|
}
|
|
|
|
options {
|
|
timestamps()
|
|
timeout(time: 120, unit: 'MINUTES')
|
|
buildDiscarder(logRotator(
|
|
daysToKeepStr: '30',
|
|
numToKeepStr: '30',
|
|
artifactNumToKeepStr: '30',
|
|
))
|
|
disableRestartFromStage()
|
|
}
|
|
|
|
environment {
|
|
PLATFORM = 'tests/e2e-android'
|
|
VIRTUAL_ENV = "${env.WORKSPACE_TMP}/venv-appium"
|
|
PYTHONUNBUFFERED = "1"
|
|
CHANGE_ID = "${params.CHANGE_ID}"
|
|
TEST_DEVICE_ID = "${params.TEST_DEVICE_ID}"
|
|
BROWSERSTACK_APP_ID = "${params.BROWSERSTACK_APP_ID?.trim() ?: ''}"
|
|
BROWSERSTACK_PROJECT_NAME = "Mobile E2E ${getBuildTypeFromUpstream()}"
|
|
}
|
|
|
|
stages {
|
|
stage('Prep') {
|
|
steps {
|
|
script {
|
|
setNewBuildName()
|
|
updateGitHubStatus()
|
|
}
|
|
}
|
|
}
|
|
|
|
stage('Setup Python environment') {
|
|
steps {
|
|
dir('test/e2e_appium') {
|
|
sh """#!/bin/bash
|
|
set -euo pipefail
|
|
python3 -m venv ${VIRTUAL_ENV}
|
|
source ${VIRTUAL_ENV}/bin/activate
|
|
pip install --upgrade pip
|
|
pip install -r requirements.txt
|
|
"""
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Copies APK from Jenkins build job (skipped when BUILD_SOURCE is a URL) */
|
|
stage('Fetch APK from Build') {
|
|
when {
|
|
allOf {
|
|
expression { !params.BROWSERSTACK_APP_ID?.trim() }
|
|
expression { !params.BUILD_SOURCE?.startsWith('http') }
|
|
}
|
|
}
|
|
steps { timeout(5) { script { dir('test/e2e_appium') {
|
|
copyArtifacts(
|
|
projectName: params.BUILD_SOURCE,
|
|
filter: 'pkg/*.apk',
|
|
selector: lastWithArtifacts(),
|
|
target: './pkg/',
|
|
flatten: true
|
|
)
|
|
} } } }
|
|
}
|
|
|
|
/* Uploads local APK or passes URL for BrowserStack to download */
|
|
stage('Provide APK to BrowserStack') {
|
|
when {
|
|
expression { !params.BROWSERSTACK_APP_ID?.trim() }
|
|
}
|
|
steps {
|
|
script {
|
|
def autSource = params.BUILD_SOURCE?.startsWith('http') ?
|
|
params.BUILD_SOURCE : utils.findFile('test/e2e_appium/pkg/*.apk')
|
|
withCredentials([
|
|
usernamePassword(
|
|
credentialsId: 'browserstack-status-mobile-android',
|
|
usernameVariable: 'BROWSERSTACK_USERNAME',
|
|
passwordVariable: 'BROWSERSTACK_ACCESS_KEY'
|
|
)
|
|
]) {
|
|
def response = sh(
|
|
script: "./scripts/upload_browserstack_apk.sh '${autSource}'",
|
|
returnStdout: true
|
|
).trim()
|
|
def result = readJSON text: response
|
|
if (!result?.app_url) {
|
|
error("BrowserStack upload failed: ${response}")
|
|
}
|
|
env.UPLOADED_BROWSERSTACK_APP_ID = result.app_url
|
|
env.BROWSERSTACK_BUILD_NAME = result.custom_id
|
|
env.BROWSERSTACK_BUILD_IDENTIFIER = env.BUILD_NUMBER
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
stage('Run pytest suite') {
|
|
steps{
|
|
lock(resource: 'e2e-android') {
|
|
script {
|
|
env.E2E_RUN_ID = env.BUILD_TAG
|
|
def appId = env.UPLOADED_BROWSERSTACK_APP_ID ?: params.BROWSERSTACK_APP_ID
|
|
dir('test/e2e_appium') {
|
|
withCredentials([
|
|
usernamePassword(
|
|
credentialsId: 'browserstack-status-mobile-android',
|
|
usernameVariable: 'BROWSERSTACK_USERNAME',
|
|
passwordVariable: 'BROWSERSTACK_ACCESS_KEY'
|
|
),
|
|
string(
|
|
credentialsId: 'wallet-test-user-seed',
|
|
variable: 'WALLET_TEST_USER_SEED'
|
|
)
|
|
]) {
|
|
sh "BROWSERSTACK_APP_ID=${appId} ${VIRTUAL_ENV}/bin/python -m pytest --env browserstack ${params.PYTEST_ARGS?.trim() ?: ''}"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
post {
|
|
always { script {
|
|
junit allowEmptyResults: true, testResults: "test/e2e_appium/reports/${env.BUILD_TAG}/pytest_results_*.xml"
|
|
archiveArtifacts artifacts: "test/e2e_appium/reports/${env.BUILD_TAG}/**/*", allowEmptyArchive: true
|
|
env.PKG_URL = "${env.BUILD_URL}testReport/"
|
|
updateGitHubStatus()
|
|
} }
|
|
success { script { github.notifyPR(true) } }
|
|
failure { script { github.notifyPR(false) } }
|
|
cleanup {
|
|
cleanWs(disableDeferredWipeout: true)
|
|
dir(env.WORKSPACE_TMP) { deleteDir() }
|
|
}
|
|
}
|
|
}
|
|
|
|
def setNewBuildName() {
|
|
if (utils.isPRBuild()) {
|
|
currentBuild.displayName = "PR${env.CHANGE_ID}"
|
|
}
|
|
}
|
|
def updateGitHubStatus() {
|
|
if (utils.isPRBuild()) {
|
|
github.statusUpdate(
|
|
context: 'jenkins/prs/tests/e2e-android',
|
|
commit: env.GIT_COMMIT,
|
|
repo_url: 'https://github.com/status-im/status-app'
|
|
)
|
|
}
|
|
}
|
|
|
|
def getBuildTypeFromUpstream() {
|
|
def upstream = currentBuild.upstreamBuilds?.getAt(0)
|
|
if (upstream) {
|
|
def upstreamJob = upstream.getFullProjectName()
|
|
if (upstreamJob.contains('/prs/')) return 'PR'
|
|
if (upstreamJob.contains('/nightly/')) return 'Nightly'
|
|
if (upstreamJob.contains('/release/')) return 'Release'
|
|
}
|
|
return 'Manual'
|
|
}
|