Set up Jenkins jobs for web and mobile tests
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
target/
|
||||||
|
build/
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
.DS_Store
|
||||||
|
jenkins_home/
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
FROM jenkins/jenkins:lts-jdk21
|
||||||
|
|
||||||
|
USER root
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
ca-certificates \
|
||||||
|
curl \
|
||||||
|
git \
|
||||||
|
maven \
|
||||||
|
docker.io \
|
||||||
|
docker-compose \
|
||||||
|
chromium \
|
||||||
|
firefox-esr \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
|
||||||
|
RUN jenkins-plugin-cli --plugin-file /usr/share/jenkins/ref/plugins.txt
|
||||||
|
|
||||||
|
COPY init.groovy.d/ /usr/share/jenkins/ref/init.groovy.d/
|
||||||
|
COPY jobs/ /usr/share/jenkins/ref/job-xml/
|
||||||
|
|
||||||
|
USER jenkins
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# OTUS Homework 8: Jenkins Jobs
|
||||||
|
|
||||||
|
Проект поднимает Jenkins в Docker и автоматически создает 2 job:
|
||||||
|
- `selenium-tests` для Selenium/Selenide тестов по Otus с выбором браузера;
|
||||||
|
- `mobile-appium-tests` для Appium тестов мобильного приложения с Allure-отчетом.
|
||||||
|
|
||||||
|
## Что входит в проект
|
||||||
|
- `Dockerfile`, `docker-compose.yml` — Jenkins с предустановленными инструментами.
|
||||||
|
- `init.groovy.d/` — автосоздание пользователя `admin/admin`, job и Allure CLI.
|
||||||
|
- `jobs/selenium-tests.xml` — job для `https://git.kovbasa.ru/otus-autotests/homework_4.git`.
|
||||||
|
- `jobs/mobile-appium-tests.xml` — job для `https://git.kovbasa.ru/otus-autotests/homework_7.git`.
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
- Docker и Docker Compose.
|
||||||
|
- Доступ Jenkins-контейнера в интернет для клонирования репозиториев и загрузки Maven dependencies.
|
||||||
|
- Для Appium job:
|
||||||
|
- доступ к БД `jdbc:postgresql://sql.otus.kartushin.su:5432/wishlist`;
|
||||||
|
- хост, на котором Docker может поднять `budtmo/docker-android`.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
1. Поднять Jenkins:
|
||||||
|
```bash
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
2. Открыть `http://localhost:8081`.
|
||||||
|
3. Войти под `admin` / `admin`.
|
||||||
|
4. Убедиться, что автоматически созданы job:
|
||||||
|
- `selenium-tests`
|
||||||
|
- `mobile-appium-tests`
|
||||||
|
|
||||||
|
## Запуск job
|
||||||
|
|
||||||
|
### selenium-tests
|
||||||
|
Запускать через **Build with Parameters**. Рабочие значения по умолчанию:
|
||||||
|
- `REPO_URL=https://git.kovbasa.ru/otus-autotests/homework_4.git`
|
||||||
|
- `BRANCH=master`
|
||||||
|
- `BROWSER=chrome`
|
||||||
|
- `EXECUTION_MODE=local`
|
||||||
|
- `HEADLESS=true`
|
||||||
|
|
||||||
|
### mobile-appium-tests
|
||||||
|
Запускать через **Build with Parameters**. Рабочие значения по умолчанию:
|
||||||
|
- `REPO_URL=https://git.kovbasa.ru/otus-autotests/homework_7.git`
|
||||||
|
- `BRANCH=master`
|
||||||
|
- `DB_URL=jdbc:postgresql://sql.otus.kartushin.su:5432/wishlist`
|
||||||
|
- `DB_USER=student`
|
||||||
|
|
||||||
|
Обязательно заполнить:
|
||||||
|
- `DB_PASSWORD`
|
||||||
|
|
||||||
|
Опционально:
|
||||||
|
- `APP_URL` — если задан, APK будет скачан автоматически; если пусто, используется APK из репозитория `homework_7`.
|
||||||
|
|
||||||
|
## Результат
|
||||||
|
- Allure-отчет публикуется в каждой job после завершения билда.
|
||||||
|
- XML job лежат в каталоге `jobs/` и могут быть выданы как результат домашнего задания.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
services:
|
||||||
|
jenkins:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8081:8080"
|
||||||
|
- "50000:50000"
|
||||||
|
environment:
|
||||||
|
- JAVA_OPTS=-Djenkins.install.runSetupWizard=false
|
||||||
|
user: root
|
||||||
|
volumes:
|
||||||
|
- ./jenkins_home:/var/jenkins_home
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import jenkins.model.Jenkins
|
||||||
|
import hudson.security.HudsonPrivateSecurityRealm
|
||||||
|
import hudson.security.FullControlOnceLoggedInAuthorizationStrategy
|
||||||
|
|
||||||
|
def jenkins = Jenkins.instance
|
||||||
|
def realm = new HudsonPrivateSecurityRealm(false)
|
||||||
|
if (realm.getAllUsers().isEmpty()) {
|
||||||
|
realm.createAccount("admin", "admin")
|
||||||
|
}
|
||||||
|
jenkins.setSecurityRealm(realm)
|
||||||
|
|
||||||
|
def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
|
||||||
|
strategy.setAllowAnonymousRead(true)
|
||||||
|
jenkins.setAuthorizationStrategy(strategy)
|
||||||
|
|
||||||
|
jenkins.save()
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import jenkins.model.Jenkins
|
||||||
|
|
||||||
|
def jenkins = Jenkins.instance
|
||||||
|
def xmlDir = new File(jenkins.root, "job-xml")
|
||||||
|
if (!xmlDir.exists()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlDir.eachFileMatch(~/.*\.xml/) { file ->
|
||||||
|
def jobName = file.name.replaceFirst(/\.xml$/, "")
|
||||||
|
def existing = jenkins.getItem(jobName)
|
||||||
|
if (existing != null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
def fis = new FileInputStream(file)
|
||||||
|
try {
|
||||||
|
jenkins.createProjectFromXML(jobName, fis)
|
||||||
|
println "Created job: ${jobName}"
|
||||||
|
} finally {
|
||||||
|
fis.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jenkins.save()
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import jenkins.model.Jenkins
|
||||||
|
import ru.yandex.qatools.allure.jenkins.tools.AllureCommandlineInstallation
|
||||||
|
import ru.yandex.qatools.allure.jenkins.tools.AllureCommandlineInstaller
|
||||||
|
import hudson.tools.InstallSourceProperty
|
||||||
|
|
||||||
|
def jenkins = Jenkins.instance
|
||||||
|
def desc = jenkins.getDescriptorByType(AllureCommandlineInstallation.DescriptorImpl)
|
||||||
|
def existing = desc.getInstallations()
|
||||||
|
|
||||||
|
def alreadyConfigured = existing.any { it.name == "allure" }
|
||||||
|
if (!alreadyConfigured) {
|
||||||
|
def installer = new AllureCommandlineInstaller("2.29.0")
|
||||||
|
def prop = new InstallSourceProperty([installer])
|
||||||
|
def installation = new AllureCommandlineInstallation("allure", "", [prop])
|
||||||
|
desc.setInstallations(installation)
|
||||||
|
desc.save()
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
<?xml version='1.1' encoding='UTF-8'?>
|
||||||
|
<flow-definition plugin="workflow-job">
|
||||||
|
<description>Appium mobile tests with APK download and Allure report.</description>
|
||||||
|
<keepDependencies>false</keepDependencies>
|
||||||
|
<properties>
|
||||||
|
<hudson.model.ParametersDefinitionProperty>
|
||||||
|
<parameterDefinitions>
|
||||||
|
<hudson.model.StringParameterDefinition>
|
||||||
|
<name>REPO_URL</name>
|
||||||
|
<description>Git repo with Appium tests (hw7)</description>
|
||||||
|
<defaultValue>https://git.kovbasa.ru/otus-autotests/homework_7.git</defaultValue>
|
||||||
|
<trim>true</trim>
|
||||||
|
</hudson.model.StringParameterDefinition>
|
||||||
|
<hudson.model.StringParameterDefinition>
|
||||||
|
<name>BRANCH</name>
|
||||||
|
<description>Git branch</description>
|
||||||
|
<defaultValue>master</defaultValue>
|
||||||
|
<trim>true</trim>
|
||||||
|
</hudson.model.StringParameterDefinition>
|
||||||
|
<hudson.model.StringParameterDefinition>
|
||||||
|
<name>APP_URL</name>
|
||||||
|
<description>APK URL (optional). If empty, repo APK will be used.</description>
|
||||||
|
<defaultValue></defaultValue>
|
||||||
|
<trim>true</trim>
|
||||||
|
</hudson.model.StringParameterDefinition>
|
||||||
|
<hudson.model.StringParameterDefinition>
|
||||||
|
<name>DB_URL</name>
|
||||||
|
<description>JDBC url</description>
|
||||||
|
<defaultValue>jdbc:postgresql://sql.otus.kartushin.su:5432/wishlist</defaultValue>
|
||||||
|
<trim>true</trim>
|
||||||
|
</hudson.model.StringParameterDefinition>
|
||||||
|
<hudson.model.StringParameterDefinition>
|
||||||
|
<name>DB_USER</name>
|
||||||
|
<description>DB user</description>
|
||||||
|
<defaultValue>student</defaultValue>
|
||||||
|
<trim>true</trim>
|
||||||
|
</hudson.model.StringParameterDefinition>
|
||||||
|
<hudson.model.PasswordParameterDefinition>
|
||||||
|
<name>DB_PASSWORD</name>
|
||||||
|
<description>DB password</description>
|
||||||
|
</hudson.model.PasswordParameterDefinition>
|
||||||
|
</parameterDefinitions>
|
||||||
|
</hudson.model.ParametersDefinitionProperty>
|
||||||
|
</properties>
|
||||||
|
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition" plugin="workflow-cps">
|
||||||
|
<script><![CDATA[
|
||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
triggers {
|
||||||
|
pollSCM('H/5 * * * *')
|
||||||
|
}
|
||||||
|
parameters {
|
||||||
|
string(name: 'REPO_URL', defaultValue: 'https://git.kovbasa.ru/otus-autotests/homework_7.git', description: 'Git repo with Appium tests (hw7)')
|
||||||
|
string(name: 'BRANCH', defaultValue: 'master', description: 'Git branch')
|
||||||
|
string(name: 'APP_URL', defaultValue: '', description: 'APK URL (optional)')
|
||||||
|
string(name: 'DB_URL', defaultValue: 'jdbc:postgresql://sql.otus.kartushin.su:5432/wishlist', description: 'JDBC url')
|
||||||
|
string(name: 'DB_USER', defaultValue: 'student', description: 'DB user')
|
||||||
|
password(name: 'DB_PASSWORD', defaultValue: '', description: 'DB password')
|
||||||
|
}
|
||||||
|
stages {
|
||||||
|
stage('Checkout') {
|
||||||
|
steps {
|
||||||
|
git branch: params.BRANCH, url: params.REPO_URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Docker Compose') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
if (isUnix()) {
|
||||||
|
def composeCmd = 'docker compose'
|
||||||
|
if (sh(script: 'command -v docker-compose >/dev/null 2>&1', returnStatus: true) == 0) {
|
||||||
|
composeCmd = 'docker-compose'
|
||||||
|
}
|
||||||
|
if (params.APP_URL?.trim()) {
|
||||||
|
sh "APP_URL='${params.APP_URL}' ${composeCmd} up -d"
|
||||||
|
} else {
|
||||||
|
sh "${composeCmd} up -d"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
def composeCmd = 'docker compose'
|
||||||
|
if (bat(script: 'where docker-compose', returnStatus: true) == 0) {
|
||||||
|
composeCmd = 'docker-compose'
|
||||||
|
}
|
||||||
|
if (params.APP_URL?.trim()) {
|
||||||
|
bat "set APP_URL=${params.APP_URL}&& ${composeCmd} up -d"
|
||||||
|
} else {
|
||||||
|
bat "${composeCmd} up -d"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Test') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
def mvn = isUnix() ? 'mvn' : 'mvn.cmd'
|
||||||
|
if (isUnix()) {
|
||||||
|
sh "DB_URL='${params.DB_URL}' DB_USER='${params.DB_USER}' DB_PASSWORD='${params.DB_PASSWORD}' ${mvn} -Dallure.results.directory=target/allure-results test"
|
||||||
|
} else {
|
||||||
|
bat "set DB_URL=${params.DB_URL}&& set DB_USER=${params.DB_USER}&& set DB_PASSWORD=${params.DB_PASSWORD}&& ${mvn} -Dallure.results.directory=target/allure-results test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
allure includeProperties: false, jdk: '', results: [[path: 'target/allure-results']]
|
||||||
|
archiveArtifacts allowEmptyArchive: true, artifacts: 'target/**'
|
||||||
|
script {
|
||||||
|
if (isUnix()) {
|
||||||
|
def composeCmd = 'docker compose'
|
||||||
|
if (sh(script: 'command -v docker-compose >/dev/null 2>&1', returnStatus: true) == 0) {
|
||||||
|
composeCmd = 'docker-compose'
|
||||||
|
}
|
||||||
|
sh "${composeCmd} down -v || true"
|
||||||
|
} else {
|
||||||
|
def composeCmd = 'docker compose'
|
||||||
|
if (bat(script: 'where docker-compose', returnStatus: true) == 0) {
|
||||||
|
composeCmd = 'docker-compose'
|
||||||
|
}
|
||||||
|
bat "${composeCmd} down -v"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></script>
|
||||||
|
<sandbox>true</sandbox>
|
||||||
|
</definition>
|
||||||
|
<triggers/>
|
||||||
|
<disabled>false</disabled>
|
||||||
|
</flow-definition>
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version='1.1' encoding='UTF-8'?>
|
||||||
|
<flow-definition plugin="workflow-job">
|
||||||
|
<description>Selenium/Selenide tests with browser parameter and Allure report.</description>
|
||||||
|
<keepDependencies>false</keepDependencies>
|
||||||
|
<properties>
|
||||||
|
<hudson.model.ParametersDefinitionProperty>
|
||||||
|
<parameterDefinitions>
|
||||||
|
<hudson.model.StringParameterDefinition>
|
||||||
|
<name>REPO_URL</name>
|
||||||
|
<description>Git repo with Selenium/Selenide tests</description>
|
||||||
|
<defaultValue>https://git.kovbasa.ru/otus-autotests/homework_4.git</defaultValue>
|
||||||
|
<trim>true</trim>
|
||||||
|
</hudson.model.StringParameterDefinition>
|
||||||
|
<hudson.model.StringParameterDefinition>
|
||||||
|
<name>BRANCH</name>
|
||||||
|
<description>Git branch</description>
|
||||||
|
<defaultValue>master</defaultValue>
|
||||||
|
<trim>true</trim>
|
||||||
|
</hudson.model.StringParameterDefinition>
|
||||||
|
<hudson.model.ChoiceParameterDefinition>
|
||||||
|
<name>BROWSER</name>
|
||||||
|
<description>Browser to run tests</description>
|
||||||
|
<choices class="java.util.Arrays$ArrayList">
|
||||||
|
<a class="string-array">
|
||||||
|
<string>chrome</string>
|
||||||
|
<string>firefox</string>
|
||||||
|
</a>
|
||||||
|
</choices>
|
||||||
|
</hudson.model.ChoiceParameterDefinition>
|
||||||
|
<hudson.model.StringParameterDefinition>
|
||||||
|
<name>BROWSER_VERSION</name>
|
||||||
|
<description>Browser version (optional)</description>
|
||||||
|
<defaultValue></defaultValue>
|
||||||
|
<trim>true</trim>
|
||||||
|
</hudson.model.StringParameterDefinition>
|
||||||
|
<hudson.model.StringParameterDefinition>
|
||||||
|
<name>EXECUTION_MODE</name>
|
||||||
|
<description>local or selenoid</description>
|
||||||
|
<defaultValue>local</defaultValue>
|
||||||
|
<trim>true</trim>
|
||||||
|
</hudson.model.StringParameterDefinition>
|
||||||
|
<hudson.model.StringParameterDefinition>
|
||||||
|
<name>SELENOID_URL</name>
|
||||||
|
<description>Selenoid URL (used when execution.mode=selenoid)</description>
|
||||||
|
<defaultValue>http://localhost/wd/hub</defaultValue>
|
||||||
|
<trim>true</trim>
|
||||||
|
</hudson.model.StringParameterDefinition>
|
||||||
|
<hudson.model.StringParameterDefinition>
|
||||||
|
<name>BASE_URL</name>
|
||||||
|
<description>Base URL for tests</description>
|
||||||
|
<defaultValue>https://otus.ru</defaultValue>
|
||||||
|
<trim>true</trim>
|
||||||
|
</hudson.model.StringParameterDefinition>
|
||||||
|
<hudson.model.ChoiceParameterDefinition>
|
||||||
|
<name>HEADLESS</name>
|
||||||
|
<description>Run browsers in headless mode</description>
|
||||||
|
<choices class="java.util.Arrays$ArrayList">
|
||||||
|
<a class="string-array">
|
||||||
|
<string>true</string>
|
||||||
|
<string>false</string>
|
||||||
|
</a>
|
||||||
|
</choices>
|
||||||
|
</hudson.model.ChoiceParameterDefinition>
|
||||||
|
</parameterDefinitions>
|
||||||
|
</hudson.model.ParametersDefinitionProperty>
|
||||||
|
</properties>
|
||||||
|
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition" plugin="workflow-cps">
|
||||||
|
<script><![CDATA[
|
||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
triggers {
|
||||||
|
pollSCM('H/5 * * * *')
|
||||||
|
}
|
||||||
|
parameters {
|
||||||
|
string(name: 'REPO_URL', defaultValue: 'https://git.kovbasa.ru/otus-autotests/homework_4.git', description: 'Git repo with Selenium/Selenide tests')
|
||||||
|
string(name: 'BRANCH', defaultValue: 'master', description: 'Git branch')
|
||||||
|
choice(name: 'BROWSER', choices: ['chrome', 'firefox'], description: 'Browser to run tests')
|
||||||
|
string(name: 'BROWSER_VERSION', defaultValue: '', description: 'Browser version (optional)')
|
||||||
|
string(name: 'EXECUTION_MODE', defaultValue: 'local', description: 'local or selenoid')
|
||||||
|
string(name: 'SELENOID_URL', defaultValue: 'http://localhost/wd/hub', description: 'Selenoid URL')
|
||||||
|
string(name: 'BASE_URL', defaultValue: 'https://otus.ru', description: 'Base URL for tests')
|
||||||
|
choice(name: 'HEADLESS', choices: ['true', 'false'], description: 'Run browsers in headless mode')
|
||||||
|
}
|
||||||
|
stages {
|
||||||
|
stage('Checkout') {
|
||||||
|
steps {
|
||||||
|
git branch: params.BRANCH, url: params.REPO_URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Test') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
def mvn = isUnix() ? 'mvn' : 'mvn.cmd'
|
||||||
|
def extra = isUnix() ? " -Dchrome.binary=/usr/bin/chromium" : ""
|
||||||
|
def cmd = "${mvn} -Dexecution.mode=${params.EXECUTION_MODE} -Dbrowser=${params.BROWSER} -Dbrowser.version=${params.BROWSER_VERSION} -Dselenoid.url=${params.SELENOID_URL} -Dbase.url=${params.BASE_URL} -Dselenide.headless=${params.HEADLESS} -Dallure.results.directory=target/allure-results${extra} test"
|
||||||
|
if (isUnix()) {
|
||||||
|
sh cmd
|
||||||
|
} else {
|
||||||
|
bat cmd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
allure includeProperties: false, jdk: '', results: [[path: 'target/allure-results']]
|
||||||
|
archiveArtifacts allowEmptyArchive: true, artifacts: 'target/**'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></script>
|
||||||
|
<sandbox>true</sandbox>
|
||||||
|
</definition>
|
||||||
|
<triggers/>
|
||||||
|
<disabled>false</disabled>
|
||||||
|
</flow-definition>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
workflow-aggregator
|
||||||
|
git
|
||||||
|
allure-jenkins-plugin
|
||||||
|
docker-workflow
|
||||||
|
matrix-project
|
||||||
Reference in New Issue
Block a user