Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cross-platform build pipeline examples. #54

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions jenkinsfile-examples/cross-platform-build/Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#!groovy

//
// This DEMO shows how to write a cross-platform(Windows/Android/Linux/iOS/MacOSX) build.
// Pipeline:
// 1.Source code checkout -> 2.Cross-Platform Build -> 3.Archiving each platform's binaries -> 4.Cleanup
//
// We assume the project's structure is like this:
//
// --project_root
// --build
// -- android-build.sh (Script to build for Android platform, will output binaries into 'dist/android/armeabi-v7a')
// -- iphoneos-build.sh (Script to build for iOS, will output binaries into 'dist/ios')
// -- macos-build.sh (Script to build for MacOSX, will output binaries into 'dist/macos')
// --src
// -- CMakeLists.txt
// -- (Your source files structured by CMake or anyother)
// --dist
// -- (Directory to hold each platform distribution binaries.)
// -- android
// -- win32
// -- ios
// -- macos
// --symbols
// -- win32 (Dir to hold PDB symbols generate from CMake)
Copy link
Member

@orrc orrc Sep 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically, information like this should go into a README in the root of this directory.

//

node('master') {

//
// #1
// Fresh checkout your cross-platform project onto the master node.
// NOTE To avoid checkout on each platform again and again, we just checkout once on the master node,
// then stash/unstash onto the target platform.
//
stage('Checkout') {
timeout(time: 10, unit: 'SECONDS') {
// Checkout source code onto master node.
// You can generate the 'checkout' command by using "Project->Pipeline Syntax->Snippet Generator"
checkout(GENERATE BY YOURSELF)

// Stash all source files for another platform usage.
// NOTE: the stashed file's scope is in node 'master', so we can unstash it later.
stash name: 'YOUR_CROSSPLATFORM_SOURCES'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I don't think it's a good idea to stash the entire workspace — but in this case if your full checkout takes less than 10 seconds, it might be ok.

But after the initial checkout, I imagine it should be faster to allow each parallel branch to update its clone, rather than stashing and unstashing the entire workspace at the start of every build.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For 'stash/unstash' topic:
In real uasge, I'm excluding much files than stashing whole worksapce, only source code was stashed, and Jenkins was setup on the same server which host my SVN, so checkout to a local workspace is fast enough for small and medium-sized project. And for this example, I removed 'exclude' session to simplify the syntax. Should we add 'exclude' back?

For 'checkout' topic:
This is a little complex, at the beginning, I'm following Jenkins guide to checkout(update clone after initial checkout) project on each platform, it works fine before I meet these two main problems:

  1. Checkout/Update on each OS made me copy at least four times(Linux/Win32/MacOS/iOS) of the same 'checkout' code in the Jenkinsfile, it doesn't smells good to me.
  2. According to the 1st reason, I'm wondering if there's any solution to avoid that copy, and I find that only 'stash/ubstash' works, but the drawback is the unstashed files is out of version control, so I need cleanup whole agent workspace after every build.

Currently the 'stash/unstash' solution works fine to me, but I'm still searching for a better one. Is there's any official examples or guidelines for cross-platform build pipleline template? Or I'll keep to make my branch better for general cross-platform usage. :)

}
}

//
// #2
// Build on each platform.
//
stage('Build Cross-Platform Libraries') {
timeout(5) {
parallel (
"win32-stream" : {
node('win32') {
// This will copy all files packaged in YOUR_CROSSPLATFORM_SOURCES to agent workspace root directory.
// To copy to another agent directory, see [https://github.com/BillHoo/pipeline-examples/tree/master/pipeline-examples/unstash-different-dir]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL should point to https://github.com/jenkinsci/pipeline-examples

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, the URL was a mistake, I'll fix it later.

unstash 'YOUR_CROSSPLATFORM_SOURCES'

// Change current directory to "build", and run CMake.
// NOTE we assume your CMake INSTALL target will put output binaries into 'dist/win32' for later usage.
dir('build') {
bat 'cmake ..\\src'
bat 'cmake --build . --config RelWithDebInfo --target INSTALL'
}
}
},

"android-stream" : {
node('android') {
unstash 'YOUR_CROSSPLATFORM_SOURCES'

// Change current directory to "build", and run Android build script.
dir('build') {
sh './android-build.sh'
}
}
},

"ios-stream" : {
node('ios') {
unstash 'YOUR_CROSSPLATFORM_SOURCES'

// Change current directory to "build", and run iOS build script.
dir('build') {
sh './iphoneos-build.sh'
}
}
},

"mac-stream" : {
node('mac') {
unstash 'YOUR_CROSSPLATFORM_SOURCES'

// Change current directory to "build", and run MacOSX build script.
dir('build') {
sh './macos-build.sh'
}
}
}
) // parallel
} // Timeout
} // State cross-platform build

//
// #3
// Cross-Platform Libraries Distribution
//
stage('Libraries Distribution') {
parallel(
"win32-archiving" : {
node('win32') {
step([$class: 'ArtifactArchiver', artifacts: 'dist\\win32\\*', fingerprint: true])
step([$class: 'ArtifactArchiver', artifacts: 'symbols\\win32\\*', fingerprint: true])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This verbose syntax is no longer required; archiveArtifacts artifacts: '**/foo.bar', fingerprint: true should be sufficient.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deal, this will be fixed later.

}
},

"android-archiving" : {
node('android') {
step([$class: 'ArtifactArchiver', artifacts: 'dist/android/armeabi-v7a/*', fingerprint: true])
}
},

"ios-archiving" : {
node('ios') {
step([$class: 'ArtifactArchiver', artifacts: 'dist/ios/*', fingerprint: true])
}
},

"mac-archiving" : {
node('mac') {
step([$class: 'ArtifactArchiver', artifacts: 'dist/macos/*', fingerprint: true])
}
}
) // parallel
}

//
// #4
// Final cleanup
// Why we need this cleaup?
// stash/unstash command just copy files from source to dest without any version control stuff like Git/SVN did.
// So all files will stay in agent workspace if we dont't remove it, and may cause issues when we launch next build.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to above: I'd just use git clean (if using Git) :)

//
stage('Cleanup') {
parallel(
"win32-clean" : {
node('win32') {
deleteDir()
}
},

"android-clean" : {
node('android') {
deleteDir()
}
},

"ios-clean" : {
node('ios') {
deleteDir()
}
},

"mac-clean" : {
node('mac') {
deleteDir()
}
}
) // parallel
} // Cleanup

} // node master