Xcode Server is Continuous Integration service provide by Apple to analyse, build, test and archive iOS apps. Xcode Server has been recently inbuilt with Xcode 9, which made Continuous Integration and Continuous Delivery of iOS apps just a few clicks away. Apple still hasn’t updated documentation of Xcode Server a.k.a XCS with Xcode 9 at the time of writing this post but in my earlier post, I have explained how to setup Xcode Server with Xcode 9 for iOS apps. Many XCS users have complained that Xcode Server lacks third-party integrations but I don’t think that true. XCS has provided the ability to write pre-integration and post-integration scripts to integrate with any possible third-party services. We just need to understand the API’s provided by Xcode Server and third-party services. In this post, we will see how to integrate Xcode Server with incredibly popular communication service Slack.

Why Slack Integration

Slack has become one of the most popular collaborative tools for most of the companies. Almost everyone loves Slack because of its slickness and awesome features. There is hardly any organization where you don’t see Slack unless they are Slack competitors. Slack is being used as communication channel within the organization for collaborative working. Slack has some amazing features like workspace, channels, bots, webhooks and many more. Slack notification can be used for providing the feedback for development activities like static analysis, code issues, test reporting, and deployments. The most Continuous Integration Servers are adding the Slack integration to give updates on deployments pipelines. In the world of iOS, we can use Fastlane Slack action to report the status of the iOS development activities. Xcode Server is developed by Apple so there won’t be any inbuilt support unless there is business level communication but we can easily integrate the with Slack using the combination of Slack API and Xcode Server post-integration script.

Know XCS Environmental Variables

The first step in order to integrate the Slack with Xcode Server is to understand the Xcode Server environment variables that we can use in the script. There is the list of the environmental variables available to use for Xcode Server but we will see some of the useful ones that we need for Slack integration.

XCS_BOT _ NAME : This can be used anywhere in the script to get the current Xcode Bot name.

: This can be used anywhere in the script to get the current Xcode Bot name. XCS_INTEGRATION_RESULT : It provides the results of the integration.

: It provides the results of the integration. XCS_PRIMARY_REPO_DIR : This provides the source code of the integration from where we can extract information like Git last commit or authors.

: This provides the source code of the integration from where we can extract information like Git last commit or authors. XCS_PRIMARY_REPO_BRANCH : It provides the branch names of the current integration.

There are many other variables that you can benefit from but for now, we will use only mentioned above.

Prepare Slack for XCS Integration

Now that, we know the Xcode Server environmental variables to be used within our script. Let’s now prepare our Slack for the Xcode Server integrations. There are few things we need to do before we actually start writing the integration script.

Create Incoming WebHook

We need to create incoming webhook in the Slack which we can use to post the messages to the particular channel. There is a clear documentation on how to setup incoming webhook so there is no need to repeat here but we will see how it look like in the practice.

Visit the Incoming WebHook page and click on add configuration.

Now, select the channel your Incoming WebHook will post messages to in my case, I have selected #xcblog channel that I have created for demo purpose.

Click Add Incoming WebHooks Integration and Save Setting

Now that, we have a WebHook URL as shown above that we can use to post the message to the channel. Our Slack is now ready to accept messages from Xcode Server.

Explore Slack API

Now that, we have setup our incoming webhook, let’s send some test messages to the channel using the Slack API for the incoming WebHooks. you can find comprehensive documentation on a Slack official page here how to send the simple to rich text messages using Slack API. In summary, we can use JSON payload to post sample message to Slack using WebHook

$ curl -X POST \ -H 'Content-type: application/json' \ --data '{"text": "This is posted to #xcblog and comes from *Xcode-bot*.", "channel": "#xcblog", "link_names": 1, "username": "xcode-bot", "icon_emoji": ":robot_face:"}' \ https://hooks.slack.com/services/your_incoming_webhook_url 1 2 3 4 $ curl - X POST \ - H 'Content-type: application/json' \ -- data '{"text": "This is posted to #xcblog and comes from *Xcode-bot*.", "channel": "#xcblog", "link_names": 1, "username": "xcode-bot", "icon_emoji": ":robot_face:"}' \ https : / / hooks .slack .com / services / your_incoming_webhook_url

This will post sample message which will look like this on the channel.

This works but we are not that boring. Let’s make it more interactive and give more information to users.

Use Slack Attachments

Slack attachments can be used to add extra information and more context to the messages. With the use of Attachments, message become more attractive, useful and informative. We can use attachments to create following things

Title and Links

Multiple fields

Different color

pretext, author etc

There is more information about attachments on the Slack official website here, please feel free to have a look to know more about Slack attachments. We can use attachments to post the interactive and rich message from Xcode Server.

Add Post-Integration Script to XCS Bot

We have just finished Slack setup, it’s time to write a script that can be triggered after the Xcode Server finishes Xcode Bot Integration.

Configure Message Content

We would like to see an attractive message when Xcode Server finishes the integration. Let start to think of content that we want to post on the Slack.

Determine Slack attachments colour depending on Xcode Bot integration result

Get the latest git message

Check if product is archived and provide link to download build on iOS devices if archived

Provide test summary e.g error count an warning count

This is the small list but you can go beyond this and configure more things in the Slack attachments. We can easily create bash script by using the Xcode Server environment variables and Slack API to satisfy above requirements. The Script will look like this:

#!/bin/sh env COLOUR='good' if [ $XCS_INTEGRATION_RESULT == 'warnings' ] || [ $XCS_INTEGRATION_RESULT == 'analyzer-warnings' ]; then COLOUR='warning' elif [ $XCS_INTEGRATION_RESULT != 'test-failures' ] || [ $XCS_INTEGRATION_RESULT != 'build-errors' ]; then COLOUR='danger' elif [ $XCS_INTEGRATION_RESULT != 'succeeded' ]; then COLOUR='good' fi LATESTMERGE="$(cd $XCS_PRIMARY_REPO_DIR && git log -1)" INSTALLABLE="https://my_xcode_server_hostname/xcode/bots/latest/${XCS_INTEGRATION_TINY_ID}" if [ -z "$XCS_PRODUCT" ]; then INSTALLABLE="This is test Integration. Nothing to download on iOS Devices" else INSTALLABLE="https://my_xcode_server_hostname/xcode/bots/latest/${XCS_INTEGRATION_TINY_ID}" fi PAYLOAD=$(cat << EOF { "attachments": [ { "fallback": "Xcode Server : '$XCS_BOT_NAME'.", "pretext": "Xcode Server has finished integration #$XCS_INTEGRATION_NUMBER for bot $XCS_BOT_NAME' with result $XCS_INTEGRATION_RESULT ", "color": "$COLOUR", "title": ":: Xcode Server Bot '$XCS_BOT_NAME' Integration: #$XCS_INTEGRATION_NUMBER.", "text": "$XCS_TESTS_COUNT tests with $XCS_TEST_FAILURE_COUNT failures.", "fields": [ { "title": "Test Summary", "value": "$XCS_ERROR_COUNT errors, and $XCS_WARNING_COUNT warnings.", "short": false }, { "title": ": Bot Result", "value": "$XCS_INTEGRATION_RESULT", "short": true }, { "title": "Install Build on iOS Devices", "value": "$INSTALLABLE", "short": false }, { "title": "Git Branch", "value": "$XCS_PRIMARY_REPO_BRANCH", "short": true }, { "title": "Latest Merge Details", "value": "$LATESTMERGE", "short": false } ] } ], "channel": "#xcblog", "icon_emoji": ":robot_face: ", "username": "Xcode Server: " } EOF) curl -X POST --data-urlencode "payload=${PAYLOAD}" https://hooks.slack.com/services/T8your_incoming_webhook_url/ echo "Done" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #!/bin/sh env COLOUR = 'good' if [ $XCS_INTEGRATION_RESULT == 'warnings' ] || [ $XCS_INTEGRATION_RESULT == 'analyzer-warnings' ] ; then COLOUR = 'warning' elif [ $XCS_INTEGRATION_RESULT != 'test-failures' ] || [ $XCS_INTEGRATION_RESULT != 'build-errors' ] ; then COLOUR = 'danger' elif [ $XCS_INTEGRATION_RESULT != 'succeeded' ] ; then COLOUR = 'good' fi LATESTMERGE = "$(cd $XCS_PRIMARY_REPO_DIR && git log -1)" INSTALLABLE = "https://my_xcode_server_hostname/xcode/bots/latest/${XCS_INTEGRATION_TINY_ID}" if [ - z "$XCS_PRODUCT" ] ; then INSTALLABLE = "This is test Integration. Nothing to download on iOS Devices" else INSTALLABLE = "https://my_xcode_server_hostname/xcode/bots/latest/${XCS_INTEGRATION_TINY_ID}" fi PAYLOAD = $ ( cat << EOF { "attachments" : [ { "fallback" : "Xcode Server : '$XCS_BOT_NAME'." , "pretext" : "Xcode Server has finished integration #$XCS_INTEGRATION_NUMBER for bot $XCS_BOT_NAME' with result $XCS_INTEGRATION_RESULT " , "color" : "$COLOUR" , "title" : ":: Xcode Server Bot '$XCS_BOT_NAME' Integration: #$XCS_INTEGRATION_NUMBER." , "text" : "$XCS_TESTS_COUNT tests with $XCS_TEST_FAILURE_COUNT failures." , "fields" : [ { "title" : "Test Summary" , "value" : "$XCS_ERROR_COUNT errors, and $XCS_WARNING_COUNT warnings." , "short" : false } , { "title" : ": Bot Result" , "value" : "$XCS_INTEGRATION_RESULT" , "short" : true } , { "title" : "Install Build on iOS Devices" , "value" : "$INSTALLABLE" , "short" : false } , { "title" : "Git Branch" , "value" : "$XCS_PRIMARY_REPO_BRANCH" , "short" : true } , { "title" : "Latest Merge Details" , "value" : "$LATESTMERGE" , "short" : false } ] } ] , "channel" : "#xcblog" , "icon_emoji" : ":robot_face: " , "username" : "Xcode Server: " } EOF ) curl - X POST -- data - urlencode "payload=${PAYLOAD}" https : / / hooks .slack .com / services / T8your_incoming_webhook_url / echo "Done"

Replace the value of variables for Xcode Server Url, Slack Channel and incoming WebHook with your details. Now that, we have a script ready and we can execute this script as part of Xcode Bot post-integration triggers while creating or editing the bots.

That’s it! We have now successfully configured Xcode Server Bots with Slack. Let’s trigger integration and watch the results in the slack channel. The end result will look like this:

You can see that we have loads of information posted on the Slack for the Xcode Server integration. It looks simply amazing!

Celebrate iOS Deployments on Slack

We have just seen an example of the test integration where we are just running the test and posting messages. When we do deployments to iTunes Connects we can create more creative messages and celebrate the success!

Watch Live Action

Watch the recorded live action of Slack and Xcode Server.

Using Fastlane Slack Action

We can achieve the same results using the Fastlane Slack Action. There is example code on the page to configure the attachments properties and JSON payload. If you are currently using Fastlane then it would be a good idea to configure a lane with Fastlane and execute it as part of the post-integration action. In our case, we can configure slack action

slack( message: "Xcode Server finished integration!", channel: "#xcblog", success: true, payload: { "Build Date" => Time.new.to_s, "Built by" => "Xcode Server", }, default_payloads: [:git_branch, :git_author], attachment_properties: { fields: [ { "title": "Test Summary", "value": "$XCS_ERROR_COUNT errors, and $XCS_WARNING_COUNT warnings.", "short": false }, { "title": ": Bot Result", "value": "$XCS_INTEGRATION_RESULT", "short": true }, { "title": "Install Build on iOS Devices", "value": "$INSTALLABLE", "short": false }, { "title": "Git Branch", "value": "$XCS_PRIMARY_REPO_BRANCH", "short": true }, { "title": "Latest Merge Details", "value": "$LATESTMERGE", "short": false } ] } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 slack ( message : "Xcode Server finished integration!" , channel : "#xcblog" , success : true , payload : { "Build Date" = > Time . new . to_s , "Built by" = > "Xcode Server" , } , default_payloads : [ : git_branch , : git_author ] , attachment_properties : { fields : [ { "title" : "Test Summary" , "value" : "$XCS_ERROR_COUNT errors, and $XCS_WARNING_COUNT warnings." , "short" : false } , { "title" : ": Bot Result" , "value" : "$XCS_INTEGRATION_RESULT" , "short" : true } , { "title" : "Install Build on iOS Devices" , "value" : "$INSTALLABLE" , "short" : false } , { "title" : "Git Branch" , "value" : "$XCS_PRIMARY_REPO_BRANCH" , "short" : true } , { "title" : "Latest Merge Details" , "value" : "$LATESTMERGE" , "short" : false } ] } )

We have to define the Xcode Server variables in the lane and we could achieve same results.

Conclusion

Slack is being the great communication tool in the world of DevOps and Continuous Delivery. It can play the very important role in providing the faster feedback from Continuous Integration servers. We can apply the Slack integration to iOS Development world by configuring it with Apple’s own CI server. Hope you will find this post useful, I can’t wait to see all of you starts using Slack and Xcode Server combination to celebrate successes!