Comparing Jenkinsfiles and Bitrise YML: A side-by-side look

This series explores and compares the Jenkinsfile and Bitrise YAML, the scripting languages for Jenkins and Bitrise CI/CD pipelines, focusing on their unique approaches to automation in app development, starting with mobile.

This series will compare two popular app development automation options, Jenkins and Bitrise. In this post, we’re focusing on their configuration languages, Jenkinsfile and Bitrise YAML. We'll explore their commonalities, unique aspects, and their suitability for diverse project types, beginning with mobile development. Buckle up, because we're about to delve into the heart of their automation magic.

First things first: Jenkinsfile and bitrise.yml are scripts defining the steps your CI/CD pipeline will execute. They tell the platform what tasks to perform and in what order, to build, test, and deploy your code to an app store. They both act as blueprints to execute your CI/CD automation. While their purpose is the same, their approaches are quite different. 

Groovy vs. YAML: A tale of two languages

Below is a quick overview :

Table 1
Jenkinsfile Bitrise YML
Language

Groovy (DSL)

YAML
Learning Curve Harder due to Groovy syntax Easier due to simpler YAML syntax
Focus and flexibility Generic and unfocused. High flexibility, and extensive capabilities with plugins. Specialized and focused on mobile app development. Offers a high degree of customization by enabling user-defined script steps
Integrations Requires plugins for most integrations
Built-in integrations for common CI/CD tools and enables crafting custom steps for specific needs
Custom logic  Requires writing Groovy code for custom logic Limited custom logic options
Community and Support Large and active community. Limited/no dedicated support. YAML format is widely used. The Bitrise community is growing. Excellent ongoing support 

Jenkinsfile

A Jenkinsfile is a text file that contains the definition of a Jenkins Pipeline. Jenkinsfile uses Groovy, a general-purpose, object-oriented language. While Groovy offers flexibility and power for complex workflows, it comes with a learning curve, especially for developers unfamiliar with the syntax. The benefits include:

  • Flexibility: Developers across mobile, web, desktop, and other platforms use Jenkins to automate their development workflows. This means that, as a product, Jenkins is generic and unfocussed, but flexible enough to be suitable for various domains. It also means that using Jenkins for mobile will need additional design, development, and maintenance time and will keep the mobile teams busier than they should be.
  • Loops and conditionals: Implement complex logic using loops (for, while) and conditional statements (if, else) within the pipeline. This allows for dynamic behavior based on specific conditions like build success/failure or a branch being built. 
  • Error handling and recovery: Define custom actions to handle errors gracefully using try-catch blocks. This allows the pipeline to continue execution, notify stakeholders, or trigger remedial actions.
  • Reusable code: Encapsulate common logic or shared functionalities within reusable Groovy functions, promoting modularity and code reuse across different pipelines.
  • Scalability: Jenkinsfiles are well-suited for managing complex workflows with numerous steps and integrations.

bitrise.yml 

Bitrise embraces the simplicity of YAML (Yet Another Markup Language, or YAML Ain't Markup Language, depending on whom you ask). This lightweight data serialization format is known for its human-readable, key-value structure. The benefits of using YAML include:

  • Simple, readable, and maintainable: The YAML syntax makes learning and managing easier than complex scripting languages. The clear structure and declarative nature enhance understanding and collaboration.
  • Pre-built steps and integrations: Connect seamlessly with popular tools and services like GitHub/Gitlab/Bitbucket, Fastlane, App Center, Slack, and more, eliminating the need for custom scripting. Utilize a vast library of pre-built Steps covering common tasks like building, testing, and deploying your app. You can also write your own custom scripts, either via a “Script Step” or via creating a “Step”. Creating a “Step” lets you reuse it across multiple workflows. If you want, you can share this Step with the Bitrise community too.
  • Conditionals: Introduce conditional logic in your Bitrise workflows with `run_if` on multiple levels (step - whether the step should run; workflows in pipelines )
  • Portability and standardization: YAML files are widely used and easily parsed by various tools and platforms, promoting portability across different CI/CD systems.
  • Tailored for mobile apps: Offers features and integrations specifically relevant to mobile app development needs, streamlining your workflow.

Similarities: Holding hands across the CI/CD bridge

Despite their linguistic differences, both configuration files share some core functionalities:

  • Code-based definition: Both use code to define the workflow, enabling version control and collaboration.
  • Modular structure: Both utilize stages/workflows to group related steps, improving readability and maintainability.
  • Declarative nature: They specify what needs to be done rather than the how, promoting a concise and declarative style.
  • Structure and hierarchy: Both Jenkinsfiles and bitrise.yml utilize a hierarchical structure to define your CI/CD pipeline, breaking down complex workflows into manageable ones. Semantically, there are two levels of abstractions overall - some text
    • Phases: Both Jenkinsfile and bitrise.yml allow you to break down your automation into phases, like  "build," "test," and "deploy." This modular approach makes understanding and visualizing your CI/CD process easier.
    • Tasks: Within each phase, you define self-contained pieces of work such as cloning code, downloading dependencies, building projects, running unit tests, and uploading artifacts.
Table 2
Jenkinsfile Bitrise.yaml
Phase level Stages: Stages represent the high-level phases of your pipeline, like "Build", "Test", and "Deploy." Workflows: Workflows also define the distinct phases of your CI/CD process. You could have a "Build" workflow, a "Test" workflow, and a "Deploy" workflow.
Parallelization of phases Stages can be nested within one another using the parallel block: It allows defining multiple sub-stages within a single stage, which are then executed concurrently. These sub-stages wouldn't be considered nested stages in the traditional sense, as they run in parallel rather than sequentially.

Pipelines: A Pipeline is the top level of Bitrise’s CI/CD configuration. Pipelines can be used to organize the entire CI/CD process and to set up advanced configurations with multiple tasks running parallel and/or sequentially. A Pipeline’s building blocks are Workflows. These workflows are arranged in Stages. Workflows in each Stage run in parallel and Stages run sequentially.

Read more about it here.
Task level Steps: Define the individual actions performed within each stage. These steps can include tasks like cloning code, running commands, building projects, and uploading artifacts.

Steps: Just like in Jenkinsfile, steps define the individual actions within each workflow. These steps execute the specific tasks required for your CI/CD process.

Bitrise has over 300 Steps in its Step Library There are three types of Steps on Bitrise. You can identify each one based on their labels on our UI:

  • Official Bitrise Steps: These Steps are created and maintained by Bitrise. These Steps are labeled by a green badge and a "B".

  • Verified Steps: These Steps are created and maintained by the community, but they are owned by a service or tool or an open-source team that guarantees secure, maintained, consistent, and high-quality performance for any Bitrise user. These Steps are labeled by a blue badge and a check mark. For more information about Verified Steps, check out our guide.

  • Community Steps: These Steps can be created by anyone in the community. These Steps are not labeled and don't have a badge. If you would like to learn how to develop Steps and share them with the Bitrise community, check out Developing a new Step.

Made with HTML Tables

In essence:

  • Steps are the building blocks of your pipeline, specifying the individual actions your CI/CD platform needs to execute. Both configurations use specific commands or function calls, potentially with arguments, to define these steps.
  • Stages/Workflows provide a high-level organization for your CI/CD automation. They define the major phases of your CI/CD process. While you configure them differently in Jenkinsfile and Bitrise.yml, they both group-related steps.
  • Parallelization is achieved by nesting stages within stages on Jenkins, whereas Bitrise does that by using “Pipelines”, “Stages” and “Workflows”

Inputting Instructions:

While both configurations use code-based definitions, the type of input you provide for each level differs slightly.

Stages/Workflows

  • In Jenkinsfile, you don't directly provide input to stages. Instead, you define the stage name and then configure the steps within it using Groovy code blocks.
  • bitrise.yml allows you to provide optional configuration options directly for workflows. These options could be environment variables, custom triggers, or conditional logic for workflow execution.

Steps

  • Both Jenkinsfile and bitrise.yml use specific commands or function calls within steps to define the actions to be performed. These commands or functions can take arguments or parameters to customize the behavior of the step. For example, for Bitrise’s `Git Clone Repository` step, you would need to input your Git repository URL .

Let’s consider the below examples. 

Example 1: Running tests on iOS

Imagine you want to run your Xcode tests for your iOS app. Below is how one might achieve this on Jenkins.

stage('Build and Test') {
    steps {
        script {
          // Clone Git repository
             git branch: 'master', url: 'https://github.com/your-username/your-repo.git'

          // Run Xcode tests
             sh 'xcodebuild test -workspace your_workspace.xcworkspace -scheme your_scheme -destination "generic/platform=iOS Simulator,name=iPhone 13"'

          // Deploy test results to S3 bucket (replace with your specific details)
             sh '''
                 aws s3 cp test_results.xml s3://your-bucket-name/path/to/results/
             '''
        }
    }
}

That might seem familiar. Now, let’s look at how the Bitrise YAML could look like for the same:

run_tests:
          summary: Run your Xcode tests and get the test report.
          description: The workflow will clone your Git repo, run Xcode tests & save the test results.
          steps:
          - git-clone@%s: 
inputs: 
- repository_url: https://github.com/your-username/your-repo.git
          - xcode-test@%s:
              inputs:
              - project_path: $BITRISE_PROJECT_PATH
              - scheme: $BITRISE_SCHEME
              - test_repetition_mode: retry_on_failure
              - cache_level: none
          - deploy-to-bitrise-io@%s: {}

Here’s an explanation of the syntax:

  • run_tests: This is the name of the workflow.
  • summary: Provides a brief summary or title of what the workflow does. 
  • description: Offers a more detailed description of the workflow's steps.
  • steps: This is a list of steps that define the actions to be executed as part of the workflow.some text
    • activate-ssh-key@%s: This step likely activates an SSH key for accessing a repository or a server. The %s is a placeholder for the version or identifier of this step.
    • git-clone@%s: This step clones the Git repository. Again, %s is a placeholder.
    • xcode-test@%s: This step runs Xcode tests. It can take a few several inputs:some text
      • project_path: The path to the Xcode project or workspace.
      • scheme: The scheme within the Xcode project to use for testing.
      • test_repetition_mode: Specifies how to handle test repetitions. In this case, it's set to "retry_on_failure," meaning tests will be retried if they fail.
      • cache_level: Specifies the caching level. In this case, it's set to "none," indicating that no caching will be used.
    • deploy-to-bitrise-io@%s: This step deploys the test report or some artifacts to Bitrise.io.
    • @%s: 
      • %s: This is a placeholder that gets replaced with the actual version number of the step during workflow execution.
      • @: This symbol acts as a separator between the step name and the version.
      • For instance, if you're using version 1.2.3 of the activate-ssh-key step, the complete step definition in your workflow YAML file would look like: [email protected]
      • It's a valid syntax that means "use the latest version". We usually we don't recommend it and the best practice is major version pinning.

Example 2: Running tests on Android 

Imagine you want to run your Xcode tests for your iOS app. Below is what the syntax looks like for bitrise yaml

run_tests:
          summary: Run your Android unit tests and get the test report.
          description: The workflow will first clone your Git repository, cache your Gradle
            dependencies, install Android tools, run your Android unit tests and save the
            test report.
          steps:
          - activate-ssh-key@%s: {}
          - git-clone@%s: {}
          - android-unit-test@%s:
              inputs:
              - project_location: $PROJECT_LOCATION
              - variant: $VARIANT
              - cache_level: none
          - save-gradle-cache@%s: {}
          - deploy-to-bitrise-io@%s: {}
  • android-unit-test@%s:This step runs Android unit tests. It can take a few inputs:some text
    • project_location: The location or path of the Android project to be tested.
    • Variant: The build variant or flavor of the Android project for which unit tests should be run.
    • cache_level: none: The caching level for the step. In this case, it's set to "none," indicating that no caching will be used.

Overall, this configuration defines a workflow that sets up the environment, clones a Git repository, runs Xcode tests with specific settings, and then potentially deploys the test results to Bitrise.io.Understanding these hierarchical structures and input options will help you effectively write and manage your CI/CD pipelines in both Jenkins and Bitrise, ensuring your deployments flow smoothly.

Conclusion: Who wins the configuration file showdown?

There's no clear-cut winner. The "better" choice depends on your specific needs and preferences. Bitrise YAML is like using Legos to build your CI/CD pipeline. Pre-built blocks make it easy and fast to construct common functionalities. Also, the “script-based” legos give plenty room for customization. Jenkinsfile is like using raw wood and tools. It offers more granular control and customization but requires more effort and expertise.

  • Choose Jenkinsfile if:some text
    • You have a strong preference for and familiarity with Groovy scripting 
    • Your project requires complex workflows with heavy customization.
  • Choose bitrise.yml if:some text
    • You prioritize simplicity and readability in your CI/CD configuration, with enough room for customization later on.
    • You want to leverage a rich library of pre-built steps and minimize custom scripting.
    • You have a team with diverse technical backgrounds.

In essence:

  • Jenkinsfiles offer more flexibility and customization through the power of Groovy scripting, making them suitable for complex workflows across various development domains.
  • Bitrise YMLs prioritize simplicity and ease of use with a user-friendly YAML syntax, catering specifically to the needs of mobile app development workflows and offering built-in integrations for common tools.

Get Started for free

Start building now, choose a plan later.

Sign Up

Get started for free

Start building now, choose a plan later.