集成ci jenkins
Incorporating Continuous Integration (CI) and Continuous Delivery (CD) in the development process is undeniably the only way to validate the correctness of code changes and to identify integration errors from early on. It is also a way to have bug-free versions of an application, quickly available for testing, and ready to be shipped to production after significant code alterations.
无可否认,在开发过程中整合持续集成(CI)和持续交付(CD)是唯一可以验证代码更改正确性并尽早发现集成错误的方法。 这也是获得无错误版本的应用程序,快速进行测试并在重大代码更改后准备好交付生产的一种方法。
By integrating CI/CD in our day-to-day work, the developers can achieve two significant goals: First, the ability to run test suites on a server which is different than the development machine, so as the engineer can continue working on developing new features in a distractions-free manner, and second, the ability to send remote builds to their Product Owner or QA Engineer, in order to demo/test/review a new feature even if they cannot build and run the project on their own machines.
通过将CI / CD集成到我们的日常工作中,开发人员可以实现两个重要目标:首先,能够在与开发机器不同的服务器上运行测试套件,以便工程师可以继续进行开发工作。以无干扰的方式发布新功能;其二,能够将远程版本发送给产品负责人或质量检查工程师,以便演示/测试/审查新功能,即使他们无法在自己的计算机上构建和运行项目。
But what happens when there are multiple staging environments, and tests must run in different servers or features must be tested in different environments? Here’s where the magic happens with Jenkins and Fastlane, tools that allow to automate the process for different configurations and this is exactly where this article focuses on.
但是,当存在多个暂存环境并且测试必须在不同的服务器上运行或功能必须在不同的环境中进行测试时,会发生什么情况? 詹金斯(Jenkins)和Fastlane就是神奇的地方,这些工具可以针对不同的配置自动执行该过程,而本文正是着眼于此。
There are many excellent articles and tutorials that describe in detail how to use Jenkins and Fastlane in order to set up CI for a mobile project. However, where I want to concentrate is how we can configure the relevant scripts to work for multiple environments.
有许多出色的文章和教程详细描述了如何使用Jenkins和Fastlane来为移动项目设置CI。 但是,我要集中精力的是如何配置相关脚本以在多种环境下工作。
詹金斯与法斯特兰🛠 (Jenkins & Fastlane 🛠)
In order to understand how we can integrate CI in a project, we have to understand how Jenkins and Fastlane work. Very briefly, Jenkins is an open-source continuous integration server written in Java and it is one of the most widely used tools for managing continuous integration builds. Jenkins offers the ability to create delivery Pipelines which basically are lifecycle processes which are called Jobs, including build, document, test, package, stage, deploy, static analysis and much more. Jobs are interlinked with one another in a sequence forming the pipeline and this is where Fastlane gets involved.
为了了解如何将CI集成到项目中,我们必须了解Jenkins和Fastlane的工作方式。 简而言之,Jenkins是一个用Java编写的开源持续集成服务器,它是管理连续集成构建的最广泛使用的工具之一。 詹金斯(Jenkins)提供了创建交付管道的能力,这些交付管道基本上是 被称为Jobs的生命周期过程,包括构建,文档,测试,打包,阶段,部署,静态分析等等。 作业按照形成管道的顺序相互链接,这就是Fastlane参与其中的地方。
Fastlane is an open-source tool that is used to automate the deployment and distribution process of mobile projects (iOS & Android) offering a great number of automation features within the lifecycle of a mobile app such as packaging, code signing, distribution of builds and many more. Fastlane allows to create Lanes which are basically scripts, meaning a series of commands called Actions that describe the workflow we want to automate.
Fastlane是一种开源工具,用于自动化移动项目(iOS和Android)的部署和分发过程,在移动应用程序的生命周期内提供大量自动化功能,例如打包,代码签名,内部版本分发和分发。还有很多。 Fastlane允许创建车道 基本上是脚本,意味着一系列称为“动作”的命令,它们描述了我们要自动化的工作流程。
我们的目标🥅 (Our Goal 🥅)
So what we basically want to achieve is automate the process of distributing our iOS application by automating the uploading of our application to Testflight, from where the stakeholders (Product Owner, QA Engineer, Sales person that wants to demo the app, you name it) can log in and download it effortlessly. What is more, we want to take it a step further and be able to upload to Testflight, automatically with the click of one button:
因此,我们基本上想要实现的是通过自动将我们的应用程序上载到Testflight来自动化分发我们的iOS应用程序的过程,利益相关者(产品所有者,QA工程师,想要演示该应用程序的销售人员,您可以为其命名)可以轻松登录并下载。 更重要的是,我们希望更进一步,只需单击一个按钮即可自动上传到Testflight:
a) for multiple feature branches
a)对于多个功能分支
b) for multiple configurations corresponding to a different environment
b)对应于不同环境的多种配置
This will be our end goal 🙏.
这将是我们的最终目标。
前提条件🤓 (Prerequisites 🤓)
In this article, we consider a prerequisite that Jenkins and Fastlane have been set up, there is a great number of tutorials out there that describe in detail how to successfully perform the set up. Additionally, Jenkins will need some plugins to be installed in order in order to allow Jenkins to be triggered from Github’s webhooks and run a job. Those are the Github plugin, the Xcode plugin, the SCM plugin (Source Control Management) which will be used in order to checkout our project from Github and the Credentials Plugin in order to bound credentials to environment variables.
在本文中,我们考虑了设置Jenkins和Fastlane的先决条件,其中有大量教程详细描述了如何成功执行设置。 另外,Jenkins将需要安装一些插件,以便允许从Github的webhooks触发Jenkins并运行作业。 这些是Github插件, Xcode插件, SCM插件(源代码管理),用于从Github签出我们的项目和Credentials插件,以便将凭据绑定到环境变量。
让我们开始吧 (Let’s start 🙌🏻)
To begin with, we need to create a new Pipeline in Jenkins. This pipeline will be described by a script we are going to create that performs exactly this: uploading our app to Testflight.
首先,我们需要在詹金斯创建一个新的管道。 该管道将由我们将要创建的脚本来描述,该脚本执行的功能完全相同:将我们的应用程序上传到Testflight。
From the Jenkins Main Dashboard menu below, we select the first option => New Item (Pipeline) and we create the Jenkins Job named “Upload to Testflight”
从下面的Jenkins主仪表板菜单中,选择第一个选项=> New Item (管道),然后创建名为“ Upload to Testflight”的Jenkins作业。
To proceed we select the Configure option from the left menu and we go on by adding the configuration for the pipeline we just created. We start by adding a small description.
要继续,我们从左侧菜单中选择配置选项,然后继续添加刚创建的管道的配置。 我们首先添加一个简短的描述。
From the Definition field below, in the Pipeline section, we choose the the “Pipeline Script from SCM” option. This option instructs Jenkins to obtain the Pipeline from Source Control Management (SCM), which will be our cloned Git repository.
在下面的“定义”字段中,在“管道”部分中,选择“来自SCM的管道脚本”选项。 此选项指示Jenkins从源控制管理(SCM)获取管道,该管道将是我们克隆的Git存储库。
We add a parameter which will be the branch we want to build and upload to Testflight each time and also we add the link of the github repository by providing also a parameter for the github login credentials.
我们添加一个参数,该参数将是我们每次要构建并上传到Testflight的分支,并且我们还通过提供github登录凭据的参数来添加github存储库的链接。
Finally we define the script which will describe the whole pipeline process.
最后,我们定义脚本来描述整个管道过程。
We hit the Save button and voila! We have managed to create our Job in Jenkins. Now we are ready to start writing our script!
我们点击保存按钮,瞧! 我们已经在詹金斯(Jenkins)建立了工作。 现在我们准备开始编写脚本!
We will basically use the Scripted Pipeline approach. Our script is going to have several phases called stages which describe what our pipeline wants to do. We ultimately want to upload to Testflight but before uploading to Testflight, we want to make sure that our unit tests pass successfully. So the different phases of the automation script should include the following stages:
我们将基本上使用脚本化管道方法。 我们的脚本将有几个称为阶段的阶段,这些阶段描述了我们的管道想要做什么。 我们最终希望上传到Testflight,但是在上传到Testflight之前,我们要确保单元测试成功通过。 因此,自动化脚本的不同阶段应包括以下阶段:
- Checkout repo 结帐回购
- Install dependencies安装依赖项
- Reset simulators重置模拟器
- Run tests运行测试
- Build project建立项目
- Upload to Testflight上载到Testflight
- Cleanup 清理
Once we have written our script we want to hit the Build with Parameters option from the menu of the Pipeline we just created and specify the branch we want to build:
编写脚本后,我们要点击刚创建的管道菜单中的带参数构建选项,并指定我们要构建的分支:
After we hit the Build button, and the Pipeline runs successfully we will see the following, in Jenkins Stage view:
按下Build按钮,并且Pipeline成功运行后,我们将在Jenkins Stage视图中看到以下内容:
which will mean that we have successfully uploaded our app to Testflight!
这意味着我们已成功将我们的应用程序上传到Testflight!
In case one of those stages fails, it automatically means that the whole Job will fail and we will see the corresponding stage with a red color. In this case we can go to the Console Output option of the Job’s menu, review the logs and locate the cause of failure, and of course re-run the job after we have fixed the issue.
如果这些阶段之一失败,则自动意味着整个Job将失败,我们将看到对应的阶段为红色。 在这种情况下,我们可以转到“作业”菜单的“控制台输出”选项,查看日志并找到失败的原因,当然,在解决问题之后,请重新运行该作业。
脚本📜 (The script 📜)
So in our script, that we named MyScript.groovy, we define a function called deploy()
and inside we are going to implement the afore-mentioned stages as follows:
因此,在脚本中,我们将其命名为MyScript.groovy,我们定义了一个名为deploy()
的函数,并且在内部将实现上述阶段,如下所示:
- Checkout repo 结帐回购
We checkout our repository by using the checkout
command of the SCM plugin which will run the project checkout using the configuration options that we specified in the Jenkins Pipeline.
我们使用SCM插件的checkout
命令签出存储库,该命令将使用我们在Jenkins Pipeline中指定的配置选项来运行项目签出。
stage('Checkout') {checkout scm
}
2. Install dependencies
2.安装依赖项
stage('Install dependencies') {sh 'gem install bundler'
sh 'bundle update'
sh 'bundle exec pod repo update'
sh 'bundle exec pod install'
}
Our project uses CocoaPods as Dependency Manager, therefore we need to run pod install
in order to download the project’s dependencies. In order to execute this command, and all other shell commands, we use Bundler, which is a tool to manage a Ruby application’s gem. By executing the first 2 commands, we manage to install the bundler and then the bundler downloads all the gems that are specified in the project’s Gemfile. This is the stage where we can specify the set of tools that our app might need, for example Fastlane that we will use right after, or if we want a linter or Danger, this is the place to determine those ruby gems. Then we go on and we run pod repo update
in order to always have the latest pod versions and finally we run pod update
in order to download the project’s dependencies.
我们的项目使用CocoaPods作为Dependency Manager,因此我们需要运行pod install
来下载项目的依赖项。 为了执行此命令以及所有其他Shell命令,我们使用Bundler,它是管理Ruby应用程序的gem的工具。 通过执行前两个命令,我们设法安装捆绑器,然后捆绑器下载项目的Gemfile中指定的所有gem。 在这个阶段,我们可以指定应用程序可能需要的工具集,例如我们将在之后使用的Fastlane,或者如果我们需要短绒棉或Danger ,则可以在此处确定那些Ruby。 然后,我们继续运行pod repo update
,以始终具有最新的Pod版本,最后运行pod update
,以下载项目的依赖项。
3. Reset simulators
3.重置模拟器
stage('Reset Simulators') {sh 'bundle exec fastlane snapshot reset_simulators --force'
}
This step is optional but essential if we want to run the unit tests in the next stage effectively, and without having to worry about a potential stale condition of a simulator which may result in the unit tests failing.
此步骤是可选的,但对于我们要在下一阶段有效运行单元测试,而又不必担心模拟器可能会导致单元测试失败的陈旧状态,这一步骤必不可少。
So this is the first time that Fastlane gets in the picture. As I mentioned earlier, Fastlane uses Lanes and Fastlane has already a great number of predefined lanes, or we can create our own custom lanes inside a file called Fastfile. Here we are using a predefined lane that does exactly what we want.
因此,这是Fastlane首次出现在照片中。 如前所述,Fastlane使用Lanes,而Fastlane已经有很多预定义的车道,或者我们可以在名为Fastfile的文件中创建自己的自定义车道。 在这里,我们使用的预定义车道正是我们想要的。
So this command will delete and re-create all iOS simulators, which one might say it’s kind of extreme but sometimes “Drastic times call for drastic measures” 😜.
因此,此命令将删除并重新创建所有iOS模拟器,这可能是一种极端的情况,但有时是“严峻的时代要求采取严厉的措施”😜。
4. Run tests
4.运行测试
stage('Run Tests') {sh 'bundle exec fastlane test'
}
In this stage we run the unit tests of our project. Now the test
is a custom lane that we have implemented inside our Fastfile and has the following implementation:
在此阶段,我们运行项目的单元测试。 现在, test
是一个已在Fastfile内部实现的自定义通道,并具有以下实现:
lane :test do
scan(
clean: true,
devices: ["iPhone X"],
workspace: "our_project.xcworkspace",
scheme: "production_scheme",
code_coverage: true,
output_directory: "./test_output",
output_types: "html,junit"
)
slather(
cobertura_xml: true,
proj: "our_project.xcodeproj",
workspace: "our_project.xcworkspace",
output_directory: "./test_output",
scheme: "production_scheme",
jenkins: true,
ignore: [array_of_docs_to_ignore]
)
end
Here we use two basic Fastlane actions, the scan and the slather.
在这里,我们使用两个基本的Fastlane操作,即scan和slather 。
Scan is used in order to actually run the unit tests and can be configured with several parameters such as the workspace, scheme, code_coverage and most importantly the devices where we can specify the simulator in which we want to run our unit tests.
使用扫描是为了实际运行单元测试,并且可以配置几个参数,例如工作空间,方案,code_coverage,最重要的是可以在其中指定我们要在其中运行单元测试的模拟器的设备。
Slather is used in order to gather code coverage while running unit tests, and also takes several arguments such us the output directory of the coverage report and also an array of documents to ignore while gathering the code coverage.
Slather用于在运行单元测试时收集代码覆盖率,并且还采用了几个参数,例如覆盖率报告的输出目录,以及在收集代码覆盖率时要忽略的一系列文档。
This is where the Fastlane magic ✨ happens. By only defining this lane with just two actions we manage to effortlessly run our unit tests inside Jenkins. Note that they should obviously all be successful, otherwise this stage and the entire job will fail.
这就是Fastlane魔法✨发生的地方。 通过仅用两个动作定义此通道,我们就可以轻松地在Jenkins中运行单元测试。 请注意,它们显然应该全部成功,否则此阶段和整个工作将失败。
5. Build
5.建立
stage('Build') {
withEnv(["FASTLANE_USER=fastlane_user_email_address"]) {
withCredentials([
string([
credentialsId:'match_password_id',
variable: 'MATCH_PASSWORD'
]),
string([
credentialsId: 'fastlane_password_id',
variable: 'FASTLANE_PASSWORD']),
]) {
sh 'bundle exec fastlane build'
}
}
}
In this stage we use the withEnv Jenkins Pipeline function in order to set the necessary environment variables as specified here according to the Fastlane documentation. So we specify the FASTLANE_USER environment variable. Afterwards we set two more environment variables, the MATCH_PASSWORD and the FASTLANE_PASSWORD which cannot be obtained without credentials. Basically they are stored, encrypted for obvious reasons, inside Jenkins under the “Credential” menu option of Jenkins Dashboard, in the secret_text format, and they are obtained by providing the credentialsId.
在此阶段,我们使用withEnv Jenkins Pipeline函数来根据Fastlane文档设置此处指定的必要环境变量。 因此,我们指定FASTLANE_USER环境变量。 之后,我们再设置两个环境变量,MATCH_PASSWORD和FASTLANE_PASSWORD,如果没有凭据则无法获得。 基本上,出于明显的原因,它们被加密存储在Jenkins内的Jenkins Dashboard的“ Credential”菜单选项下,并以secret_text格式存储,并通过提供certificateId来获得它们。
Again, for the build phase, we have implemented a custom lane inside the Fastfile which will be the most complex lane that we will need to create as follows:
同样,在构建阶段,我们在Fastfile内实现了一个自定义通道,这将是我们需要创建的最复杂的通道,如下所示:
lane :build do
match(
git_branch: "the_branch_of_the_repo_with_the_prov_profile",
username: "github_username",
git_url: "github_repo_with_prov_profiles",
type: "appstore",
app_identifier: "production_app_identifier",
force: true)
version = get_version_number(
xcodeproj: "our_project.xcodeproj",
target: "production_target"
)
build_number = latest_testflight_build_number(
version: version,
app_identifier: "production_app_identifier",
initial_build_number: 0
)
increment_build_number({ build_number: build_number + 1 })
settings_to_override = {
:BUNDLE_IDENTIFIER => "production_bundle_id",
:PROVISIONING_PROFILE_SPECIFIER => "production_prov_profile",
:DEVELOPMENT_TEAM => "team_id"
}
export_options = {
iCloudContainerEnvironment: "Production",
provisioningProfiles: { "production_bundle_id": "production_prov_profile" }
}
gym(
clean: true,
scheme: "production_scheme",
configuration: "production_configuration",
xcargs: settings_to_override,
export_method: "app-store",
include_bitcode: true,
include_symbols: true,
export_options: export_options
)
end
Now let’s take this step by step.
现在,让我们逐步进行此操作。
We start by using the match Fastlane action. Match basically creates all required certificates & provisioning profiles which are stored in a separate git repository, so it basically automates the code signing experience. This means that prior to running match, we should have created a different Github repository where we have stored our provisioning profiles. Alternatively, if we don’t want to use match for the code signing, we can use the sigh and cert actions.
我们从使用匹配Fastlane操作开始。 Match基本创建了所有必需的证书和配置文件,这些证书和配置文件存储在单独的git存储库中,因此基本上可以使代码签名体验自动化。 这意味着在进行匹配之前,我们应该创建一个不同的Github存储库,在其中存储我们的配置文件。 另外,如果我们不想使用match作为代码签名,则可以使用sigh和cert动作。
Now this is where the interesting part comes up. What we want to automate, is to increase the build number for the same release in order not to do this manually every time from Xcode build settings. We are all aware of the fact that, in order to upload multiple times a build to Testflight for the same release, it automatically fails if we don’t increase the build number, and each time we have to go to the project settings or .plist file, do this manually and then try to re-upload it. With the above code, we manage to automate this procedure by following the 3 steps below:
现在这是有趣的部分出现的地方。 我们要自动化的是增加同一发行版的内部版本号,以免每次都不通过Xcode构建设置手动进行此操作。 我们都知道以下事实:为了将一个版本的版本多次上传到同一版本的Testflight,如果不增加版本号,并且每次必须转到项目设置或,它都会自动失败。 plist文件,请手动执行此操作,然后尝试重新上传它。 使用上面的代码,我们通过执行以下3个步骤来使该过程自动化:
get_version_number : Get the version of the project that is currently uploaded
get_version_number :获取当前上载的项目的版本
latest_testflight_build_number: Get the current build number for the version we obtained in the previous step
Latest_testflight_build_number :获取上一步获得的版本的当前内部版本号
increment_build_number: Increment the build number by specified times (here by one).
crement_build_number :将内部版本号增加指定的次数(此处增加一)。
This is also Fastlane magic ✨ to me!
这对我来说也是Fastlane的魔力!
Finally we continue by calling the gym action which makes the actual build and packaging of the application. It gets configured with several arguments such as the configuration, scheme, and xcargs where we can specify the bundle_identifier, export_options etc.
最后,我们通过调用Gym动作继续进行操作,该动作将实际构建和包装应用程序。 它配置了几个参数,例如配置,方案和xcargs,我们可以在其中指定bundle_identifier,export_options等。
6. Upload to Testflight
6.上传到Testflight
stage('Upload to TestFlight') {
withEnv(["FASTLANE_USER=fastlane_user_email_address"]) {
withCredentials([
string([
credentialsId: 'fastlane_password_id',
variable: 'FASTLANE_PASSWORD']),
]) {
sh "bundle exec fastlane upload_to_testflight"
}
}
}
Again here, we specify the environment variables necessary, same way we did in the previous step, and we implement another custom lane inside the Fastfile as follows:
再次在这里,我们以与上一步相同的方式指定必需的环境变量,并在Fastfile中实现另一个自定义通道,如下所示:
lane :upload_to_testflight do
pilot(
ipa: "./build/our_project.ipa",
skip_submission: true,
skip_waiting_for_build_processing: true,
app_identifier: "production_app_identifier"
)
end
We use the pilot Fastlane command which uploads the generated .ipa file from the previous step to Testflight. With this action we can also specify a changelog. We can also skip the submission of the binary, which means, the .ipa file will only be uploaded and not distributed to testers.
我们使用试验性Fastlane命令,该命令将从上一步中生成的.ipa文件上载到Testflight。 通过此操作,我们还可以指定一个变更日志。 我们也可以跳过二进制文件的提交,这意味着.ipa文件将仅被上传,而不会分发给测试人员。
7. Cleanup
7.清理
Last but not least, this is the step where we perform the Workspace cleanup by using the cleanup Jenkins plugin.
最后但并非最不重要的一步,这是我们使用清理Jenkins插件执行Workspace清理的步骤。
stage('Cleanup') {cleanWs notFailBuild: true
}
This means that we delete the Workspace when the build is done since it’s no longer needed.
这意味着完成构建后,我们将删除工作区,因为不再需要它。
So to sum up, this is is how the deploy() function looks inside a Deploy.script we have created.
综上所述,这就是deploy()函数在我们创建的Deploy.script中的外观。
def deploy() {
stage('Checkout') {
checkout scm
}
stage('Install dependencies') {
sh 'gem install bundler'
sh 'bundle update'
sh 'bundle exec pod repo update'
sh 'bundle exec pod install'
}
stage('Reset Simulators') {
sh 'bundle exec fastlane snapshot reset_simulators --force'
}
stage('Run Tests') {
sh 'bundle exec fastlane test'
}
stage('Build') {
withEnv(["FASTLANE_USER=fastlane_user_email_address"]) {
withCredentials([
string([
credentialsId:'match_password_id',
variable: 'MATCH_PASSWORD'
]),
string([
credentialsId: 'fastlane_password_id',
variable: 'FASTLANE_PASSWORD']),
]) {
sh 'bundle exec fastlane build'
}
}
}
stage('Upload to TestFlight') {
withEnv(["FASTLANE_USER=fastlane_user_email_address"]) {
withCredentials([
string([
credentialsId: 'fastlane_password_id',
variable: 'FASTLANE_PASSWORD']),
]) {
sh "bundle exec fastlane upload_to_testflight"
}
}
}
stage('Cleanup') {
cleanWs notFailBuild: true
}
}
And this is how our Fastfile looks like now:
这就是我们的Fastfile现在的样子:
fastlane_version "2.75.0"
default_platform :ios
lane :test do
scan(
clean: true,
devices: ["iPhone X"],
workspace: "our_project.xcworkspace",
scheme: "production_scheme",
code_coverage: true,
output_directory: "./test_output",
output_types: "html,junit"
)
slather(
cobertura_xml: true,
proj: "our_project.xcodeproj",
workspace: "our_project.xcworkspace",
output_directory: "./test_output",
scheme: "production_scheme",
jenkins: true,
ignore: [array_of_docs_to_ignore]
)
end
lane :build do
match(
git_branch: "the_branch_of_the_repo_with_the_prov_profile",
username: "github_username",
git_url: "github_repo_with_prov_profiles",
type: "appstore",
app_identifier: "production_app_identifier",
force: true)
version = get_version_number(
xcodeproj: "our_project.xcodeproj",
target: "production_target"
)
build_number = latest_testflight_build_number(
version: version,
app_identifier: "production_app_identifier",
initial_build_number: 0
)
increment_build_number({ build_number: build_number + 1 })
settings_to_override = {
:BUNDLE_IDENTIFIER => "production_bundle_id",
:PROVISIONING_PROFILE_SPECIFIER => "production_prov_profile",
:DEVELOPMENT_TEAM => "team_id"
}
export_options = {
iCloudContainerEnvironment: "Production",
provisioningProfiles: { "production_bundle_id": "production_prov_profile" }
}
gym(
clean: true,
scheme: "production_scheme",
configuration: "production_configuration",
xcargs: settings_to_override,
export_method: "app-store",
include_bitcode: true,
include_symbols: true,
export_options: export_options
)
end
lane :upload_to_testflight do
pilot(
ipa: "./build/our_project.ipa",
skip_submission: true,
skip_waiting_for_build_processing: true,
app_identifier: "production_app_identifier"
)
end
The deploy()
function is called from the script that we have defined in the job, the MyScript.groovy, and is the following:
从我们在作业中定义的脚本MyScript.groovy中调用deploy()
函数,如下所示:
node(label: 'ios') {
def deploy;
def utils;
String RVM = "ruby-2.5.0"
ansiColor('xterm') {
withEnv(["LANG=en_US.UTF-8", "LANGUAGE=en_US.UTF-8", "LC_ALL=en_US.UTF-8"]) {
deploy = load("jenkins/Deploy.groovy")
utils = load("jenkins/utils.groovy")
utils.withRvm(RVM) {
deploy.deploy()
}
}
}
}
We load the Deploy.groovy script and we call the deploy() function that does all the work. Here we can notice that we also load a utils.groovy script which basically helps us set some environment variables before starting the Jenkins.job. The ansiColor is another Jenkins Plugin that is used in order to colorize the output of the steps in a pipeline build. Finally, we can notice that we start the script inside a
我们加载Deploy.groovy脚本,然后调用执行所有工作的deploy()函数。 在这里我们可以注意到,我们还加载了一个utils.groovy脚本,该脚本基本上可以帮助我们在启动Jenkins.job之前设置一些环境变量。 ansiColor是另一个Jenkins插件,用于使管道构建中的步骤输出着色。 最后,我们可以注意到我们在
node(label: 'ios')
In the Scripted Pipeline, the above node
is a crucial first step as it allocates an executor and workspace for the Pipeline.
在脚本化管道中,上述node
是至关重要的第一步,因为它为管道分配了执行程序和工作区。
And this is how we have managed to create a Jenkins Job that distributes different feature branches of our application by defining the feature branch as a parameter in Jenkins.
这就是我们设法通过在Jenkins中将特征分支定义为参数来创建一个Jenkins Job的方法,该任务分配了应用程序的不同特征分支。
第2部分 (Part 2)
In the next part, we will examine how we can configure Jenkins in order to distribute our application for different environments and thus for different Xcode configurations.
在下一部分中,我们将研究如何配置Jenkins,以便将应用程序分发到不同的环境,从而分发到不同的Xcode配置。
集成ci jenkins