react-native/Jenkinsfile

207 lines
6.9 KiB
Groovy

import groovy.json.JsonSlurperClassic
def runPipeline() {
try {
ansiColor('xterm') {
runStages();
}
} catch(err) {
echo "Error: ${err}"
currentBuild.result = "FAILED"
}
}
def pullDockerImage(imageName) {
def result = sh(script: "docker pull ${imageName}", returnStatus: true)
if (result != 0) {
throw new Exception("Failed to pull image[${imageName}]")
}
}
def buildDockerfile(dockerfilePath = "Dockerfile", imageName) {
def buildCmd = "docker build -f ${dockerfilePath} -t ${imageName} ."
echo "${buildCmd}"
def result = sh(script: buildCmd, returnStatus: true)
if (result != 0) {
throw new Exception("Failed to build image[${imageName}] from '${dockerfilePath}'")
}
}
def runCmdOnDockerImage(imageName, cmd, run_opts = '') {
def result = sh(script: "docker run ${run_opts} -i ${imageName} sh -c '${cmd}'", returnStatus: true)
if(result != 0) {
throw new Exception("Failed to run cmd[${cmd}] on image[${imageName}]")
}
}
def calculateGithubInfo() {
return [
branch: env.BRANCH_NAME,
sha: sh(returnStdout: true, script: 'git rev-parse HEAD').trim(),
tag: null,
isPR: "${env.CHANGE_URL}".contains('/pull/')
]
}
def getParallelInstrumentationTests(testDir, parallelCount, imageName) {
def integrationTests = [:]
def testCount = sh(script: "ls ${testDir} | wc -l", returnStdout: true).trim().toInteger()
def testPerParallel = testCount.intdiv(parallelCount) + 1
def ignoredTests = 'CatalystNativeJavaToJSReturnValuesTestCase|CatalystUIManagerTestCase|CatalystMeasureLayoutTest|CatalystNativeJavaToJSArgumentsTestCase|CatalystNativeJSToJavaParametersTestCase|ReactScrollViewTestCase|ReactHorizontalScrollViewTestCase|ViewRenderingTestCase';
for (def x = 0; (x*testPerParallel) < testCount; x++) {
def offset = x
integrationTests["android integration tests: ${offset}"] = {
run: {
runCmdOnDockerImage(imageName, "bash /app/ContainerShip/scripts/run-android-docker-instrumentation-tests.sh --offset=${offset} --count=${testPerParallel} --ignore=\"${ignoredTests}\"", '--privileged --rm')
}
}
}
return integrationTests
}
def runStages() {
def buildInfo = [
image: [
name: "facebook/react-native",
tag: null
],
scm: [
branch: null,
sha: null,
tag: null,
isPR: false
]
]
node {
def jsDockerBuild, androidDockerBuild
def jsTag, androidTag, jsImageName, androidImageName, parallelInstrumentationTests
try {
stage('Setup') {
parallel(
'pull images': {
pullDockerImage('containership/android-base:latest')
}
)
}
stage('Build') {
checkout scm
def githubInfo = calculateGithubInfo()
buildInfo.scm.branch = githubInfo.branch
buildInfo.scm.sha = githubInfo.sha
buildInfo.scm.tag = githubInfo.tag
buildInfo.scm.isPR = githubInfo.isPR
buildInfo.image.tag = "${buildInfo.scm.sha}-${env.BUILD_TAG.replace(" ", "-").replace("/", "-").replace("%2F", "-")}"
jsTag = "${buildInfo.image.tag}"
androidTag = "${buildInfo.image.tag}"
jsImageName = "${buildInfo.image.name}-js:${jsTag}"
androidImageName = "${buildInfo.image.name}-android:${androidTag}"
parallelInstrumentationTests = getParallelInstrumentationTests('./ReactAndroid/src/androidTest/java/com/facebook/react/tests', 3, androidImageName)
parallel(
'javascript build': {
jsDockerBuild = docker.build("${jsImageName}", "-f ContainerShip/Dockerfile.javascript .")
},
'android build': {
androidDockerBuild = docker.build("${androidImageName}", "-f ContainerShip/Dockerfile.android .")
}
)
}
stage('Tests JS') {
try {
parallel(
'javascript flow': {
runCmdOnDockerImage(jsImageName, 'yarn run flow -- check', '--rm')
},
'javascript tests': {
runCmdOnDockerImage(jsImageName, 'yarn test --maxWorkers=4', '--rm')
},
'documentation tests': {
runCmdOnDockerImage(jsImageName, 'cd website && yarn test', '--rm')
},
'documentation generation': {
runCmdOnDockerImage(jsImageName, 'cd website && node ./server/generate.js', '--rm')
}
)
} catch(e) {
currentBuild.result = "FAILED"
echo "Test JS Stage Error: ${e}"
}
}
stage('Tests Android') {
try {
parallel(
'android unit tests': {
runCmdOnDockerImage(androidImageName, 'bash /app/ContainerShip/scripts/run-android-docker-unit-tests.sh', '--privileged --rm')
},
'android e2e tests': {
runCmdOnDockerImage(androidImageName, 'bash /app/ContainerShip/scripts/run-ci-e2e-tests.sh --android --js', '--privileged --rm')
}
)
} catch(e) {
currentBuild.result = "FAILED"
echo "Tests Android Stage Error: ${e}"
}
}
stage('Tests Android Instrumentation') {
// run all tests in parallel
try {
parallel(parallelInstrumentationTests)
} catch(e) {
currentBuild.result = "FAILED"
echo "Tests Android Instrumentation Stage Error: ${e}"
}
}
stage('Cleanup') {
cleanupImage(jsDockerBuild)
cleanupImage(androidDockerBuild)
}
} catch(err) {
cleanupImage(jsDockerBuild)
cleanupImage(androidDockerBuild)
throw err
}
}
}
def isMasterBranch() {
return env.GIT_BRANCH == 'master'
}
def gitCommit() {
return sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
}
def cleanupImage(image) {
if (image) {
try {
sh "docker ps -a | awk '{ print \$1,\$2 }' | grep ${image.id} | awk '{print \$1 }' | xargs -I {} docker rm {}"
sh "docker rmi -f ${image.id}"
} catch(e) {
echo "Error cleaning up ${image.id}"
echo "${e}"
}
}
}
runPipeline()