How to create and share your own Bitrise step

We're going to go through creating a step (properly) and sharing it with the Bitrise community. Tutorial based on a real step created and written by SΓ©bastien Pousse.

We're going to go through creating a step (properly) and sharing it with the Bitrise community. Tutorial based on a real step created and written by SΓ©bastien Pousse.

Guest blog post by SΓ©bastien Pousse, the original appeared on Developers @ Yellow Pages in French.

SΓ©bastien works for PagesJaunes (French Yellow Pages) as head of innovation and mobile strategy and he likes sports, especially climbing, squash, mountain biking and running.

Summary

Bitrise is a solution that allows you to industrialize your mobile compilations (iOS, Android, Xamarin, ReactNative, Ionic etc.) by making dedicated virtual machines available for a defined period of time.

These virtual machines are launched on demand following trigger events (activity on your source code repositories for example) and execute a workflow containing a set of steps.

A step is a cogwheel of your workflow, that will run and perform a specific task.

Bitrise offers a catalogue of steps already written:

bitrise-steps-catalog

The objective of this tutorial

In this tutorial I'll assist you in the creation of a step, explaining all the essential steps until the submission of the step to the Bitrise team to appear in the catalogue above.

Customer in the command line

Bitrise is a SAAS solution but it is still possible to work locally with it. For that, we will first install a Bitrise client in CLI with homebrew .

 
MacBook-Pro-de-spousse:~ spousse$ brew install bitrise
Copy code


Setup

We will do updates with a bitrise setup, which will take care of updating the kernel tools like envman, stepman. It'll also install Bitrise plugins, in particular, the one for steps that is important for us.


MacBook-Pro-de-spousse:~ spousse$ bitrise setup

  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
  β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β•β•β•
  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
  β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β•šβ•β•β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β•
  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
  β•šβ•β•β•β•β•β• β•šβ•β•   β•šβ•β•   β•šβ•β•  β•šβ•β•β•šβ•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•

  version: 1.12.0

Setup
Full setup: false
Clean setup: false
Detected OS: darwin

Checking Bitrise Core tools...
[OK] envman (1.1.9): /Users/spousse/.bitrise/tools/envman
[OK] stepman (0.9.37): /Users/spousse/.bitrise/tools/stepman

Doing OS X specific setup
Checking required tools...
[OK] Homebrew 1.5.2: /usr/local/bin/brew
[OK] Homebrew/homebrew-core (git revision f4c7d; last commit 2018-01-30)
[OK] xcodebuild (Xcode 8.1 | Build version 8B62): /usr/bin/xcodebuild
[OK] active Xcode (Command Line Tools) path (xcode-select --print-path): /Applications/Xcode.app/Contents/Developer

Checking Bitrise Plugins...
[OK] Plugin workflow-editor (1.1.3): /Users/spousse/.bitrise/plugins/workflow-editor
[OK] Plugin analytics (0.9.11): /Users/spousse/.bitrise/plugins/analytics
[OK] Plugin init (1.0.1): /Users/spousse/.bitrise/plugins/init
[OK] Plugin step (0.9.5): /Users/spousse/.bitrise/plugins/step

Checking Bitrise Toolkits...
[OK] go (1.9.2): /Users/spousse/.bitrise/toolkits/go/inst/go/bin/go
[OK] bash (GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)): /bin/bash

All the required tools are installed! We're ready to rock!!

To start using bitrise:
* cd into your project's directory (if you're not there already)
* call: bitrise init
* follow the guide

That's all :)
Copy code

‍

Initialization of the step

Let's get down to business. We will start with an actual case: at the moment I need to be able to upload a build to wetransfer to send it to a third party.

We will design a step which uploads a file on wetransfer.

The small novelty is that since version 1.6 of the Bitrise client in CLI, the creation of a step is simplified. Go to a working directory and run the command bitrise :step create


MacBook-Pro-de-spousse:~ spousse$ bitrise :step create
Who are you / who's the author? : kawaiseb
What's the title / name of the Step? : wetransfer
Generated Step ID (from provided Title): wetransfer
Please provide a summary : Upload files to wetransfer and share a short url to download
Please provide a description : This step send files to wetransfer. Wetransfer give you a short url to download files. Limit 2GO.
Copy code

‍
Answer all the questions above.


What's the primary category of this Step?
Please select from the list:
[1] : access-control
[2] : artifact-info
[3] : installer
[4] : deploy
[5] : utility
[6] : dependency
[7] : code-sign
[8] : build
[9] : test
[10] : notification
(type in the option's number, then hit Enter) : 5
Copy code

‍
Choose a category. I chose utility.


Toolkit: the entry/base language of the Step.
Our recommendation is to use Bash for very simple Steps
 and for more complex ones use another language, one which we have toolkit support for.
If you're just getting started with Step development our suggestion is to select Bash,
 as that's the easiest option. It's possible to convert the step later, if needed.
Note: Of course even if you select e.g. Bash as the entry language, you can run other scripts from there,
 so it's possible to write the majority of the step's code in e.g. Ruby,
 and have an entry Bash script which does nothing else except running the Ruby script.
Which toolkit (language) would you like to use?
Please select from the list:
[1] : bash
[2] : go
(type in the option's number, then hit Enter) : 1
Copy code

In my case, I chose to do the step in nodejs and the script will be launched in bash so 1) it is.


Website & source code URL:
Will you host the source code on GitHub? [YES/no]: YES
What's your GitHub username (user/org where you'll register the step's repository)? : kawaiseb
We'll use https://github.com/kawaiseb/bitrise-step-wetransfer as the website/repo URL for this step.
Please when you create the repository on GitHub for the step
 create it under the user/org: kawaiseb
 and the name of the repository should be: bitrise-step-wetransfer

Creating Step directory at: /Users/spousse/bitrise-step-wetransfer
 * [OK] created: /Users/spousse/bitrise-step-wetransfer/README.md
 * [OK] created: /Users/spousse/bitrise-step-wetransfer/LICENSE
 * [OK] created: /Users/spousse/bitrise-step-wetransfer/.gitignore
 * [OK] created: /Users/spousse/bitrise-step-wetransfer/step.yml
 * [OK] created: /Users/spousse/bitrise-step-wetransfer/bitrise.yml
 * [OK] created: /Users/spousse/bitrise-step-wetransfer/.bitrise.secrets.yml
 * [OK] created: /Users/spousse/bitrise-step-wetransfer/step.sh

Initializing git repository in step directory ...
 $ git "init"
 $ git "remote" "add" "origin" "https://github.com/kawaiseb/bitrise-step-wetransfer"

Step is ready!

You can find it at: /Users/spousse/bitrise-step-wetransfer

TIP: cd into /Users/spousse/bitrise-step-wetransfer and run bitrise run test for a quick test drive!
Copy code

I've decided to store the step on GitHub. The repository of my step is created, as well as all the necessary files.

Let's check that the test workflow starts all right...


MacBook-Pro-de-spousse:bitrise-step-wetransfer spousse$ bitrise run test
Copy code


Achtung!

There are some basic rules to know before you start:

  1. Every input, output and parameter in any step is an Environment Variable
  2. The value of an Environment Variable can only be a String
  3. If you create an environment variable in a child process, it will not be visible from the parent process

I repeat these here because these caused me some trouble πŸ™‚ (Read more about these concepts here.)

Workflows

bitrise.yml

This file is actually the main configuration file. It will allow you to create one or more workflow(s) and define one or more step(s) to execute. This is your scheduler, which you will find in the cloud. This file is in YAML format.

Let's look at some elements of the file.

Environment variables

We have a series of variables defined globally to our application. These variables are reusable from anywhere thereafter.


app:
  envs:

  # If you want to share this step into a StepLib
  - BITRISE_STEP_ID: wetransfer
  - BITRISE_STEP_VERSION: "0.0.4"
  - BITRISE_STEP_GIT_CLONE_URL: https://github.com/kawaiseb/bitrise-step-wetransfer.git
  - MY_STEPLIB_REPO_FORK_GIT_URL: https://github.com/kawaiseb/bitrise-steplib
Copy code

For the variable MY_STEPLIB_REPO_FORK_GIT_URL, the bitrise-steplib project will have to be forked. Indeed it is in this project that our step will be placed in the end.

The test workflow

The test workflow contains a step with a bash script that will display the environment variable declared above. Nothing really exciting at the moment.


workflows:
  test:
    steps:
    - script:
        inputs:
        - content: |
            #!/bin/bash
            echo "Just an example 'secrets' print."
            echo "The value of 'A_SECRET_PARAM' is: $A_SECRET_PARAM"
Copy code

The test workflow will later allow you to test your step in the command line and also on Bitrise.

Specification

Back to the step. I will declare all the parameters I need for uploading to wetransfer. Here's what I need:

  • The sender's email address
  • The email address of the recipient(s)
  • A short message to accompany the link
  • The files to send to wetransfer

It's as simple as that. Once the problem is posed, here is how to solve it.

Production

The description of the step (step.yml)

You can find the source here. In this file, we will describe the operation of the step and set all the parameters necessary for its proper functioning.

I will not go into all the details, I'll only deal with the input variables which are the most interesting in our case:


inputs:
  # All parameter we need to upload files to wetransfer
  - wtu_mailsender:
    opts:
      title: Email of the sender
      is_expand: true
      is_required: true

  - wtu_mailreceiver:
    opts:
      title: One or more email separated by comma for receiver
      is_required: true
Copy code


This will materialize as follows:

cran-of-Capture-2018-02-19-a - 08.09.34

The is_expand statement is used to directly expand the description field
The is_required statement specifies that the variable is required.

And so on for all the expected parameters. There is also a possibility of making lists.

For example, for the debug mode I just want to make an enum {yes, no}.


# Debug mode deactivated by default
  - wtu_debug_mode: "no"
    opts:
      title: "Debug mode ?"
      description: |
        Step prints additional debug information if this option
        is enabled
      is_expand: true
      is_required: false
      value_options:
        - "yes"
        - "no"
Copy code

‍
Fill in the form ...

cran-of-Capture-2018-02-19-a - 08.12.30

Execution of the step (step.sh)

You can find the source here. This file will be executed each time the step is launched.

Following feedback from Bitrise, I had to make some changes. The most important thing is not to change the working directory. This is advocated by Bitrise.

In the end, the step.sh will launch my nodejs script with the set of parameters that have been entered in the configuration interface of the step.


#!/bin/bash
set -ex

THIS_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

npm install --prefix $THIS_SCRIPT_DIR wetransfert --save

$THIS_SCRIPT_DIR/upload.js "${wtu_debug_mode}" "${wtu_mailsender}" "${wtu_mailreceiver}" "${wtu_filepath}" "${wtu_message}" "${wtu_language}"
Copy code


The main script (upload.js)

(Source file.) I will not go into the details of the script, it is not really the object of the tutorial, just understand that as a default, you can develop steps in bash and go languages. If you'd like to use any other language, you can, but you have to check if the interpreter belonging to the given language is pre-installed on the Bitrise virtual machines or not. If they are not, then choosing bash, you have to install the chosen interpreter from the bash script and also run your choice of script from there.

The transfer.js script takes arguments on the standard input that match the expected parameters and are provided by the step.


#!/usr/bin/env node

const fs = require('fs');
const { upload } = require('wetransfert');

// USAGE : node wetransfertupload.js debug sender receiver filepath message lang

let debug = process.argv[2]; //debug true/false
let sender = process.argv[3]; //email of the sender
let receivers = process.argv[4]; //email of the receiver
let filepath = process.argv[5]; //filepath where files to send are
let message = process.argv[6]; //body of the mail
let lang = process.argv[7]; //langage of the mail
let tabReceivers;

// testing parameters
if(debug == null || sender == null || receivers == null || filepath == null || lang == null) {
  console.log('ERROR : One or more parameters are invalid');
  return 1;
}
Copy code

‍

What is important in particular is to be able to notify the user quickly enough when the step does not have all the required parameters. I did not go very far with this in this first version, especially since we specify values as is_required in the step.yml.

But for example, I could verify that the given directory exists and contains many files, and if it is not the case I could directly send an error message. This saves time and interrupts the step directly.

The audit of the step

Once our step finished running, we will check that everything is ok by launching the audit of our step via the command:


MacBook-Pro-de-spousse:bitrise-step-wetransfer spousse$ bitrise run audit-this-step
Copy code

A priori it is a format validation of the step.yml which is tested here. If all went well we'll see this:


+ stepman audit --step-yml ./step.yml
INFO[13:47:49]  * [OK] Success audit (./step.yml)
Copy code

‍

Forking the bitrise-steplib project

The final goal is to put this step in the project bitrise-steplib and make a PR so that Bitrise can validate the step (or not).

Fork the project: https://github.com/bitrise-io/bitrise-steplib

Then fill in the url of the fork in the file bitrise.yml

- MY_STEPLIB_REPO_FORK_GIT_URL:https://github.com/kawaiseb/bitrise-steplib

Once this is done, you can share his step.

Share the step

Start with the command:

bitrise-step-wetransfer [master] bitrise run share-this-step

This command will prepare the PR for the stepLib. Then what only remains is to submit it to Bitrise.

cran-of-Capture-2018-02-18-a - 22.56.41

Well... I will not hide that I had to go back to it 3 times. πŸ™‚

cran-of-Capture-2018-02-19-a - 10.44.11

Before the step was accepted, here are the main reasons for the refusal by the Bitrise team:

  • Cleanness of the step: I left a lot of unnecessary things in the code
  • Bad compliance with the guidelines on variable names. The input variables must be in lower case, the output variables in upper case, for example
  • Then in my step, I made a change in a directory which could actually have an impact for a person who executed my step in his workflow

Conclusion

Well, this is it, now you can create and share a step. The nice thing is that you can use the technology of your choice, we could have done a script in Ruby or php, in short: I did not see any limits. The only limitation is to preinstall the necessary dependencies.

Feel free to write me comments, ask questions or tell me if some points are not clear enough :)

Links

You can find the source files of the step in question here: https://github.com/kawaiseb/bitrise-step-wetransfer

The bitrise-steplib Bitrise project that will need to be forked: https://github.com/bitrise-io/bitrise-steplib

The lib nodejs to use the wetransfer API: https://www.npmjs.com/package/wetransfert

The discussion forum (they are very responsive):
https://discuss.bitrise.io/

English version by Anna BΓ‘tki.

Get Started for free

Start building now, choose a plan later.

Sign Up

Get started for free

Start building now, choose a plan later.