ci: stabilize Jenkins jobs and mobile pipeline
This commit is contained in:
@@ -7,6 +7,11 @@
|
|||||||
compose_dir: "{{ hw8_root }}/compose"
|
compose_dir: "{{ hw8_root }}/compose"
|
||||||
compose_file: "{{ compose_dir }}/docker-compose.yml"
|
compose_file: "{{ compose_dir }}/docker-compose.yml"
|
||||||
compose_env_file: "{{ compose_dir }}/.env"
|
compose_env_file: "{{ compose_dir }}/.env"
|
||||||
|
jobs_profile_effective: "{{ jobs_profile | default('full') }}"
|
||||||
|
jjb_paths:
|
||||||
|
full: /workspace/hw8/config/jobs
|
||||||
|
devops: /workspace/hw8/config/jobs-devops
|
||||||
|
jjb_upload_path: "{{ jjb_paths.get(jobs_profile_effective, jjb_paths.full) }}"
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: Check Docker CLI availability
|
- name: Check Docker CLI availability
|
||||||
@@ -89,7 +94,7 @@
|
|||||||
|
|
||||||
- name: Upload Jenkins jobs via JJB container
|
- name: Upload Jenkins jobs via JJB container
|
||||||
ansible.builtin.command:
|
ansible.builtin.command:
|
||||||
cmd: timeout 900 docker compose -f {{ compose_file }} --env-file {{ compose_env_file }} run --rm jobs_uploader
|
cmd: timeout 900 docker compose -f {{ compose_file }} --env-file {{ compose_env_file }} run --rm -e JJB_PATH={{ jjb_upload_path }} jobs_uploader
|
||||||
args:
|
args:
|
||||||
chdir: "{{ compose_dir }}"
|
chdir: "{{ compose_dir }}"
|
||||||
|
|
||||||
@@ -98,3 +103,5 @@
|
|||||||
msg:
|
msg:
|
||||||
- "Jenkins UI: http://localhost:8088 (via nginx) or http://localhost:8081"
|
- "Jenkins UI: http://localhost:8088 (via nginx) or http://localhost:8081"
|
||||||
- "Registry: http://localhost:5005/v2/"
|
- "Registry: http://localhost:5005/v2/"
|
||||||
|
- "JJB profile: {{ jobs_profile_effective }}"
|
||||||
|
- "JJB path: {{ jjb_upload_path }}"
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ services:
|
|||||||
- jenkins_home:/var/jenkins_home
|
- jenkins_home:/var/jenkins_home
|
||||||
- ./jenkins/casc:/var/jenkins_home/casc_configs:ro
|
- ./jenkins/casc:/var/jenkins_home/casc_configs:ro
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- ../..:/workspace/otus-autotests:ro
|
- ..:/workspace/hw8:ro
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:8080/login >/dev/null"]
|
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:8080/login >/dev/null"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
@@ -67,9 +67,9 @@ services:
|
|||||||
JENKINS_HOSTNAME: http://jenkins:8080
|
JENKINS_HOSTNAME: http://jenkins:8080
|
||||||
JENKINS_USERNAME: ${JENKINS_ADMIN_ID}
|
JENKINS_USERNAME: ${JENKINS_ADMIN_ID}
|
||||||
JENKINS_PASSWORD: ${JENKINS_ADMIN_PASSWORD}
|
JENKINS_PASSWORD: ${JENKINS_ADMIN_PASSWORD}
|
||||||
JJB_PATH: /workspace/otus-autotests/hw8/config/jobs
|
JJB_PATH: /workspace/hw8/config/jobs
|
||||||
volumes:
|
volumes:
|
||||||
- ../..:/workspace/otus-autotests:ro
|
- ..:/workspace/hw8:ro
|
||||||
networks:
|
networks:
|
||||||
- jenkins_net
|
- jenkins_net
|
||||||
|
|
||||||
@@ -87,9 +87,10 @@ services:
|
|||||||
JENKINS_AGENT_WORKDIR: /home/jenkins/agent
|
JENKINS_AGENT_WORKDIR: /home/jenkins/agent
|
||||||
JENKINS_WEB_SOCKET: "true"
|
JENKINS_WEB_SOCKET: "true"
|
||||||
JENKINS_LABELS: maven docker
|
JENKINS_LABELS: maven docker
|
||||||
|
HW8_ROOT: /workspace/hw8
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- ../..:/workspace/otus-autotests:ro
|
- ..:/workspace/hw8:ro
|
||||||
networks:
|
networks:
|
||||||
- jenkins_net
|
- jenkins_net
|
||||||
|
|
||||||
@@ -107,9 +108,10 @@ services:
|
|||||||
JENKINS_AGENT_WORKDIR: /home/jenkins/agent
|
JENKINS_AGENT_WORKDIR: /home/jenkins/agent
|
||||||
JENKINS_WEB_SOCKET: "true"
|
JENKINS_WEB_SOCKET: "true"
|
||||||
JENKINS_LABELS: jjb docker
|
JENKINS_LABELS: jjb docker
|
||||||
|
HW8_ROOT: /workspace/hw8
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- ../..:/workspace/otus-autotests:ro
|
- ..:/workspace/hw8:ro
|
||||||
networks:
|
networks:
|
||||||
- jenkins_net
|
- jenkins_net
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ RUN apt-get update \
|
|||||||
ca-certificates \
|
ca-certificates \
|
||||||
curl \
|
curl \
|
||||||
docker.io \
|
docker.io \
|
||||||
|
git \
|
||||||
unzip \
|
unzip \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,55 @@
|
|||||||
FROM maven:3.9.11-eclipse-temurin-21
|
FROM maven:3.9.11-eclipse-temurin-21
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN set -eux; \
|
||||||
&& apt-get install -y --no-install-recommends \
|
apt-get update; \
|
||||||
chromium \
|
apt-get install -y --no-install-recommends \
|
||||||
chromium-driver \
|
ca-certificates \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
curl \
|
||||||
|
unzip \
|
||||||
|
fontconfig \
|
||||||
|
fonts-liberation \
|
||||||
|
libasound2t64 \
|
||||||
|
libatk-bridge2.0-0 \
|
||||||
|
libatk1.0-0 \
|
||||||
|
libc6 \
|
||||||
|
libcairo2 \
|
||||||
|
libcups2 \
|
||||||
|
libdbus-1-3 \
|
||||||
|
libexpat1 \
|
||||||
|
libfontconfig1 \
|
||||||
|
libgbm1 \
|
||||||
|
libgcc1 \
|
||||||
|
libglib2.0-0 \
|
||||||
|
libgtk-3-0 \
|
||||||
|
libnspr4 \
|
||||||
|
libnss3 \
|
||||||
|
libpango-1.0-0 \
|
||||||
|
libpangocairo-1.0-0 \
|
||||||
|
libstdc++6 \
|
||||||
|
libx11-6 \
|
||||||
|
libx11-xcb1 \
|
||||||
|
libxcb1 \
|
||||||
|
libxcomposite1 \
|
||||||
|
libxcursor1 \
|
||||||
|
libxdamage1 \
|
||||||
|
libxext6 \
|
||||||
|
libxfixes3 \
|
||||||
|
libxi6 \
|
||||||
|
libxrandr2 \
|
||||||
|
libxrender1 \
|
||||||
|
libxss1 \
|
||||||
|
libxtst6 \
|
||||||
|
xdg-utils; \
|
||||||
|
CHROME_VERSION="$(curl -fsSL https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_STABLE)"; \
|
||||||
|
curl -fsSL "https://storage.googleapis.com/chrome-for-testing-public/${CHROME_VERSION}/linux64/chrome-linux64.zip" -o /tmp/chrome.zip; \
|
||||||
|
curl -fsSL "https://storage.googleapis.com/chrome-for-testing-public/${CHROME_VERSION}/linux64/chromedriver-linux64.zip" -o /tmp/chromedriver.zip; \
|
||||||
|
unzip -q /tmp/chrome.zip -d /opt; \
|
||||||
|
unzip -q /tmp/chromedriver.zip -d /opt; \
|
||||||
|
ln -sf /opt/chrome-linux64/chrome /usr/bin/google-chrome; \
|
||||||
|
ln -sf /opt/chrome-linux64/chrome /usr/bin/chromium; \
|
||||||
|
ln -sf /opt/chromedriver-linux64/chromedriver /usr/bin/chromedriver; \
|
||||||
|
chmod +x /opt/chrome-linux64/chrome /opt/chromedriver-linux64/chromedriver; \
|
||||||
|
rm -f /tmp/chrome.zip /tmp/chromedriver.zip; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ jenkins:
|
|||||||
- key: JENKINS_URL_INTERNAL
|
- key: JENKINS_URL_INTERNAL
|
||||||
value: "http://jenkins:8080"
|
value: "http://jenkins:8080"
|
||||||
- key: OTUS_WORKSPACE_ROOT
|
- key: OTUS_WORKSPACE_ROOT
|
||||||
value: "/workspace/otus-autotests"
|
value: "/workspace/hw8"
|
||||||
- key: MOBILE_DB_PASSWORD
|
- key: MOBILE_DB_PASSWORD
|
||||||
value: "${MOBILE_DB_PASSWORD}"
|
value: "${MOBILE_DB_PASSWORD}"
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ services:
|
|||||||
- EMULATOR_PARAMS=-no-window -no-audio -gpu swiftshader_indirect -no-snapshot -no-boot-anim
|
- EMULATOR_PARAMS=-no-window -no-audio -gpu swiftshader_indirect -no-snapshot -no-boot-anim
|
||||||
shm_size: 2gb
|
shm_size: 2gb
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "[ \"$(cat /home/androidusr/device_status 2>/dev/null)\" = \"READY\" ]"]
|
test: ["CMD-SHELL", "[ \"$(cat /home/androidusr/device_status 2>/dev/null)\" = \"READY\" ] && wget -qO- http://127.0.0.1:4723/status >/dev/null 2>&1"]
|
||||||
interval: 15s
|
interval: 15s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 40
|
retries: 40
|
||||||
@@ -45,7 +45,7 @@ services:
|
|||||||
- EMULATOR_PARAMS=-no-window -no-audio -gpu swiftshader_indirect -no-snapshot -no-boot-anim
|
- EMULATOR_PARAMS=-no-window -no-audio -gpu swiftshader_indirect -no-snapshot -no-boot-anim
|
||||||
shm_size: 2gb
|
shm_size: 2gb
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "[ \"$(cat /home/androidusr/device_status 2>/dev/null)\" = \"READY\" ]"]
|
test: ["CMD-SHELL", "[ \"$(cat /home/androidusr/device_status 2>/dev/null)\" = \"READY\" ] && wget -qO- http://127.0.0.1:4723/status >/dev/null 2>&1"]
|
||||||
interval: 15s
|
interval: 15s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 40
|
retries: 40
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- defaults:
|
||||||
|
name: global
|
||||||
|
project_folder: /workspace/hw8
|
||||||
|
test_image_tag: "1.0.0"
|
||||||
|
build_keep: 40
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
- job:
|
||||||
|
name: infra-health-check
|
||||||
|
description: "Проверка инфраструктуры Jenkins/Registry/Agent образов."
|
||||||
|
project-type: pipeline
|
||||||
|
concurrent: false
|
||||||
|
sandbox: true
|
||||||
|
properties:
|
||||||
|
- build-discarder:
|
||||||
|
num-to-keep: 30
|
||||||
|
dsl: !include-raw-verbatim: ../../jobs/scripts/infra-health-check.groovy
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
- job:
|
||||||
|
name: jobs-uploader
|
||||||
|
description: "Обновляет Jenkins jobs из JJB YAML (config/jobs)."
|
||||||
|
project-type: pipeline
|
||||||
|
concurrent: false
|
||||||
|
sandbox: true
|
||||||
|
properties:
|
||||||
|
- build-discarder:
|
||||||
|
num-to-keep: 30
|
||||||
|
parameters:
|
||||||
|
- string:
|
||||||
|
name: JJB_PATH
|
||||||
|
default: /workspace/hw8/config/jobs
|
||||||
|
description: "Путь до JJB-конфигов"
|
||||||
|
dsl: !include-raw-verbatim: ../../jobs/scripts/jobs-uploader.groovy
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
- view:
|
||||||
|
name: DevOps
|
||||||
|
view-type: list
|
||||||
|
description: "Инфраструктурные job"
|
||||||
|
filter-executors: true
|
||||||
|
filter-queue: true
|
||||||
|
job-name:
|
||||||
|
- jobs-uploader
|
||||||
|
- infra-health-check
|
||||||
|
columns:
|
||||||
|
- status
|
||||||
|
- weather
|
||||||
|
- job
|
||||||
|
- last-success
|
||||||
|
- last-failure
|
||||||
|
- last-duration
|
||||||
|
- build-button
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- defaults:
|
- defaults:
|
||||||
name: global
|
name: global
|
||||||
project_folder: /workspace/otus-autotests
|
project_folder: /workspace/hw8
|
||||||
test_image_tag: "1.0.0"
|
test_image_tag: "1.0.0"
|
||||||
build_keep: 40
|
build_keep: 40
|
||||||
|
|||||||
@@ -5,6 +5,18 @@ pipeline {
|
|||||||
ansiColor('xterm')
|
ansiColor('xterm')
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
|
stage('Prepare Metadata') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
wrap([$class: 'BuildUser']) {
|
||||||
|
env.RUN_TRIGGER_USER = env.BUILD_USER_ID ?: env.BUILD_USER ?: 'system'
|
||||||
|
env.RUN_TRIGGER_NAME = env.BUILD_USER ?: env.BUILD_USER_ID ?: 'system'
|
||||||
|
}
|
||||||
|
currentBuild.displayName = "#${env.BUILD_NUMBER} infra"
|
||||||
|
currentBuild.description = "by=${env.RUN_TRIGGER_NAME}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('Check Docker & Registry') {
|
stage('Check Docker & Registry') {
|
||||||
steps {
|
steps {
|
||||||
sh '''
|
sh '''
|
||||||
@@ -17,13 +29,12 @@ pipeline {
|
|||||||
'''
|
'''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Check Sources') {
|
stage('Check Job Configs') {
|
||||||
steps {
|
steps {
|
||||||
sh '''
|
sh '''
|
||||||
set -eux
|
set -eux
|
||||||
test -f /workspace/otus-autotests/homework_4/pom.xml
|
HW8_ROOT_PATH="${HW8_ROOT:-/workspace/hw8}"
|
||||||
test -f /workspace/otus-autotests/hw7/pom.xml
|
test -f "${HW8_ROOT_PATH}/config/jobs/global.yaml"
|
||||||
test -f /workspace/otus-autotests/hw8/config/jobs/global.yaml
|
|
||||||
'''
|
'''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,18 @@ pipeline {
|
|||||||
ansiColor('xterm')
|
ansiColor('xterm')
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
|
stage('Prepare Metadata') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
wrap([$class: 'BuildUser']) {
|
||||||
|
env.RUN_TRIGGER_USER = env.BUILD_USER_ID ?: env.BUILD_USER ?: 'system'
|
||||||
|
env.RUN_TRIGGER_NAME = env.BUILD_USER ?: env.BUILD_USER_ID ?: 'system'
|
||||||
|
}
|
||||||
|
currentBuild.displayName = "#${env.BUILD_NUMBER} jjb"
|
||||||
|
currentBuild.description = "by=${env.RUN_TRIGGER_NAME}; jjbPath=${params.JJB_PATH}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('Validate Input') {
|
stage('Validate Input') {
|
||||||
steps {
|
steps {
|
||||||
sh '''
|
sh '''
|
||||||
|
|||||||
@@ -5,19 +5,47 @@ pipeline {
|
|||||||
ansiColor('xterm')
|
ansiColor('xterm')
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
|
stage('Prepare Metadata') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
wrap([$class: 'BuildUser']) {
|
||||||
|
env.RUN_TRIGGER_USER = env.BUILD_USER_ID ?: env.BUILD_USER ?: 'system'
|
||||||
|
env.RUN_TRIGGER_NAME = env.BUILD_USER ?: env.BUILD_USER_ID ?: 'system'
|
||||||
|
}
|
||||||
|
currentBuild.displayName = "#${env.BUILD_NUMBER} api"
|
||||||
|
currentBuild.description =
|
||||||
|
"by=${env.RUN_TRIGGER_NAME}; repo=${params.QA_REPO_URL}; ref=${params.QA_REPO_REF}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('Run API Tests In Docker') {
|
stage('Run API Tests In Docker') {
|
||||||
steps {
|
steps {
|
||||||
sh '''
|
sh '''
|
||||||
set -eux
|
set -eux
|
||||||
|
rm -rf ./sources
|
||||||
|
git clone "${QA_REPO_URL}" ./sources
|
||||||
|
git -C ./sources checkout "${QA_REPO_REF}"
|
||||||
|
GIT_SHA="$(git -C ./sources rev-parse --short HEAD)"
|
||||||
|
|
||||||
rm -rf ./artifacts
|
rm -rf ./artifacts
|
||||||
mkdir -p ./artifacts
|
mkdir -p ./artifacts
|
||||||
|
{
|
||||||
|
echo "job=${JOB_NAME}"
|
||||||
|
echo "build=${BUILD_NUMBER}"
|
||||||
|
echo "trigger_user=${RUN_TRIGGER_USER}"
|
||||||
|
echo "trigger_name=${RUN_TRIGGER_NAME}"
|
||||||
|
echo "qa_repo_url=${QA_REPO_URL}"
|
||||||
|
echo "qa_repo_ref=${QA_REPO_REF}"
|
||||||
|
echo "qa_repo_sha=${GIT_SHA}"
|
||||||
|
echo "timestamp_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
} > ./artifacts/run-info.txt
|
||||||
|
|
||||||
CID="$(docker create localhost:5005/otus/test-api:1.0.0 bash -lc "set -e; cd /workspace; mvn -f citrus-tests/pom.xml test")"
|
CID="$(docker create localhost:5005/otus/test-api:1.0.0 bash -lc "set -e; cd /workspace; mvn -f citrus-tests/pom.xml test")"
|
||||||
cleanup_container() {
|
cleanup_container() {
|
||||||
docker rm -f "${CID}" >/dev/null 2>&1 || true
|
docker rm -f "${CID}" >/dev/null 2>&1 || true
|
||||||
}
|
}
|
||||||
trap cleanup_container EXIT INT TERM
|
trap cleanup_container EXIT INT TERM
|
||||||
tar -C /workspace/otus-autotests/homework_4 -cf - . | docker cp - "${CID}:/workspace"
|
tar -C ./sources -cf - . | docker cp - "${CID}:/workspace"
|
||||||
set +e
|
set +e
|
||||||
docker start -a "${CID}"
|
docker start -a "${CID}"
|
||||||
TEST_RC=$?
|
TEST_RC=$?
|
||||||
@@ -32,7 +60,7 @@ pipeline {
|
|||||||
post {
|
post {
|
||||||
always {
|
always {
|
||||||
junit allowEmptyResults: true, testResults: 'artifacts/citrus-target/surefire-reports/*.xml'
|
junit allowEmptyResults: true, testResults: 'artifacts/citrus-target/surefire-reports/*.xml'
|
||||||
archiveArtifacts allowEmptyArchive: true, artifacts: 'artifacts/citrus-target/**'
|
archiveArtifacts allowEmptyArchive: true, artifacts: 'artifacts/run-info.txt,artifacts/citrus-target/**'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,61 @@ pipeline {
|
|||||||
ansiColor('xterm')
|
ansiColor('xterm')
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
|
stage('Prepare Metadata') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
wrap([$class: 'BuildUser']) {
|
||||||
|
env.RUN_TRIGGER_USER = env.BUILD_USER_ID ?: env.BUILD_USER ?: 'system'
|
||||||
|
env.RUN_TRIGGER_NAME = env.BUILD_USER ?: env.BUILD_USER_ID ?: 'system'
|
||||||
|
}
|
||||||
|
currentBuild.displayName = "#${env.BUILD_NUMBER} mobile"
|
||||||
|
currentBuild.description =
|
||||||
|
"by=${env.RUN_TRIGGER_NAME}; repo=${params.MOBILE_REPO_URL}; ref=${params.MOBILE_REPO_REF}; emulators=${params.MOBILE_MAX_EMULATORS}; junit=${params.JUNIT_PARALLELISM}; order=${params.TEST_CLASSES_ORDER}; rerun=${params.SUREFIRE_RERUN_FAILING}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('Prepare Workspace') {
|
stage('Prepare Workspace') {
|
||||||
steps {
|
steps {
|
||||||
sh '''
|
sh '''
|
||||||
set -eux
|
set -eux
|
||||||
rm -rf ./project
|
rm -rf ./project
|
||||||
mkdir -p ./project
|
git clone "${MOBILE_REPO_URL}" ./project
|
||||||
cp -a /workspace/otus-autotests/hw7/. ./project/
|
git -C ./project checkout "${MOBILE_REPO_REF}"
|
||||||
|
GIT_SHA="$(git -C ./project rev-parse --short HEAD)"
|
||||||
|
if ! grep -q "<artifactId>allure-junit5</artifactId>" ./project/pom.xml; then
|
||||||
|
awk -v ver="${ALLURE_ADAPTER_VERSION}" '
|
||||||
|
index($0, "</dependencies>") && !done {
|
||||||
|
print " <dependency>"
|
||||||
|
print " <groupId>io.qameta.allure</groupId>"
|
||||||
|
print " <artifactId>allure-junit5</artifactId>"
|
||||||
|
print " <version>" ver "</version>"
|
||||||
|
print " <scope>test</scope>"
|
||||||
|
print " </dependency>"
|
||||||
|
done=1
|
||||||
|
}
|
||||||
|
{ print }
|
||||||
|
' ./project/pom.xml > ./project/pom.xml.tmp
|
||||||
|
mv ./project/pom.xml.tmp ./project/pom.xml
|
||||||
|
fi
|
||||||
|
mkdir -p ./project/target/allure-results
|
||||||
|
{
|
||||||
|
echo "job=${JOB_NAME}"
|
||||||
|
echo "build=${BUILD_NUMBER}"
|
||||||
|
echo "trigger_user=${RUN_TRIGGER_USER}"
|
||||||
|
echo "trigger_name=${RUN_TRIGGER_NAME}"
|
||||||
|
echo "mobile_repo_url=${MOBILE_REPO_URL}"
|
||||||
|
echo "mobile_repo_ref=${MOBILE_REPO_REF}"
|
||||||
|
echo "mobile_repo_sha=${GIT_SHA}"
|
||||||
|
echo "app_url=${APP_URL}"
|
||||||
|
echo "mobile_max_emulators=${MOBILE_MAX_EMULATORS}"
|
||||||
|
echo "junit_parallelism=${JUNIT_PARALLELISM}"
|
||||||
|
echo "test_classes_order=${TEST_CLASSES_ORDER}"
|
||||||
|
echo "surefire_rerun_failing=${SUREFIRE_RERUN_FAILING}"
|
||||||
|
echo "db_url=${DB_URL}"
|
||||||
|
echo "db_user=${DB_USER}"
|
||||||
|
echo "reservation_owner=${RESERVATION_OWNER}"
|
||||||
|
echo "timestamp_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
} > ./project/run-info.txt
|
||||||
'''
|
'''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,7 +68,8 @@ pipeline {
|
|||||||
dir('project') {
|
dir('project') {
|
||||||
sh '''
|
sh '''
|
||||||
set -eux
|
set -eux
|
||||||
COMPOSE_FILE="/workspace/otus-autotests/hw8/config/compose/mobile-ci.compose.yml"
|
HW8_ROOT_PATH="${HW8_ROOT:-/workspace/hw8}"
|
||||||
|
COMPOSE_FILE="${HW8_ROOT_PATH}/config/compose/mobile-ci.compose.yml"
|
||||||
if docker compose version >/dev/null 2>&1; then
|
if docker compose version >/dev/null 2>&1; then
|
||||||
compose_cmd() { PROJECT_DIR="$PWD" docker compose -f "${COMPOSE_FILE}" "$@"; }
|
compose_cmd() { PROJECT_DIR="$PWD" docker compose -f "${COMPOSE_FILE}" "$@"; }
|
||||||
elif docker-compose version >/dev/null 2>&1; then
|
elif docker-compose version >/dev/null 2>&1; then
|
||||||
@@ -30,11 +79,32 @@ pipeline {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
export COMPOSE_PROJECT_NAME=mobileci
|
export COMPOSE_PROJECT_NAME=mobileci
|
||||||
compose_cmd down -v --remove-orphans || true
|
MAX_EMULATORS="${MOBILE_MAX_EMULATORS:-1}"
|
||||||
compose_cmd up -d wiremock android-emulator-1 android-emulator-2
|
if ! [ "${MAX_EMULATORS}" -eq "${MAX_EMULATORS}" ] 2>/dev/null; then
|
||||||
|
echo "Invalid MOBILE_MAX_EMULATORS='${MAX_EMULATORS}', expected integer"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "${MAX_EMULATORS}" -lt 1 ] || [ "${MAX_EMULATORS}" -gt 2 ]; then
|
||||||
|
echo "Invalid MOBILE_MAX_EMULATORS='${MAX_EMULATORS}', expected 1 or 2"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SERVICES="wiremock android-emulator-1"
|
||||||
|
if [ "${MAX_EMULATORS}" -ge 2 ]; then
|
||||||
|
SERVICES="${SERVICES} android-emulator-2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
compose_cmd down -v --remove-orphans || true
|
||||||
|
compose_cmd up -d ${SERVICES}
|
||||||
EMULATORS=""
|
EMULATORS=""
|
||||||
|
SELECTED=0
|
||||||
for service in android-emulator-1 android-emulator-2; do
|
for service in android-emulator-1 android-emulator-2; do
|
||||||
|
if [ "${service}" = "android-emulator-2" ] && [ "${MAX_EMULATORS}" -lt 2 ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "${SELECTED}" -ge "${MAX_EMULATORS}" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
cid="$(compose_cmd ps -q "$service")"
|
cid="$(compose_cmd ps -q "$service")"
|
||||||
if [ -z "${cid}" ]; then
|
if [ -z "${cid}" ]; then
|
||||||
echo "Container for ${service} not found, skipping"
|
echo "Container for ${service} not found, skipping"
|
||||||
@@ -55,6 +125,7 @@ pipeline {
|
|||||||
EMULATORS="${EMULATORS},"
|
EMULATORS="${EMULATORS},"
|
||||||
fi
|
fi
|
||||||
EMULATORS="${EMULATORS}${service}|http://${service}:4723|Android Emulator|${APP_URL}"
|
EMULATORS="${EMULATORS}${service}|http://${service}:4723|Android Emulator|${APP_URL}"
|
||||||
|
SELECTED=$((SELECTED + 1))
|
||||||
else
|
else
|
||||||
echo "Service ${service} is not healthy in time, excluding from test run"
|
echo "Service ${service} is not healthy in time, excluding from test run"
|
||||||
docker logs "${cid}" || true
|
docker logs "${cid}" || true
|
||||||
@@ -76,40 +147,258 @@ pipeline {
|
|||||||
dir('project') {
|
dir('project') {
|
||||||
sh '''
|
sh '''
|
||||||
set -eux
|
set -eux
|
||||||
rm -rf ./target
|
rm -rf ./target ./target-run
|
||||||
MOBILE_EMULATORS_VALUE="$(cat ./.mobile_emulators.txt)"
|
MOBILE_EMULATORS_VALUE="$(cat ./.mobile_emulators.txt)"
|
||||||
|
EMULATOR_ENTRIES_COUNT="$(printf '%s' "${MOBILE_EMULATORS_VALUE}" | awk -F, '{print NF}')"
|
||||||
|
DOCKER_NETWORK_ARG="--network mobileci_default"
|
||||||
|
if [ "${EMULATOR_ENTRIES_COUNT}" -eq 1 ]; then
|
||||||
|
SINGLE_SERVICE="$(printf '%s' "${MOBILE_EMULATORS_VALUE}" | cut -d'|' -f1)"
|
||||||
|
if [ "${SINGLE_SERVICE}" = "android-emulator-1" ] || [ "${SINGLE_SERVICE}" = "android-emulator-2" ]; then
|
||||||
|
SINGLE_EMULATOR_CID="$(docker ps -q --filter "name=mobileci-${SINGLE_SERVICE}" | head -n1 || true)"
|
||||||
|
if [ -n "${SINGLE_EMULATOR_CID}" ]; then
|
||||||
|
DOCKER_NETWORK_ARG="--network container:${SINGLE_EMULATOR_CID}"
|
||||||
|
MOBILE_EMULATORS_VALUE="$(printf '%s' "${MOBILE_EMULATORS_VALUE}" | awk -F'|' 'BEGIN { OFS="|" } { $2="http://127.0.0.1:4723"; print $1, $2, $3, $4 }')"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
DB_PASSWORD_EFFECTIVE="${DB_PASSWORD:-${MOBILE_DB_PASSWORD:-}}"
|
DB_PASSWORD_EFFECTIVE="${DB_PASSWORD:-${MOBILE_DB_PASSWORD:-}}"
|
||||||
if [ -z "${DB_PASSWORD_EFFECTIVE}" ]; then
|
if [ -z "${DB_PASSWORD_EFFECTIVE}" ]; then
|
||||||
echo "DB password is not set. Provide DB_PASSWORD job parameter or MOBILE_DB_PASSWORD env variable."
|
echo "DB password is not set. Provide DB_PASSWORD job parameter or MOBILE_DB_PASSWORD env variable."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
CID="$(docker create \
|
|
||||||
--network mobileci_default \
|
# Validate Appium endpoints from the same Docker network as test container.
|
||||||
-e DB_URL="${DB_URL:-}" \
|
if ! docker run --rm \
|
||||||
-e DB_USER="${DB_USER:-}" \
|
${DOCKER_NETWORK_ARG} \
|
||||||
-e DB_PASSWORD="${DB_PASSWORD_EFFECTIVE}" \
|
|
||||||
-e APP_URL="${APP_URL:-}" \
|
|
||||||
-e MOBILE_EMULATORS="${MOBILE_EMULATORS_VALUE}" \
|
-e MOBILE_EMULATORS="${MOBILE_EMULATORS_VALUE}" \
|
||||||
-e WISHLISTS_USERNAME="${WISHLISTS_USERNAME:-}" \
|
|
||||||
-e WISHLISTS_PASSWORD="${WISHLISTS_PASSWORD:-}" \
|
|
||||||
-e GIFTS_USERNAME="${GIFTS_USERNAME:-}" \
|
|
||||||
-e GIFTS_PASSWORD="${GIFTS_PASSWORD:-}" \
|
|
||||||
-e RESERVATION_USERNAME="${RESERVATION_USERNAME:-}" \
|
|
||||||
-e RESERVATION_PASSWORD="${RESERVATION_PASSWORD:-}" \
|
|
||||||
-e RESERVATION_OWNER="${RESERVATION_OWNER:-}" \
|
|
||||||
localhost:5005/otus/test-mobile:1.0.0 \
|
localhost:5005/otus/test-mobile:1.0.0 \
|
||||||
bash -lc "set -e; cd /workspace; timeout 1800s mvn -Dallure.results.directory=target/allure-results test")"
|
bash -lc '
|
||||||
cleanup_container() {
|
set -euo pipefail
|
||||||
|
IFS="," read -ra TARGETS <<< "${MOBILE_EMULATORS}"
|
||||||
|
for target in "${TARGETS[@]}"; do
|
||||||
|
endpoint="$(echo "${target}" | cut -d"|" -f2)"
|
||||||
|
if [ -z "${endpoint}" ]; then
|
||||||
|
echo "Invalid MOBILE_EMULATORS entry: ${target}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
ready="false"
|
||||||
|
for i in $(seq 1 60); do
|
||||||
|
if curl -fsS "${endpoint}/status" >/dev/null 2>&1; then
|
||||||
|
ready="true"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
if [ "${ready}" != "true" ]; then
|
||||||
|
echo "Appium endpoint is not reachable from test container: ${endpoint}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
'; then
|
||||||
|
echo "Appium preflight failed. Dumping emulator logs."
|
||||||
|
for service in android-emulator-1 android-emulator-2; do
|
||||||
|
cid="$(docker ps -q --filter "name=mobileci-${service}" | head -n1 || true)"
|
||||||
|
if [ -n "${cid}" ]; then
|
||||||
|
echo "--- logs for ${service} (${cid}) ---"
|
||||||
|
docker logs --tail 200 "${cid}" || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_single_class() {
|
||||||
|
class_name="$1"
|
||||||
|
attempt="$2"
|
||||||
|
class_key="$(echo "${class_name}" | sed 's/[^a-zA-Z0-9._-]/_/g')"
|
||||||
|
attempt_dir="./target-run/${class_key}/attempt-${attempt}"
|
||||||
|
mkdir -p "${attempt_dir}"
|
||||||
|
|
||||||
|
CID="$(docker create \
|
||||||
|
${DOCKER_NETWORK_ARG} \
|
||||||
|
-e DB_URL="${DB_URL:-}" \
|
||||||
|
-e DB_USER="${DB_USER:-}" \
|
||||||
|
-e DB_PASSWORD="${DB_PASSWORD_EFFECTIVE}" \
|
||||||
|
-e APP_URL="${APP_URL:-}" \
|
||||||
|
-e MOBILE_EMULATORS="${MOBILE_EMULATORS_VALUE}" \
|
||||||
|
-e WISHLISTS_USERNAME="${WISHLISTS_USERNAME:-}" \
|
||||||
|
-e WISHLISTS_PASSWORD="${WISHLISTS_PASSWORD:-}" \
|
||||||
|
-e GIFTS_USERNAME="${GIFTS_USERNAME:-}" \
|
||||||
|
-e GIFTS_PASSWORD="${GIFTS_PASSWORD:-}" \
|
||||||
|
-e RESERVATION_USERNAME="${RESERVATION_USERNAME:-}" \
|
||||||
|
-e RESERVATION_PASSWORD="${RESERVATION_PASSWORD:-}" \
|
||||||
|
-e RESERVATION_OWNER="${RESERVATION_OWNER:-}" \
|
||||||
|
localhost:5005/otus/test-mobile:1.0.0 \
|
||||||
|
bash -lc "set -e; cd /workspace; timeout 1800s mvn -Dallure.version=${ALLURE_ADAPTER_VERSION} -Djunit.jupiter.execution.parallel.enabled=false -Djunit.jupiter.execution.parallel.config.fixed.parallelism=${JUNIT_PARALLELISM:-1} -Dtest=${class_name} -Dsurefire.rerunFailingTestsCount=${SUREFIRE_RERUN_FAILING:-0} -Dallure.results.directory=target/allure-results test")"
|
||||||
|
|
||||||
|
tar -C "$PWD" -cf - . | docker cp - "${CID}:/workspace"
|
||||||
|
set +e
|
||||||
|
docker start -a "${CID}"
|
||||||
|
class_rc=$?
|
||||||
|
set -e
|
||||||
|
docker cp "${CID}:/workspace/target" "${attempt_dir}/target" || true
|
||||||
docker rm -f "${CID}" >/dev/null 2>&1 || true
|
docker rm -f "${CID}" >/dev/null 2>&1 || true
|
||||||
|
return "${class_rc}"
|
||||||
}
|
}
|
||||||
trap cleanup_container EXIT INT TERM
|
|
||||||
tar -C "$PWD" -cf - . | docker cp - "${CID}:/workspace"
|
collect_attempt_artifacts() {
|
||||||
set +e
|
src_dir="$1"
|
||||||
docker start -a "${CID}"
|
mkdir -p ./target/allure-results ./target/surefire-reports
|
||||||
TEST_RC=$?
|
if [ -d "${src_dir}/allure-results" ]; then
|
||||||
docker cp "${CID}:/workspace/target" "./target" || true
|
cp -a "${src_dir}/allure-results/." ./target/allure-results/ || true
|
||||||
trap - EXIT INT TERM
|
fi
|
||||||
docker rm -f "${CID}" || true
|
if [ -d "${src_dir}/surefire-reports" ]; then
|
||||||
|
cp -a "${src_dir}/surefire-reports/." ./target/surefire-reports/ || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -n "${TEST_CLASSES_ORDER:-}" ]; then
|
||||||
|
printf '%s\n' "${TEST_CLASSES_ORDER}" | tr ',' '\n' > .test-classes.txt
|
||||||
|
else
|
||||||
|
cat > .test-classes.txt <<'EOF'
|
||||||
|
ru.otus.mobile.tests.WishlistsTest
|
||||||
|
ru.otus.mobile.tests.GiftsTest
|
||||||
|
ru.otus.mobile.tests.ReservationTest
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
TEST_RC=0
|
||||||
|
MAX_CLASS_ATTEMPTS=2
|
||||||
|
while IFS= read -r raw_class; do
|
||||||
|
class_name="$(echo "${raw_class}" | xargs)"
|
||||||
|
if [ -z "${class_name}" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
CLASS_OK=0
|
||||||
|
LAST_ATTEMPT_DIR=""
|
||||||
|
for attempt in $(seq 1 "${MAX_CLASS_ATTEMPTS}"); do
|
||||||
|
echo "Running ${class_name} (attempt ${attempt}/${MAX_CLASS_ATTEMPTS})"
|
||||||
|
if run_single_class "${class_name}" "${attempt}"; then
|
||||||
|
CLASS_OK=1
|
||||||
|
LAST_ATTEMPT_DIR="./target-run/$(echo "${class_name}" | sed 's/[^a-zA-Z0-9._-]/_/g')/attempt-${attempt}/target"
|
||||||
|
collect_attempt_artifacts "${LAST_ATTEMPT_DIR}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
LAST_ATTEMPT_DIR="./target-run/$(echo "${class_name}" | sed 's/[^a-zA-Z0-9._-]/_/g')/attempt-${attempt}/target"
|
||||||
|
sleep 3
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "${CLASS_OK}" -ne 1 ]; then
|
||||||
|
TEST_RC=1
|
||||||
|
if [ -n "${LAST_ATTEMPT_DIR}" ] && [ -d "${LAST_ATTEMPT_DIR}" ]; then
|
||||||
|
collect_attempt_artifacts "${LAST_ATTEMPT_DIR}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < .test-classes.txt
|
||||||
|
|
||||||
|
mkdir -p ./target/mobile-debug
|
||||||
|
docker network inspect mobileci_default > ./target/mobile-debug/network.inspect.json 2>&1 || true
|
||||||
|
for service in android-emulator-1 android-emulator-2; do
|
||||||
|
emu_cid="$(docker ps -q --filter "name=mobileci-${service}" | head -n1 || true)"
|
||||||
|
if [ -n "${emu_cid}" ]; then
|
||||||
|
docker inspect "${emu_cid}" > "./target/mobile-debug/${service}.inspect.json" 2>&1 || true
|
||||||
|
docker logs "${emu_cid}" > "./target/mobile-debug/${service}.log" 2>&1 || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
GIT_SHA="$(git -C "$PWD" rev-parse --short HEAD)"
|
||||||
|
mkdir -p ./target/allure-results
|
||||||
|
|
||||||
|
SCREENSHOT_FILES="$(find ./target ./target-run -type f \\( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' \\) 2>/dev/null || true)"
|
||||||
|
ATTACHMENT_COUNT=0
|
||||||
|
ATTACHMENTS_JSON=""
|
||||||
|
if [ -n "${SCREENSHOT_FILES}" ]; then
|
||||||
|
while IFS= read -r screenshot_file; do
|
||||||
|
if [ -z "${screenshot_file}" ] || [ ! -f "${screenshot_file}" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
ATTACHMENT_COUNT=$((ATTACHMENT_COUNT + 1))
|
||||||
|
ext="$(echo "${screenshot_file}" | awk -F. '{print tolower($NF)}')"
|
||||||
|
if [ "${ext}" = "jpg" ] || [ "${ext}" = "jpeg" ]; then
|
||||||
|
mime="image/jpeg"
|
||||||
|
else
|
||||||
|
ext="png"
|
||||||
|
mime="image/png"
|
||||||
|
fi
|
||||||
|
source_name="external-screenshot-${ATTACHMENT_COUNT}.${ext}"
|
||||||
|
cp "${screenshot_file}" "./target/allure-results/${source_name}" || continue
|
||||||
|
safe_name="$(basename "${screenshot_file}" | sed 's/"/\\"/g')"
|
||||||
|
if [ -n "${ATTACHMENTS_JSON}" ]; then
|
||||||
|
ATTACHMENTS_JSON="${ATTACHMENTS_JSON},"
|
||||||
|
fi
|
||||||
|
ATTACHMENTS_JSON="${ATTACHMENTS_JSON}{\"name\":\"${safe_name}\",\"type\":\"${mime}\",\"source\":\"${source_name}\"}"
|
||||||
|
done <<EOF
|
||||||
|
${SCREENSHOT_FILES}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${ATTACHMENT_COUNT}" -gt 0 ]; then
|
||||||
|
EXTRA_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||||
|
TS_MS="$(( $(date +%s) * 1000 ))"
|
||||||
|
cat > "./target/allure-results/${EXTRA_UUID}-result.json" <<EOF
|
||||||
|
{
|
||||||
|
"uuid": "${EXTRA_UUID}",
|
||||||
|
"historyId": "external-screenshots-${BUILD_NUMBER}",
|
||||||
|
"name": "Collected screenshots",
|
||||||
|
"fullName": "pipeline.CollectedScreenshots",
|
||||||
|
"status": "passed",
|
||||||
|
"stage": "finished",
|
||||||
|
"start": ${TS_MS},
|
||||||
|
"stop": ${TS_MS},
|
||||||
|
"labels": [
|
||||||
|
{"name": "suite", "value": "Pipeline Artifacts"},
|
||||||
|
{"name": "package", "value": "pipeline"},
|
||||||
|
{"name": "testClass", "value": "CollectedScreenshots"},
|
||||||
|
{"name": "testMethod", "value": "attach"},
|
||||||
|
{"name": "framework", "value": "jenkins-pipeline"}
|
||||||
|
],
|
||||||
|
"attachments": [${ATTACHMENTS_JSON}],
|
||||||
|
"steps": [],
|
||||||
|
"parameters": []
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
{
|
||||||
|
echo "job=${JOB_NAME}"
|
||||||
|
echo "build=${BUILD_NUMBER}"
|
||||||
|
echo "trigger.user=${RUN_TRIGGER_USER}"
|
||||||
|
echo "trigger.name=${RUN_TRIGGER_NAME}"
|
||||||
|
echo "repo.url=${MOBILE_REPO_URL}"
|
||||||
|
echo "repo.ref=${MOBILE_REPO_REF}"
|
||||||
|
echo "repo.sha=${GIT_SHA}"
|
||||||
|
echo "app.url=${APP_URL}"
|
||||||
|
echo "db.url=${DB_URL}"
|
||||||
|
echo "db.user=${DB_USER}"
|
||||||
|
echo "reservation.owner=${RESERVATION_OWNER}"
|
||||||
|
echo "mobile.emulators=${MOBILE_EMULATORS_VALUE}"
|
||||||
|
echo "mobile.max.emulators=${MOBILE_MAX_EMULATORS:-1}"
|
||||||
|
echo "junit.parallelism=${JUNIT_PARALLELISM:-1}"
|
||||||
|
echo "test.classes.order=${TEST_CLASSES_ORDER}"
|
||||||
|
echo "surefire.rerunFailing=${SUREFIRE_RERUN_FAILING:-1}"
|
||||||
|
} > ./target/allure-results/environment.properties
|
||||||
|
cat > ./target/allure-results/executor.json <<EOF
|
||||||
|
{
|
||||||
|
"name": "Jenkins",
|
||||||
|
"type": "jenkins",
|
||||||
|
"url": "${JENKINS_URL}",
|
||||||
|
"buildName": "${JOB_NAME} #${BUILD_NUMBER}",
|
||||||
|
"buildUrl": "${BUILD_URL}",
|
||||||
|
"reportUrl": "${BUILD_URL}allure",
|
||||||
|
"buildOrder": ${BUILD_NUMBER}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
cat > ./target/allure-results/categories.json <<'EOF'
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Infrastructure issues",
|
||||||
|
"matchedStatuses": ["broken"],
|
||||||
|
"messageRegex": ".*(Connection refused|No route to host|timed out|timeout|No healthy emulators available).*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mobile UI locator/assertion issues",
|
||||||
|
"matchedStatuses": ["failed", "broken"],
|
||||||
|
"messageRegex": ".*(Element not found|NoSuchElement|AssertionError).*"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
EOF
|
||||||
exit "${TEST_RC}"
|
exit "${TEST_RC}"
|
||||||
'''
|
'''
|
||||||
}
|
}
|
||||||
@@ -121,7 +410,8 @@ pipeline {
|
|||||||
dir('project') {
|
dir('project') {
|
||||||
sh '''
|
sh '''
|
||||||
set +e
|
set +e
|
||||||
COMPOSE_FILE="/workspace/otus-autotests/hw8/config/compose/mobile-ci.compose.yml"
|
HW8_ROOT_PATH="${HW8_ROOT:-/workspace/hw8}"
|
||||||
|
COMPOSE_FILE="${HW8_ROOT_PATH}/config/compose/mobile-ci.compose.yml"
|
||||||
if docker compose version >/dev/null 2>&1; then
|
if docker compose version >/dev/null 2>&1; then
|
||||||
compose_cmd() { PROJECT_DIR="$PWD" docker compose -f "${COMPOSE_FILE}" "$@"; }
|
compose_cmd() { PROJECT_DIR="$PWD" docker compose -f "${COMPOSE_FILE}" "$@"; }
|
||||||
elif docker-compose version >/dev/null 2>&1; then
|
elif docker-compose version >/dev/null 2>&1; then
|
||||||
@@ -142,7 +432,7 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
junit allowEmptyResults: true, testResults: 'project/target/surefire-reports/*.xml'
|
junit allowEmptyResults: true, testResults: 'project/target/surefire-reports/*.xml'
|
||||||
archiveArtifacts allowEmptyArchive: true, artifacts: 'project/target/**'
|
archiveArtifacts allowEmptyArchive: true, artifacts: 'project/run-info.txt,project/target/**'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,29 +5,48 @@ pipeline {
|
|||||||
ansiColor('xterm')
|
ansiColor('xterm')
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
|
stage('Prepare Metadata') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
wrap([$class: 'BuildUser']) {
|
||||||
|
env.RUN_TRIGGER_USER = env.BUILD_USER_ID ?: env.BUILD_USER ?: 'system'
|
||||||
|
env.RUN_TRIGGER_NAME = env.BUILD_USER ?: env.BUILD_USER_ID ?: 'system'
|
||||||
|
}
|
||||||
|
currentBuild.displayName = "#${env.BUILD_NUMBER} runner"
|
||||||
|
currentBuild.description = "by=${env.RUN_TRIGGER_NAME}; qaRef=${params.QA_REPO_REF}; mobileRef=${params.MOBILE_REPO_REF}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('Run Jobs In Parallel') {
|
stage('Run Jobs In Parallel') {
|
||||||
steps {
|
steps {
|
||||||
script {
|
script {
|
||||||
def fanout = [:]
|
def fanout = [:]
|
||||||
|
|
||||||
fanout['selenium'] = {
|
fanout['selenium'] = {
|
||||||
build job: 'qa-selenium-tests',
|
def run = build job: 'qa-selenium-tests',
|
||||||
wait: true,
|
wait: true,
|
||||||
propagate: true,
|
propagate: false,
|
||||||
parameters: [
|
parameters: [
|
||||||
|
string(name: 'QA_REPO_URL', value: params.QA_REPO_URL),
|
||||||
|
string(name: 'QA_REPO_REF', value: params.QA_REPO_REF),
|
||||||
string(name: 'BROWSER', value: params.BROWSER),
|
string(name: 'BROWSER', value: params.BROWSER),
|
||||||
string(name: 'BASE_URL', value: params.BASE_URL),
|
string(name: 'BASE_URL', value: params.BASE_URL),
|
||||||
string(name: 'EXECUTION_MODE', value: params.EXECUTION_MODE),
|
string(name: 'EXECUTION_MODE', value: params.EXECUTION_MODE),
|
||||||
string(name: 'SELENOID_URL', value: params.SELENOID_URL),
|
string(name: 'SELENOID_URL', value: params.SELENOID_URL),
|
||||||
string(name: 'HEADLESS', value: params.HEADLESS)
|
string(name: 'HEADLESS', value: params.HEADLESS)
|
||||||
]
|
]
|
||||||
|
writeFile file: 'downstream-selenium.txt', text: "${run.number}|${run.result}\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
fanout['mobile'] = {
|
fanout['mobile'] = {
|
||||||
build job: 'qa-mobile-appium-tests',
|
def run = build job: 'qa-mobile-appium-tests',
|
||||||
wait: true,
|
wait: true,
|
||||||
propagate: true,
|
propagate: false,
|
||||||
parameters: [
|
parameters: [
|
||||||
|
string(name: 'MOBILE_REPO_URL', value: params.MOBILE_REPO_URL),
|
||||||
|
string(name: 'MOBILE_REPO_REF', value: params.MOBILE_REPO_REF),
|
||||||
|
string(name: 'MOBILE_MAX_EMULATORS', value: params.MOBILE_MAX_EMULATORS),
|
||||||
|
string(name: 'JUNIT_PARALLELISM', value: params.JUNIT_PARALLELISM),
|
||||||
string(name: 'APP_URL', value: params.APP_URL),
|
string(name: 'APP_URL', value: params.APP_URL),
|
||||||
string(name: 'DB_URL', value: params.DB_URL),
|
string(name: 'DB_URL', value: params.DB_URL),
|
||||||
string(name: 'DB_USER', value: params.DB_USER),
|
string(name: 'DB_USER', value: params.DB_USER),
|
||||||
@@ -40,13 +59,64 @@ pipeline {
|
|||||||
string(name: 'RESERVATION_PASSWORD', value: params.RESERVATION_PASSWORD),
|
string(name: 'RESERVATION_PASSWORD', value: params.RESERVATION_PASSWORD),
|
||||||
string(name: 'RESERVATION_OWNER', value: params.RESERVATION_OWNER)
|
string(name: 'RESERVATION_OWNER', value: params.RESERVATION_OWNER)
|
||||||
]
|
]
|
||||||
|
writeFile file: 'downstream-mobile.txt', text: "${run.number}|${run.result}\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
fanout['api'] = {
|
fanout['api'] = {
|
||||||
build job: 'qa-api-citrus-tests', wait: true, propagate: true
|
def run = build job: 'qa-api-citrus-tests',
|
||||||
|
wait: true,
|
||||||
|
propagate: false,
|
||||||
|
parameters: [
|
||||||
|
string(name: 'QA_REPO_URL', value: params.QA_REPO_URL),
|
||||||
|
string(name: 'QA_REPO_REF', value: params.QA_REPO_REF)
|
||||||
|
]
|
||||||
|
writeFile file: 'downstream-api.txt', text: "${run.number}|${run.result}\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
parallel fanout
|
parallel fanout
|
||||||
|
|
||||||
|
def parseRun = { String fileName ->
|
||||||
|
if (!fileExists(fileName)) {
|
||||||
|
return [number: 'n/a', result: 'NOT_BUILT']
|
||||||
|
}
|
||||||
|
def parts = readFile(fileName).trim().tokenize('|')
|
||||||
|
return [
|
||||||
|
number: parts ? parts[0] : 'n/a',
|
||||||
|
result: parts.size() > 1 ? parts[1] : 'UNKNOWN'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def seleniumRun = parseRun('downstream-selenium.txt')
|
||||||
|
def mobileRun = parseRun('downstream-mobile.txt')
|
||||||
|
def apiRun = parseRun('downstream-api.txt')
|
||||||
|
def lines = []
|
||||||
|
lines << "job=${env.JOB_NAME}"
|
||||||
|
lines << "build=${env.BUILD_NUMBER}"
|
||||||
|
lines << "trigger_user=${env.RUN_TRIGGER_USER}"
|
||||||
|
lines << "trigger_name=${env.RUN_TRIGGER_NAME}"
|
||||||
|
lines << "qa_repo_url=${params.QA_REPO_URL}"
|
||||||
|
lines << "qa_repo_ref=${params.QA_REPO_REF}"
|
||||||
|
lines << "mobile_repo_url=${params.MOBILE_REPO_URL}"
|
||||||
|
lines << "mobile_repo_ref=${params.MOBILE_REPO_REF}"
|
||||||
|
lines << "selenium_build=${seleniumRun.number}"
|
||||||
|
lines << "selenium_result=${seleniumRun.result}"
|
||||||
|
lines << "mobile_build=${mobileRun.number}"
|
||||||
|
lines << "mobile_result=${mobileRun.result}"
|
||||||
|
lines << "api_build=${apiRun.number}"
|
||||||
|
lines << "api_result=${apiRun.result}"
|
||||||
|
lines << "selenium_link=/job/qa-selenium-tests/${seleniumRun.number}/"
|
||||||
|
lines << "mobile_link=/job/qa-mobile-appium-tests/${mobileRun.number}/"
|
||||||
|
lines << "api_link=/job/qa-api-citrus-tests/${apiRun.number}/"
|
||||||
|
lines << "selenium_link_abs=${env.JENKINS_URL}job/qa-selenium-tests/${seleniumRun.number}/"
|
||||||
|
lines << "mobile_link_abs=${env.JENKINS_URL}job/qa-mobile-appium-tests/${mobileRun.number}/"
|
||||||
|
lines << "api_link_abs=${env.JENKINS_URL}job/qa-api-citrus-tests/${apiRun.number}/"
|
||||||
|
writeFile file: 'runner-summary.txt', text: lines.join('\n') + '\n'
|
||||||
|
archiveArtifacts allowEmptyArchive: false, artifacts: 'runner-summary.txt'
|
||||||
|
|
||||||
|
def failed = [seleniumRun, mobileRun, apiRun].any { it.result != 'SUCCESS' }
|
||||||
|
if (failed) {
|
||||||
|
error("One or more downstream QA jobs failed. See runner-summary.txt for build links and statuses.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,60 @@ pipeline {
|
|||||||
ansiColor('xterm')
|
ansiColor('xterm')
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
|
stage('Prepare Metadata') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
wrap([$class: 'BuildUser']) {
|
||||||
|
env.RUN_TRIGGER_USER = env.BUILD_USER_ID ?: env.BUILD_USER ?: 'system'
|
||||||
|
env.RUN_TRIGGER_NAME = env.BUILD_USER ?: env.BUILD_USER_ID ?: 'system'
|
||||||
|
}
|
||||||
|
currentBuild.displayName = "#${env.BUILD_NUMBER} ${params.BROWSER}/${params.HEADLESS}"
|
||||||
|
currentBuild.description =
|
||||||
|
"by=${env.RUN_TRIGGER_NAME}; repo=${params.QA_REPO_URL}; ref=${params.QA_REPO_REF}; mode=${params.EXECUTION_MODE}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('Run Selenium Tests In Docker') {
|
stage('Run Selenium Tests In Docker') {
|
||||||
steps {
|
steps {
|
||||||
sh '''
|
sh '''
|
||||||
set -eux
|
set -eux
|
||||||
|
rm -rf ./sources
|
||||||
|
git clone "${QA_REPO_URL}" ./sources
|
||||||
|
git -C ./sources checkout "${QA_REPO_REF}"
|
||||||
|
GIT_SHA="$(git -C ./sources rev-parse --short HEAD)"
|
||||||
|
if ! grep -q "<artifactId>allure-junit5</artifactId>" ./sources/pom.xml; then
|
||||||
|
awk -v ver="${ALLURE_ADAPTER_VERSION}" '
|
||||||
|
index($0, "</dependencies>") && !done {
|
||||||
|
print " <dependency>"
|
||||||
|
print " <groupId>io.qameta.allure</groupId>"
|
||||||
|
print " <artifactId>allure-junit5</artifactId>"
|
||||||
|
print " <version>" ver "</version>"
|
||||||
|
print " <scope>test</scope>"
|
||||||
|
print " </dependency>"
|
||||||
|
done=1
|
||||||
|
}
|
||||||
|
{ print }
|
||||||
|
' ./sources/pom.xml > ./sources/pom.xml.tmp
|
||||||
|
mv ./sources/pom.xml.tmp ./sources/pom.xml
|
||||||
|
fi
|
||||||
|
|
||||||
rm -rf ./artifacts
|
rm -rf ./artifacts
|
||||||
mkdir -p ./artifacts
|
mkdir -p ./artifacts
|
||||||
|
{
|
||||||
|
echo "job=${JOB_NAME}"
|
||||||
|
echo "build=${BUILD_NUMBER}"
|
||||||
|
echo "trigger_user=${RUN_TRIGGER_USER}"
|
||||||
|
echo "trigger_name=${RUN_TRIGGER_NAME}"
|
||||||
|
echo "qa_repo_url=${QA_REPO_URL}"
|
||||||
|
echo "qa_repo_ref=${QA_REPO_REF}"
|
||||||
|
echo "qa_repo_sha=${GIT_SHA}"
|
||||||
|
echo "browser=${BROWSER}"
|
||||||
|
echo "headless=${HEADLESS}"
|
||||||
|
echo "execution_mode=${EXECUTION_MODE}"
|
||||||
|
echo "selenoid_url=${SELENOID_URL}"
|
||||||
|
echo "base_url=${BASE_URL}"
|
||||||
|
echo "timestamp_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
} > ./artifacts/run-info.txt
|
||||||
|
|
||||||
EXTRA_ARGS=""
|
EXTRA_ARGS=""
|
||||||
if [ "${BROWSER}" = "chrome" ]; then
|
if [ "${BROWSER}" = "chrome" ]; then
|
||||||
@@ -20,16 +68,55 @@ pipeline {
|
|||||||
CID="$(docker create \
|
CID="$(docker create \
|
||||||
--add-host=host.docker.internal:host-gateway \
|
--add-host=host.docker.internal:host-gateway \
|
||||||
localhost:5005/otus/test-selenium:1.0.0 \
|
localhost:5005/otus/test-selenium:1.0.0 \
|
||||||
bash -lc "set -e; cd /workspace; mvn -Dexecution.mode=${EXECUTION_MODE} -Dbrowser=${BROWSER} -Dbrowser.version= -Dselenoid.url=${SELENOID_URL} -Dbase.url=${BASE_URL} -Dselenide.headless=${HEADLESS} -Dallure.results.directory=target/allure-results ${EXTRA_ARGS} test")"
|
bash -lc "set -e; cd /workspace; mvn -Dallure.version=${ALLURE_ADAPTER_VERSION} -Dexecution.mode=${EXECUTION_MODE} -Dbrowser=${BROWSER} -Dbrowser.version= -Dselenoid.url=${SELENOID_URL} -Dbase.url=${BASE_URL} -Dselenide.headless=${HEADLESS} -Dallure.results.directory=target/allure-results ${EXTRA_ARGS} test")"
|
||||||
cleanup_container() {
|
cleanup_container() {
|
||||||
docker rm -f "${CID}" >/dev/null 2>&1 || true
|
docker rm -f "${CID}" >/dev/null 2>&1 || true
|
||||||
}
|
}
|
||||||
trap cleanup_container EXIT INT TERM
|
trap cleanup_container EXIT INT TERM
|
||||||
tar -C /workspace/otus-autotests/homework_4 -cf - . | docker cp - "${CID}:/workspace"
|
tar -C ./sources -cf - . | docker cp - "${CID}:/workspace"
|
||||||
set +e
|
set +e
|
||||||
docker start -a "${CID}"
|
docker start -a "${CID}"
|
||||||
TEST_RC=$?
|
TEST_RC=$?
|
||||||
docker cp "${CID}:/workspace/target" "./artifacts/target" || true
|
docker cp "${CID}:/workspace/target" "./artifacts" || true
|
||||||
|
mkdir -p ./artifacts/target/allure-results
|
||||||
|
{
|
||||||
|
echo "job=${JOB_NAME}"
|
||||||
|
echo "build=${BUILD_NUMBER}"
|
||||||
|
echo "trigger.user=${RUN_TRIGGER_USER}"
|
||||||
|
echo "trigger.name=${RUN_TRIGGER_NAME}"
|
||||||
|
echo "repo.url=${QA_REPO_URL}"
|
||||||
|
echo "repo.ref=${QA_REPO_REF}"
|
||||||
|
echo "repo.sha=${GIT_SHA}"
|
||||||
|
echo "browser=${BROWSER}"
|
||||||
|
echo "headless=${HEADLESS}"
|
||||||
|
echo "execution.mode=${EXECUTION_MODE}"
|
||||||
|
echo "base.url=${BASE_URL}"
|
||||||
|
} > ./artifacts/target/allure-results/environment.properties
|
||||||
|
cat > ./artifacts/target/allure-results/executor.json <<EOF
|
||||||
|
{
|
||||||
|
"name": "Jenkins",
|
||||||
|
"type": "jenkins",
|
||||||
|
"url": "${JENKINS_URL}",
|
||||||
|
"buildName": "${JOB_NAME} #${BUILD_NUMBER}",
|
||||||
|
"buildUrl": "${BUILD_URL}",
|
||||||
|
"reportUrl": "${BUILD_URL}allure",
|
||||||
|
"buildOrder": ${BUILD_NUMBER}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
cat > ./artifacts/target/allure-results/categories.json <<'EOF'
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Infrastructure issues",
|
||||||
|
"matchedStatuses": ["broken"],
|
||||||
|
"messageRegex": ".*(Connection refused|No route to host|timed out|timeout).*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "UI locator/assertion issues",
|
||||||
|
"matchedStatuses": ["failed", "broken"],
|
||||||
|
"messageRegex": ".*(Element not found|NoSuchElement|AssertionError).*"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
EOF
|
||||||
trap - EXIT INT TERM
|
trap - EXIT INT TERM
|
||||||
docker rm -f "${CID}" || true
|
docker rm -f "${CID}" || true
|
||||||
exit "${TEST_RC}"
|
exit "${TEST_RC}"
|
||||||
@@ -47,7 +134,7 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
junit allowEmptyResults: true, testResults: 'artifacts/target/surefire-reports/*.xml'
|
junit allowEmptyResults: true, testResults: 'artifacts/target/surefire-reports/*.xml'
|
||||||
archiveArtifacts allowEmptyArchive: true, artifacts: 'artifacts/target/**'
|
archiveArtifacts allowEmptyArchive: true, artifacts: 'artifacts/run-info.txt,artifacts/target/**'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,6 @@
|
|||||||
parameters:
|
parameters:
|
||||||
- string:
|
- string:
|
||||||
name: JJB_PATH
|
name: JJB_PATH
|
||||||
default: /workspace/otus-autotests/hw8/config/jobs
|
default: /workspace/hw8/config/jobs
|
||||||
description: "Путь до JJB-конфигов"
|
description: "Путь до JJB-конфигов"
|
||||||
dsl: !include-raw-verbatim: ../scripts/jobs-uploader.groovy
|
dsl: !include-raw-verbatim: ../scripts/jobs-uploader.groovy
|
||||||
|
|||||||
@@ -8,4 +8,13 @@
|
|||||||
properties:
|
properties:
|
||||||
- build-discarder:
|
- build-discarder:
|
||||||
num-to-keep: 50
|
num-to-keep: 50
|
||||||
|
parameters:
|
||||||
|
- string:
|
||||||
|
name: QA_REPO_URL
|
||||||
|
default: https://git.kovbasa.ru/otus-autotests/homework_4.git
|
||||||
|
description: "Git URL репозитория с Selenium/API тестами"
|
||||||
|
- string:
|
||||||
|
name: QA_REPO_REF
|
||||||
|
default: master
|
||||||
|
description: "Git branch/tag/commit для checkout"
|
||||||
dsl: !include-raw-verbatim: ../scripts/qa-api-citrus-tests.groovy
|
dsl: !include-raw-verbatim: ../scripts/qa-api-citrus-tests.groovy
|
||||||
|
|||||||
@@ -9,6 +9,38 @@
|
|||||||
- build-discarder:
|
- build-discarder:
|
||||||
num-to-keep: 30
|
num-to-keep: 30
|
||||||
parameters:
|
parameters:
|
||||||
|
- string:
|
||||||
|
name: MOBILE_REPO_URL
|
||||||
|
default: https://git.kovbasa.ru/otus-autotests/homework_7.git
|
||||||
|
description: "Git URL репозитория с Appium тестами"
|
||||||
|
- string:
|
||||||
|
name: MOBILE_REPO_REF
|
||||||
|
default: master
|
||||||
|
description: "Git branch/tag/commit для checkout"
|
||||||
|
- string:
|
||||||
|
name: ALLURE_ADAPTER_VERSION
|
||||||
|
default: 2.29.1
|
||||||
|
description: "Версия allure-junit5 адаптера"
|
||||||
|
- choice:
|
||||||
|
name: MOBILE_MAX_EMULATORS
|
||||||
|
choices:
|
||||||
|
- "1"
|
||||||
|
- "2"
|
||||||
|
description: "Сколько эмуляторов использовать в прогоне (1=стабильнее, 2=быстрее)"
|
||||||
|
- choice:
|
||||||
|
name: JUNIT_PARALLELISM
|
||||||
|
choices:
|
||||||
|
- "1"
|
||||||
|
- "2"
|
||||||
|
description: "Параллельность JUnit классов в мобильных тестах"
|
||||||
|
- string:
|
||||||
|
name: TEST_CLASSES_ORDER
|
||||||
|
default: "ru.otus.mobile.tests.WishlistsTest,ru.otus.mobile.tests.GiftsTest,ru.otus.mobile.tests.ReservationTest"
|
||||||
|
description: "Порядок классов для поочередного запуска (-Dtest)"
|
||||||
|
- string:
|
||||||
|
name: SUREFIRE_RERUN_FAILING
|
||||||
|
default: "0"
|
||||||
|
description: "Количество surefire rerun внутри одного запуска класса (обычно 0, т.к. ретрай делается на уровне pipeline)"
|
||||||
- string:
|
- string:
|
||||||
name: APP_URL
|
name: APP_URL
|
||||||
default: http://wiremock:8080/wishlist.apk
|
default: http://wiremock:8080/wishlist.apk
|
||||||
|
|||||||
@@ -9,6 +9,28 @@
|
|||||||
- build-discarder:
|
- build-discarder:
|
||||||
num-to-keep: 50
|
num-to-keep: 50
|
||||||
parameters:
|
parameters:
|
||||||
|
- string:
|
||||||
|
name: QA_REPO_URL
|
||||||
|
default: https://git.kovbasa.ru/otus-autotests/homework_4.git
|
||||||
|
- string:
|
||||||
|
name: QA_REPO_REF
|
||||||
|
default: master
|
||||||
|
- string:
|
||||||
|
name: MOBILE_REPO_URL
|
||||||
|
default: https://git.kovbasa.ru/otus-autotests/homework_7.git
|
||||||
|
- string:
|
||||||
|
name: MOBILE_REPO_REF
|
||||||
|
default: master
|
||||||
|
- choice:
|
||||||
|
name: MOBILE_MAX_EMULATORS
|
||||||
|
choices:
|
||||||
|
- "1"
|
||||||
|
- "2"
|
||||||
|
- choice:
|
||||||
|
name: JUNIT_PARALLELISM
|
||||||
|
choices:
|
||||||
|
- "1"
|
||||||
|
- "2"
|
||||||
- choice:
|
- choice:
|
||||||
name: BROWSER
|
name: BROWSER
|
||||||
choices:
|
choices:
|
||||||
@@ -19,7 +41,7 @@
|
|||||||
default: https://otus.ru
|
default: https://otus.ru
|
||||||
- string:
|
- string:
|
||||||
name: EXECUTION_MODE
|
name: EXECUTION_MODE
|
||||||
default: selenoid
|
default: local
|
||||||
- string:
|
- string:
|
||||||
name: SELENOID_URL
|
name: SELENOID_URL
|
||||||
default: http://host.docker.internal:4444/wd/hub
|
default: http://host.docker.internal:4444/wd/hub
|
||||||
|
|||||||
@@ -9,6 +9,18 @@
|
|||||||
- build-discarder:
|
- build-discarder:
|
||||||
num-to-keep: 50
|
num-to-keep: 50
|
||||||
parameters:
|
parameters:
|
||||||
|
- string:
|
||||||
|
name: QA_REPO_URL
|
||||||
|
default: https://git.kovbasa.ru/otus-autotests/homework_4.git
|
||||||
|
description: "Git URL репозитория с Selenium/API тестами"
|
||||||
|
- string:
|
||||||
|
name: QA_REPO_REF
|
||||||
|
default: master
|
||||||
|
description: "Git branch/tag/commit для checkout"
|
||||||
|
- string:
|
||||||
|
name: ALLURE_ADAPTER_VERSION
|
||||||
|
default: 2.29.1
|
||||||
|
description: "Версия allure-junit5 адаптера"
|
||||||
- choice:
|
- choice:
|
||||||
name: BROWSER
|
name: BROWSER
|
||||||
choices:
|
choices:
|
||||||
@@ -21,7 +33,7 @@
|
|||||||
description: "Базовый URL тестируемого сайта"
|
description: "Базовый URL тестируемого сайта"
|
||||||
- string:
|
- string:
|
||||||
name: EXECUTION_MODE
|
name: EXECUTION_MODE
|
||||||
default: selenoid
|
default: local
|
||||||
description: "Режим запуска (local|selenoid)"
|
description: "Режим запуска (local|selenoid)"
|
||||||
- string:
|
- string:
|
||||||
name: SELENOID_URL
|
name: SELENOID_URL
|
||||||
|
|||||||
+18
-2
@@ -18,13 +18,29 @@
|
|||||||
- build-button
|
- build-button
|
||||||
|
|
||||||
- view:
|
- view:
|
||||||
name: QA
|
name: QA-Runner
|
||||||
view-type: list
|
view-type: list
|
||||||
description: "Тестовые job и раннер"
|
description: "Точка входа для запуска всех тестов"
|
||||||
filter-executors: true
|
filter-executors: true
|
||||||
filter-queue: true
|
filter-queue: true
|
||||||
job-name:
|
job-name:
|
||||||
- qa-runner
|
- qa-runner
|
||||||
|
columns:
|
||||||
|
- status
|
||||||
|
- weather
|
||||||
|
- job
|
||||||
|
- last-success
|
||||||
|
- last-failure
|
||||||
|
- last-duration
|
||||||
|
- build-button
|
||||||
|
|
||||||
|
- view:
|
||||||
|
name: QA-Tests
|
||||||
|
view-type: list
|
||||||
|
description: "Тестовые job"
|
||||||
|
filter-executors: true
|
||||||
|
filter-queue: true
|
||||||
|
job-name:
|
||||||
- qa-selenium-tests
|
- qa-selenium-tests
|
||||||
- qa-api-citrus-tests
|
- qa-api-citrus-tests
|
||||||
- qa-mobile-appium-tests
|
- qa-mobile-appium-tests
|
||||||
|
|||||||
Reference in New Issue
Block a user