I'm trying to mount a jenkins pipeline, with jenkinsfile and docker-compose.
My docker-compose run fine. But the next steps (test stage in Jenkinsfile) don't run.
How to tell jenkins "ok fine the docker container is fine, you can do the next thing" but prevent the docker container to stop (this is why I put rails s at the end of the command"
Here the docker-compose.yml :
version: '3'
services:
db-test:
image: postgres
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=server_dev
volumes:
- ./tmp/db:/var/lib/postgresql/data
ports:
- "${POSTGRES_PORT}:5432"
web-test:
image: starefossen/ruby-node
command: bash -c "cd /app && bundle install && rake db:migrate && rails s"
volumes:
- /home/xero/jenkins/jenkins_home/workspace/project-open-source:/app # Workspace
- /home/cache/bundle:/usr/local/bundle # Cache gemfiles
- /home/cache/node_modules:/app/node_modules # Cache yarn files
- /home/xero/.ssh:/root/.ssh # SSH keys (for git)
ports:
- "3000:3000"
depends_on:
- db-test
And the Jenkinsfile :
pipeline {
agent any
options {
timeout(time: 1, unit: 'DAYS')
disableConcurrentBuilds()
}
stages {
stage("Init") {
agent any
steps { initialize() }
}
stage("Test") {
agent any
steps { test() }
}
}
}
def initialize() {
sh 'docker-compose -f docker-compose-jenkins.yml up --build --abort-on-container-exit'
}
def test() {
sh 'docker exec -ti web-test sh -c "cd app/ && bundle exec rspec -f documentation"'
}
Here my solution. I used retry and sleep, to wait that the dockers containers starts.
#!groovy
def message = "";
def author = "";
def getLastCommitMessage = {
message = sh(returnStdout: true, script: 'git log -1 --pretty=%B').trim()
}
def getGitAuthor = {
def commit = sh(returnStdout: true, script: 'git rev-parse HEAD')
author = sh(returnStdout: true, script: "git --no-pager show -s --format='%an' ${commit}").trim()
}
pipeline {
agent any
options {
timeout(time: 1, unit: 'DAYS')
disableConcurrentBuilds()
}
stages {
stage("Init RoR and DB") {
agent any
steps { initialize() }
}
stage("Tests") {
agent any
steps { test() }
post {
success {
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false, reportDir: '/var/jenkins_home/workspace/VPX-open-source/coverage/', reportFiles: 'index.html', reportName: 'RspecCoverage', reportTitles: ''])
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false, reportDir: '/var/jenkins_home/workspace/VPX-open-source/coverage/lcov-report', reportFiles: 'index.html', reportName: 'JestCoverage', reportTitles: ''])
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false, reportDir: '/var/jenkins_home/workspace/VPX-open-source/reports/', reportFiles: 'eslint.html', reportName: 'Eslint', reportTitles: ''])
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false, reportDir: '/var/jenkins_home/workspace/VPX-open-source/reports/', reportFiles: 'rubocop.html', reportName: 'Rubocop', reportTitles: ''])
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false, reportDir: '/var/jenkins_home/workspace/VPX-open-source/reports/rubycritic/', reportFiles: 'overview.html', reportName: 'Rubycritic', reportTitles: ''])
}
}
}
}
post {
failure {
script {
getLastCommitMessage()
getGitAuthor()
}
rocketSend channel: 'myproject-ci', emoji: ':x:', message: "Build failed - Commit : '${message}' by ${author}", rawMessage: true
}
}
}
def initialize() {
sh 'docker-compose -f docker-compose-jenkins.yml up --build --detach'
}
def test() {
try {
retry(3){
sleep 25
HEALTH = sh (
script: 'docker inspect -f \'{{json .State.Health.Status}}\' vpx-web-test',
returnStdout: true
).trim()
echo "${HEALTH}"
if(HEALTH == "starting"){
return true
}
}
sh 'docker exec vpx-web-test sh -c "cd app/ && RAILS_ENV=test bundle exec rspec -f documentation"'
sh 'docker exec vpx-web-test sh -c "cd app/ && yarn test"'
sh 'docker exec vpx-web-test sh -c "cd app/ && yarn test --coverage > reports/jest-coverage.html"'
sh 'docker exec vpx-web-test sh -c "cd app/ && yarn lint --f html reports/eslint.html ; exit 0"'
sh 'docker exec vpx-web-test sh -c "cd app/ && rubycritic app/ --no-browser -p reports/rubycritic"'
sh 'docker exec vpx-web-test sh -c "cd app/ && rubocop app/ --format html -o reports/rubocop.html --fail-level error"'
}
catch (exc) {
error("Build failed")
}
finally{
sh 'docker-compose -f docker-compose-jenkins.yml down'
}
}
Related
please help me with
what are commands we write in jenkins file to upload artifacts to private repository by jenkins windows server(batch commands)
how to deploy the App to remote linux server from jenkins windows server
i have written this code but its showing error
pipeline {
agent any
}
/*
environment{
CI= 'true'
}
*/
stages {
stage('Build') {
steps {
/*
//bat '"C:\\Program Files\\nodejs\\"npm ci'
bat '"C:\\Program Files\\nodejs\\"npm config set registry http://registry.npmjs.org/'
bat '"C:\\Program Files\\nodejs\\"npm config set strict-ssl false'
bat '"C:\\Program Files\\nodejs\\"npm install'
*/
bat 'npm install'
}
}
/*
stage('test') {
steps {
//bat '"C:\\Program Files\\nodejs\\"npm config set registry http://registry.npmjs.org/'
//bat '"C:\\Program Files\\nodejs\\"npm config set strict-ssl false'
bat '"C:\\Program Files\\nodejs\\"npm test'
}
}
*/
stage('Upload to Artifactory') {
steps{
def server = Artifactory.server "ci-artifacts.devops.fds.com"
def uploadSpec = """{
"files": [
{
"pattern": "target/*.jar",
"target": "macys-release-local/com/macys/mas/application name/"
}
]
}"""
server.upload(uploadSpec)
}
}
stage('deploy') {
steps {
bat 'npm run build'
dir('properties'){
sshPublisher(publishers:
[
sshPublisherDesc(configName: 'linux server host name',
transfers: [sshTransfer(excludes: '',
execCommand: '/www/apps/mas/dev/service.sh',
execTimeout: 120000,
flatten: false,
makeEmptyDirs: false,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: '/mas/dev/',
remoteDirectorySDF: false, removePrefix: '',
sourceFiles: '**/*application-dev.properties')],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: false)
]
)
}
}
}
}
}
I am using Jenkins inside a docker container using following command
docker pull jenkins/jenkins
docker run -p 8080:8080 --name=jenkins-master jenkins/jenkins
getting this error
calc.py/var/jenkins_home/workspace/python calculator#tmp/durable-b7e99e01/script.sh: 1: /var/jenkins_home/workspace/python calculator#tmp/durable-b7e99e01/script.sh: calc.py: not found
repository link - -https://github.com/jatin633/Calculator.git
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building the application....'
}
}
stage('Test') {
steps {
echo 'Testing the application....'
git branch: 'python', url: 'https://github.com/jatin633/Calculator.git'
sh 'python calc.py'
sh 'python calculator_unittest.py'
}
}
stage('Deploy') {
steps {
echo 'Deploy the application....'
}
}
}
}
I think the calc.py file is not in root, so maybe try to change:
stage('Test') {
steps {
echo 'Testing the application....'
git branch: 'python', url: 'https://github.com/jatin633/Calculator.git'
sh 'python calc.py'
sh 'python calculator_unittest.py'
}
}
into:
stage('Checkout') {
steps {
echo 'Testing the application....'
git branch: 'python', url: 'https://github.com/jatin633/Calculator.git'
}
}
stage('Run Program') {
dir('sources') {
steps {
sh 'python calc.py'
sh 'python calculator_unittest.py'
}
}
}
Let me know if it helped. Regards!
While running my tests in jenkins pipeline, it says you have passed the cy.request() url as null. I have mentioned all of the env variables in jenkins. Could someone please advise what is the problem here ?
Error:
CypressError: cy.request()requires aurl. You did not provide a url.
my .env file:
CYPRESS_TEST_USERNAME=Test1
CYPRESS_TEST_PASSWORD=BooksTest1234
CYPRESS_BASE_URL=https://my-test-url.com/books/
CYPRESS_API_URL=https://my-test-url.com/api/v1.0/books/
my jenkins file
def channel = '#jenkins-cypress'
def ARTEFACT_DIR=""
pipeline {
agent any
stages {
stage('Clone books-suite') {
steps {
dir('books-co') {
script {
checkout([
$class: 'GitSCM',
branches: [
[name: "origin/develop"]
],
extensions: [
[$class: 'CleanCheckout'],
[$class: 'LocalBranch', localBranch: '**'],
[$class: 'CloneOption', depth: 1, noTags: false, reference: '', shallow: true, timeout: 10]
],
userRemoteConfigs: [[
credentialsId: 'fsdf68fs61-esdfsdf56546-92ea-7345bcfsfsdfb3d391',
url: 'ssh://git#bitbucket_url_location'
]],
doGenerateSubmoduleConfigurations: false,
submoduleCfg: []
])
ARTEFACT_DIR="${env.WORKSPACE}/artefacts/${BUILD_NUMBER}"
}
}
}
}
stage('Run cypress') {
steps {
script {
mattermostSend color: 'good', channel: channel, message: "**STARTING** - Cypress starts (<${env.BUILD_URL}|build ${env.BUILD_NUMBER}>)"
sh "mkdir -p \"${ARTEFACT_DIR}/videos\""
sh "mkdir -p \"${ARTEFACT_DIR}/screenshots\""
def baseUrlConfig="-e CYPRESS_baseUrl=https://my-test-url.com/books/"
def screenshotsFolderConfig="screenshotsFolder=/artefacts/screenshots"
def videosFolderConfig="videosFolder=/artefacts/videos"
def config = "--config ${screenshotsFolderConfig},${videosFolderConfig}"
def cypressArgs = "run --headless --browser chrome ${config} --project /books-suite"
sh """
docker run ${baseUrlConfig} \
-v \"${ARTEFACT_DIR}:/artefacts\" \
-e CYPRESS_OUTPUT_FILE=\"/artefacts/report.html\" \
-e CYPRESS_TEST_USERNAME=\"Test1\" \
-e CYPRESS_TEST_PASSWORD=\"BooksTest1234\" \
-e CYPRESS_BASE_URL=\"https://my-test-url.com/books/\" \
-e CYPRESS_API_URL=\"https://my-test-url.com/api/v1.0/books/\" \
cypress:latest \
/node_modules/.bin/cypress ${cypressArgs}
"""
mattermostSend color: 'good', channel: channel, message: "**SUCCESSED** - Cypress CI passed successfully (<${env.BUILD_URL}|build ${env.BUILD_NUMBER}>)"
}
}
}
}
post {
always {
script {
USER_ID = get_uid()
GROUP_ID = get_gid()
sh """
docker run --user ${USER_ID}:${GROUP_ID} \
-v \"${ARTEFACT_DIR}:/artefacts\" \
-v \"${env.WORKSPACE}/books-co:/books\" \
-e JSON_DIR=\"/books/tests/cypress/cucumber-json\" \
-e OUTPUT_FILE=\"/artefacts/report.html\" \
cypress-books-report:latest
"""
}
archiveArtifacts artifacts: "artefacts/${BUILD_NUMBER}/**/*", fingerprint: true
emailext attachmentsPattern: "artefacts/${BUILD_NUMBER}/**/*",
body: '${FILE, path="' + "artefacts/${BUILD_NUMBER}/report.html" + '"}',
mimeType: 'text/html',
to: 'first.lastman#books.com',
subject: "Cypress Jenkins Build ${currentBuild.currentResult}: Job ${env.JOB_NAME}"
sh "rm -Rf artefacts/${BUILD_NUMBER}"
mattermostSend color: 'good', channel: channel, message: "**SUCCESSED** - Cypress CI report generated (<${env.BUILD_URL}|build ${env.BUILD_NUMBER}>)"
}
failure {
mattermostSend color: 'danger', channel: channel, message: "**FAILED** - cypress CI failed (<${env.BUILD_URL}|build ${env.BUILD_NUMBER}> - <${env.BUILD_URL}console|click here to see the console output>)"
}
}
}
def get_uid() {
node('master') {
return sh(script: "id -u ${USER}", returnStdout: true).trim()
}
}
def get_gid() {
node('master') {
return sh(script: "id -g ${USER}", returnStdout: true).trim()
}
}
plugins/index.js :
module.exports = (on, config) => {
on('file:preprocessor', cucumber()),
on('before:browser:launch', (browser, launchOptions) => {
console.log("Print browser name: "+browser.name);
if (browser.name === 'chrome' || browser.name === 'chrome' && browser.isHeadless) {
launchOptions.args.push('--disable-features=SameSiteByDefaultCookies') // bypass 401 unauthorised access on chromium-based browsers
return launchOptions
}
if (browser.name === 'chrome') {
// launch chrome using incognito
launchOptions.args.push(' --incognito')
return launchOptions
}
if (browser.name === 'chrome' && browser.isHeadless) {
launchOptions.args.push('--disable-gpu');
return launchOptions
}
});
config = dotenvPlugin(config)
return config
};
commands.js file
Cypress.Commands.add("loginReq", () => {
cy.request({
method: 'POST',
url: Cypress.env('BASE_URL'), // baseUrl is prepended to url
form: true,
body: {
loginUsername: Cypress.env('TEST_USERNAME'),
loginPassword: Cypress.env('TEST_PASSWORD')
}
}).then((response)=>{
console.log("login success: "+response);
})
});
When you set CYPRESS_BASE_URL, Cypress config will look like:
{
"baseUrl": "your set base url",
"env": {
}
}
You can have a look when you run cypress open and then go to Settings in the opened test runner.
The problem is that Cypress.env() reads variables from env object, where your base url is not set because CYPRESS_BASE_URL sets baseUrl property, not env.baseUrl property.
If you want to set CYPRESS_BASE_URL and access it from your tests, then you have to invoke it with Cypress.config().baseUrl.
However, you don't really need to call (not in your example) Cypress.config().baseUrl because Cypress does that automatically for you, so:
cy
.visit('/');
really means that Cypress prepends the base url for you. The same goes for cy.request(), so in your example, you can delete it from there.
all !
I have a problem with Plugin Publisher over ftp in pipeline code. I set APP_NAME in "environment {APP_NAME='123'}" on top of pipeline code. but the variable "APP_NAME" not to be konwn by ftpPublisher。
and same as BUILD_NUMBER JOB_NAME etc vars to be known by ftpPublisher.
Any people can help me ? thank you very very much !!!
and my jenkins ver is 2.164.2 ,Publish over ftp ver is 1.15 .
pipeline {
environment {
APP_NAME='123'
}
......
stages {
stage('1. git pull') {
steps {
git(
branch: 'release',
credentialsId: '*****',
url : '*********',
changelog: true
)
sh "ls -lat"
}
}
stage('2. build') {
steps {
sh 'cnpm install'
sh 'bower install --allow-root'
sh 'gulp goluk:pro'
sh 'mkdir -p $APP_NAME target'
sh 'cp -rf dist/* $APP_NAME/'
sh 'tar jcvf $APP_NAME.tar.bz2 $APP_NAME/'
sh 'ls -lh'
sh 'mv $APP_NAME.tar.bz2 target/$APP_NAME.tar.bz2'
sh 'rm -rf $APP_NAME'
}
}
stage('3. send to ftp') {
steps {
sh 'printenv'
ftpPublisher(
masterNodeName: 'master' ,
paramPublish: [parameterName: ''],
alwaysPublishFromMaster: false,
continueOnError: false,
failOnError: false,
publishers: [
[ configName: 'ftpServer_250',
transfers: [
[ asciiMode: false,
cleanRemote: false,
excludes: '',
flatten: false,
makeEmptyDirs: true,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: '${APP_NAME}/$BUILD_NUMBER($BUILD_ID)',
remoteDirectorySDF: false,
removePrefix: '',
sourceFiles: 'target/*.tar.bz2'
]
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: true
]
]
)
}
}
}
}
change to remoteDirectory: "${APP_NAME}/$BUILD_NUMBER($BUILD_ID)"
I have a multi-container job which runs on k8s via kubernetes-jenkins plugin. everything works great but I am unable to junit or archiveArtifacts anything. I suspect it's because it exists only in the container but not sure. code is below:
def label = "foo-${UUID.randomUUID().toString()}"
podTemplate(
label: label,
containers: [
containerTemplate(name: 'c1', image: 'c1'),
containerTemplate(name: 'c2', image: 'c2'),
containerTemplate(name: 'c3', image: 'c3'),
],
volumes: [
hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'),
],
) {
node(label) {
stage('test') {
container('c1') {
sh """
cd /some-path
./generate-junit-xml
"""
archiveArtifacts allowEmptyArchive: true, artifacts: '/some-path/foo.xml'
sh "cat /some-path/foo.xml"
}
}
}
}
def label = "foo-${UUID.randomUUID().toString()}"
podTemplate(
label: label,
namespace: 'jenkins',
imagePullSecrets: [ 'myreg' ],
containers: [
containerTemplate(name: 'c1', image: 'c1'),
containerTemplate(name: 'c2', image: 'c2'),
containerTemplate(name: 'c3', image: 'c3'),
],
volumes: [
hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'),
],
) {
node(label) {
stage('test') {
container('c1') {
sh """
./something-that-generates-junit-foo-xml
"""
archiveArtifacts allowEmptyArchive: true, artifacts: '/abs/path/to/foo.xml'
sh "cat /abs/path/to/foo.xml"
}
}
}
}
build log shows the following output:
[Pipeline] archiveArtifacts
Archiving artifacts
WARN: No artifacts found that match the file pattern "/some-path/foo.xml". Configuration error?
[Pipeline] sh
[test-pipeline] Running shell script
+ cat /some-path/unittest.xml
<?xml version="1.0" encoding="utf-8"?>...</xml>
would appreciate your help!
both junit and archiveArtifacts can only archive files that are inside WORKSPACE, containers do not shave any volumes with host (where jenkins WORKSPACE is) unless you explicitly do so
I solved this with:
- adding additional volume where I save files
hostPathVolume(hostPath: '/tmp', mountPath: '/tmp')
- copying files from tmp to WORKSPACE with File Operations Plugin
dir("/tmp/screenshots") {
fileOperations([fileCopyOperation(excludes: '', flattenFiles: true, includes: '*.png', targetLocation: "${WORKSPACE}/screenshots")])
}
- archiving artifacts
archiveArtifacts allowEmptyArchive: true, artifacts: 'screenshots/**/*.png'
copying the artifacts to the Jenkins workspace will solve it
age('test') {
container('c1') {
sh """
./something-that-generates-junit-foo-xml
"""
sh 'cp /abs/path/to/foo.xml ${WORKSPACE}/abs/foo.xml'
archiveArtifacts allowEmptyArchive: true, artifacts: 'abs/foo.xml'
sh "cat /abs/path/to/foo.xml"
}
you can copy the dir if you need all the dir content
sh 'cp -r /abs/path/to/ ${WORKSPACE}/abs/to'
archiveArtifacts allowEmptyArchive: true, artifacts: 'abs/to/*.xml'