README.md 18.3 KB
Newer Older
1
# unity3d ci example
Gabriel Le Breton's avatar
Gabriel Le Breton committed
2

3
[![pipeline status](https://gitlab.com/gableroux/unity3d-gitlab-ci-example/badges/master/pipeline.svg)](https://gitlab.com/gableroux/unity3d-gitlab-ci-example/commits/master)
Gabriel Le Breton's avatar
Gabriel Le Breton committed
4
[![Build Status](https://travis-ci.com/GabLeRoux/unity3d-ci-example.svg?branch=master)](https://travis-ci.com/GabLeRoux/unity3d-ci-example)
5

6 7 8 9 10 11 12
This project is a PoC to **run unity3d tests and builds inside a CI** using **[gableroux/unity3d docker image](https://hub.docker.com/r/gableroux/unity3d/)**. It currently creates builds for Windows, Linux, MacOS and webgl. The webgl build is published by the CI to [gitlab-pages](https://about.gitlab.com/features/pages/) and [github-pages](https://pages.github.com/)! **You can try the built project on [the published gitlab-pages](https://gableroux.gitlab.io/unity3d-gitlab-ci-example/)**. 

_github-pages integration will be done in [GabLeRoux/unity3d-ci-example#4](https://github.com/GabLeRoux/unity3d-ci-example/issues/4)._

## Git remotes

This repository is hosted on multiple remotes to provide examples for [Gitlab-CI](https://about.gitlab.com/product/continuous-integration/), [Travis](https://travis-ci.org/) and [CircleCI](https://circleci.com/)
13 14 15 16 17 18

* [github](https://github.com/gableroux/unity3d-ci-example)
* [gitlab](https://gitlab.com/gableroux/unity3d-gitlab-ci-example)

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
19
## Table of Contents  *generated with [DocToc](https://github.com/thlorenz/doctoc)*
20 21 22

- [Getting started](#getting-started)
- [Points of interest](#points-of-interest)
23 24 25 26 27 28
    - [Build script](#build-script)
    - [CI Configuration](#ci-configuration)
        - [gitlab-ci](#gitlab-ci)
        - [WIP: CircleCI](#wip-circleci)
        - [Travis](#travis)
    - [Test files](#test-files)
29
- [How to activate](#how-to-activate)
30
    - [Unity Personal](#unity-personal)
31 32
        - [a. Using gitlab-ci](#a-using-gitlab-ci)
        - [b. Locally](#b-locally)
33 34 35 36
    - [Unity Plus/Pro](#unity-pluspro)
    - [Unity license per target](#unity-license-per-target)
        - [Note about components in recent images](#note-about-components-in-recent-images)
    - [Travis](#travis-1)
37
- [How to add build targets](#how-to-add-build-targets)
38 39 40
    - [gitlab-ci](#gitlab-ci-1)
    - [iOS support](#ios-support)
    - [Android support](#android-support)
41
- [How to run scripts manually](#how-to-run-scripts-manually)
42 43
    - [Test](#test)
    - [Build](#build)
44 45
- [About the example project](#about-the-example-project)
- [Get involved](#get-involved)
Gabriel Le Breton's avatar
Gabriel Le Breton committed
46
- [Shameless plug](#shameless-plug)
47 48 49 50 51 52 53 54 55
- [License](#license)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Getting started

If you don't have a Unity project yet:

1. Fork this project from github or gitlab
56 57 58
1. Update the readme and remove undesired CI configurations
1. Follow How to activate instructions
1. Configure your CI environment variables (once everything is set, you should only need `UNITY_LICENSE_CONTENT` in your project variables)
59 60 61

If you already have your own project:

62 63 64 65 66 67
1. Copy desired ci file (`.gitlab-ci.yml`, or `.travis.yml`, etc.)
1. Copy [`BuildScript.cs`](Assets/Scripts/Editor/BuildCommand.cs) (make sure you use the same path as original project, it must be in an `Editor` folder)
1. Copy [`ci` folder](ci)
1. Update the Unity version according to your project version in the CI file. All versions are available at [gableroux/unity3d docker image](https://hub.docker.com/r/gableroux/unity3d/)
1. Follow How to activate instructions
1. Configure your CI environment variables (once everything is set, you should only need `UNITY_LICENSE_CONTENT` in your project variables)
Gabriel Le Breton's avatar
Gabriel Le Breton committed
68

69
## Points of interest
Gabriel Le Breton's avatar
Gabriel Le Breton committed
70

71
This is probably what you're looking for.
Gabriel Le Breton's avatar
Gabriel Le Breton committed
72

73
### Build script
Gabriel Le Breton's avatar
Gabriel Le Breton committed
74

75
Script passed to the unity3d command line as argument to create builds
Gabriel Le Breton's avatar
Gabriel Le Breton committed
76

77
* See [`BuildScript.cs`](Assets/Scripts/Editor/BuildCommand.cs)
Gabriel Le Breton's avatar
Gabriel Le Breton committed
78

79 80
You need to have this file in your project in order to build your project in the CI.

81
### CI Configuration
Gabriel Le Breton's avatar
Gabriel Le Breton committed
82

83
Pick one, if you're on gitlab, use gitlab-ci as Travis and CircleCI don't support Gitlab as of september 2018, if you're on github, Travis is more popular but CircleCI and [gitlab-ci will also work](https://about.gitlab.com/features/github/). If you can't decide, see [CircleCI vs. GitLab CI/CD](https://about.gitlab.com/comparison/gitlab-vs-circleci.html) and [Travis CI vs GitLab](https://about.gitlab.com/comparison/travis-ci-vs-gitlab.html).
Gabriel Le Breton's avatar
Gabriel Le Breton committed
84

85 86
You need to have one of these files in your project in order to build your project to actually use your CI.

87
#### gitlab-ci
Gabriel Le Breton's avatar
Gabriel Le Breton committed
88

89
* [`.gitlab-ci.yml`](.gitlab-ci.yml)
90

91 92 93 94 95
Note: you can add BuildOptions per target by adding environment variable `BuildOptions`.

```
build-ios:
  <<: *build
96
  image: gableroux/unity3d:2019.2.11f1-android
97 98 99 100 101 102 103 104 105 106 107 108
  variables:
    BUILD_TARGET: iOS
	BuildOptions: AcceptExternalModificationsToPlayer
```

If you would like to use several BuildOptions, you have to separate all values by `,` :  
```	
	BuildOptions: AcceptExternalModificationsToPlayer,CompressTextures,ConnectToHost
```

See [HERE](https://docs.unity3d.com/ScriptReference/BuildOptions.html) for BuildOptions values.

Gabriel Le Breton's avatar
Gabriel Le Breton committed
109 110 111
#### WIP: CircleCI

**TODO**
112

113
* [`.circleci/config.yml`](.circleci/config.yml)
114

115
#### Travis
116

117 118 119 120 121 122
* [`.travis.yml`](.travis.yml)

### Test files

* [`editmode` tests in `Assets/Scripts/Editor/EditModeTests`](Assets/Scripts/Editor/EditModeTests)
* [`playmode` tests in `Assets/Tests/`](Assets/Tests/)
Gabriel Le Breton's avatar
Gabriel Le Breton committed
123

124 125
## How to activate

126
There are a few methods available, if you're using gitlab-ci, the easiest method in the current documentation is using gitlab-ci.
127

128 129
### Unity Personal

130 131 132 133 134 135 136 137 138 139 140 141 142
#### a. Using gitlab-ci

Once you've added all required files to your project (mainly `.gitlab-ci.yml`), there should be a manual step that can be triggered for activation. 

1. Visit your project's settings > CI/CD > Variables and add `UNITY_USERNAME` and `UNITY_PASSWORD` with your credentials
1. Push your first commit to your project and visit CI/CD Pipelines.
1. Locate your latest job, there should be a `play` button, click on it and click `get-activation-file`
1. Wait for the job to run and follow instructions in the console 

#### b. Locally

All you need is [docker](https://www.docker.com/) installed on your machine.

143 144 145
1. Clone this project
2. Pull the docker image and run bash inside, passing unity username and password to env

146
    _hint: you should write this to a shell script and execute the shell script so you don't have your credentials stored in your bash history_. Also make sure you use your Unity3d _email address_ for `UNITY_USERNAME` env var.
147 148

    ```bash
149
    UNITY_VERSION=2019.2.11f1
150 151 152 153 154 155
    docker run -it --rm \
    -e "[email protected]" \
    -e "UNITY_PASSWORD=example_password" \
    -e "TEST_PLATFORM=linux" \
    -e "WORKDIR=/root/project" \
    -v "$(pwd):/root/project" \
156
    gableroux/unity3d:$UNITY_VERSION \
157 158
    bash
    ```
159 160 161 162 163 164 165 166
    
    If your password contains a `!`, you can escape it like this (`example_pass!word`):
    
 ```bash
 ...
 -e "UNITY_PASSWORD=example_pass"'!'"word" \
 ...
 ```   
167 168 169 170 171
3. In Unity docker container's bash, run once like this, it will try to activate

    ```bash
    xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
    /opt/Unity/Editor/Unity \
172
    -logFile /dev/stdout \
173 174 175 176 177 178 179 180 181
    -batchmode \
    -username "$UNITY_USERNAME" -password "$UNITY_PASSWORD"
    ```

4. Wait for output that looks like this:

    ```
    LICENSE SYSTEM [2017723 8:6:38] Posting <?xml version="1.0" encoding="UTF-8"?><root><SystemInfo><IsoCode>en</IsoCode><UserName>[...]
    ```
182 183 184 185 186
    If you get the following error:
    
    > Can't activate unity: No sufficient permissions while processing request HTTP error code 401
    
    Make sure your credentials are valid. You may try to disable 2FA in your account and try again. Once done, you should enable 2FA again for security reasons. See [#11](https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/11) for more details.
187 188

5. Copy xml content and save as `unity3d.alf`
189
6. Open https://license.unity3d.com/manual and answer questions
190
7. Upload `unity3d.alf` for manual activation
191
8. Download `Unity_v2018.x.ulf` (`Unity_v2019.x.ulf` for 2019 versions)
192
9. Copy the content of `Unity_v2018.x.ulf` license file to your CI's environment variable `UNITY_LICENSE_CONTENT`.
193
   _Note: if you are doing this on windows, chances are the [line endings will be wrong as explained here](https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/5#note_95831816). Luckily for you, [`.gitlab-ci.yml`](.gitlab-ci.yml) solves this by removing `\r` character from the env variable so you'll be alright_
194 195
[`.gitlab-ci.yml`](.gitlab-ci.yml) will then place the `UNITY_LICENSE_CONTENT` to the right place before running tests or creating the builds.

196 197 198 199 200 201 202 203
### Unity Plus/Pro

1. Clone this project
2. Pull the docker image and run bash inside, passing unity username and password to env

    _hint: you should write this to a shell script and execute the shell script so you don't have your credentials stored in your bash history_. Also make sure you use your Unity3d _email address_ for `UNITY_USERNAME` env var.

    ```bash
204
    UNITY_VERSION=2019.2.11f1
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
    docker run -it --rm \
    -e "[email protected]" \
    -e "UNITY_PASSWORD=example_password" \
    -e "UNITY_SERIAL=AN-EXAM-PLE-SERIA-LKEY-1234" \
    -e "TEST_PLATFORM=linux" \
    -e "WORKDIR=/root/project" \
    -v "$(pwd):/root/project" \
    gableroux/unity3d:$UNITY_VERSION \
    bash
    ```
3. In Unity docker container's bash, run once like this, it will try to activate

    ```bash
    xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
    /opt/Unity/Editor/Unity \
    -logFile /dev/stdout \
    -batchmode \
    -username "$UNITY_USERNAME" -password "$UNITY_PASSWORD" -serial "$UNITY_SERIAL"
    ```
4. Wait for the command to finish without errors
5. Obtain the contents of the license file by running `cat /root/.local/share/unity3d/Unity/Unity_lic.ulf`
5. Copy the content to your CI's environment variable `UNITY_LICENSE_CONTENT`.
   _Note: if you are doing this on windows, chances are the [line endings will be wrong as explained here](https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/5#note_95831816). Luckily for you, [`.gitlab-ci.yml`](.gitlab-ci.yml) solves this by removing `\r` character from the env variable so you'll be alright_
228 229
[`.gitlab-ci.yml`](.gitlab-ci.yml) will then place the `UNITY_LICENSE_CONTENT` to the right place before running tests or creating the builds.

230 231 232 233 234 235 236 237
### Unity license per target

Before `2018.4.8f1` for 2018 versions and before `2019.2.4f1` for 2019 versions, if you need a specific Unity license for a build target, you can add environment var `UNITY_LICENSE_CONTENT_{BUILD_TARGET}`. (`UNITY_LICENSE_CONTENT_ANDROID`, `UNITY_LICENSE_CONTENT_IOS`, ...). _This is not required anymore now that images share a base image [See related change](https://gitlab.com/gableroux/unity3d/merge_requests/63)**

#### Note about components in recent images

Starting from these versions, base image doesn't include windows, mac and webgl components anymore. This means you must use `-mac`, `-windows` or `-webgl` images. [See related change](https://gitlab.com/gableroux/unity3d/merge_requests/63)

238 239
### Travis

240
Travis doesn't support multiple-lines env variable out of the box and I had troubles with escaping so I recommend encrypting the license file. `.travis.yml` will decrypt the file and add its content to `UNITY_LICENSE_CONTENT` env var itself afterward.
241 242

```bash
Gabriel Le Breton's avatar
Gabriel Le Breton committed
243
travis encrypt-file --pro -r YOUR_TRAVIS_USERNAME/YOUR_TRAVIS_REPO_NAME ./Unity_v2018.x.ulf # TODO confirm new file name for 2019
244 245
```

246 247 248 249 250
For the record, the message I was getting:

> The previous command failed, possibly due to a malformed secure environment variable.
>  Please be sure to escape special characters such as ' ' and '$'.
>  For more information, see https://docs.travis-ci.com/user/encryption-keys.
251

252 253
## How to add build targets

254 255 256 257
Supported build targets can be found [here](https://docs.unity3d.com/ScriptReference/BuildTarget.html)

### gitlab-ci

258 259 260 261 262 263 264 265 266
Update [`.gitlab-ci.yml`](.gitlab-ci.yml) by adding a build section like this:

```yaml
build-StandaloneWindows64:
  <<: *build
  variables:
    BUILD_TARGET: StandaloneWindows64
```

267
### iOS support
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
#### Setup (only one time per mac)
Install the latest Xcode command line tools :
```
xcode-select --install
```
Install fastlane using : 
```
# Using RubyGems
sudo gem install fastlane -NV

# Alternatively using Homebrew
brew install fastlane
```

#### Unity Settings:
Switch target to iOS, then, in PlayerSettings -> Other Settings, 
- Fill the field `Signing Team ID` 
- Ensure `Automatically Sign` is unchecked
- iOS Provisioning Profile  
---- `ProfileID` : `match AppStore yourBundleIdentifier` < yourBundleIdentifier to replace by yours.  
---- `ProfileType` : `Distribution`

#### XCode project: 
Make a first iOS build using your mac from Unity, that will create an xcode project.  
Ensure your target the same path than the ci.  
Ex : if you let `BUILD_NAME: ExampleProjectName` in `.gitlab-ci.yml`, your xcode project must be at the root of the following path : `.\Builds\iOS\ExampleProjectName\`

#### App on portail:
Make sure that you have setup your app on the Apple Developer Portal and the App Store Connect or use [fastlane produce](https://docs.fastlane.tools/actions/produce/) to create it.

#### Fastlane initialization: 
Open the terminal at the same path then run `fastlane init`, follow instructions to generate Appfile and default Fastfile.

#### Provisioning profile:
Run `fastlane match init`, follow instructions, select `appstore` provisioning profile type. ([Documentation](https://docs.fastlane.tools/actions/match/))

#### Make lane:
Copy the following instructions on your Fastfile:
```
default_platform(:ios)

platform :ios do
  desc "Push a new beta build to TestFlight"
  lane :beta do
    sync_code_signing(type:"appstore", readonly: is_ci)
    increment_build_number({
        build_number: latest_testflight_build_number + 1
    })
    build_app(scheme:"Unity-iPhone")
    upload_to_testflight(groups:["Team"]) 
  end
end
```
Note about `upload_to_testflight` : Change "Team" to your internal tester or remove (groups:["Team"]) if you want set manually who can test the build  
Docs:   
[sync_code_signing (alias for match)](https://docs.fastlane.tools/actions/sync_code_signing/)  
[increment_build_number](https://docs.fastlane.tools/actions/increment_build_number/)  
[build_app (alias for gym)](https://docs.fastlane.tools/actions/build_app/)  
[upload_to_testflight (alias for pilot)](https://docs.fastlane.tools/actions/testflight/)
327

328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368

#### Local test:
Run `fastlane ios beta` to test the build and the deployement localy.  
If the build and upload are ok, you have to force add some file to your git using command below   
```
git add -f pathToTheFileToAdd
```
you have to add those following files :
- `Gemfile`, 
- `Gemfile.lock` (if here), 
- `fastlane/Appfile`, 
- `fastlane/Fastfile`, 
- `fastlane/Matchfile`

#### Gitlab-runner : register your mac :
To automate your build with gitlab, you need to setup your mac as a gitlab runner.  
Installation : 
```
sudo curl --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64
```
Give permission to execute : 
```
sudo chmod +x /usr/local/bin/gitlab-runner
```
[Source (if you would like to check)](https://docs.gitlab.com/runner/install/osx.html)

Go to your project gitlab page, then go to `settings` -> `CI/CD` -> `Runners` -> `Specitic Runners` -> `Set up a specific Runner manually` -> take note of the token 

Follow instructions on this [LINK](https://docs.gitlab.com/runner/register/index.html) to register your mac as a gitlab-runner for your specific project.  
Follow **macOS** instructions **without** sudo command for registration.

Tags : set `mac,ios`  
Executor : set `shell`

Then, to install/launch the runner : 
```
cd ~ 
gitlab-runner install
gitlab-runner start
```
Runner is installed and will be run after a system reboot.
369 370 371

### Android support

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
To make build working with Android, you will need a specific Unity license (because that is not the same docker image).  
Add the content of your specific Unity license in your CI's environment variable : `UNITY_LICENSE_CONTENT_ANDROID`

By default the apk is not signed and the build will use the Unity's default debug key.  
For security reason, you must not add your keystore to git.  
Encode your keystore file as base64 using openssl:  
`openssl base64 -A -in yourKeystore.keystore`

Copy the result to your CI's environment variable `ANDROID_KEYSTORE_BASE64`

Add following environment variables:  
- `KEYSTORE_PASS` : Keystore pass  
- `KEY_ALIAS_NAME` : Keystore alias name to use (if not set, the program will use the alias name set in Project's PlayerSettings)  
- `KEY_ALIAS_PASS` : Keystore alias pass to use

Note about keystore security, if you would like to use another solution, see [HERE](https://android.jlelse.eu/where-to-store-android-keystore-file-in-ci-cd-cycle-2365f4e02e57)
388

389
## How to run scripts manually
390

391 392 393 394 395
You can execute the local scripts and specify the path of your Unity executable using `UNITY_EXECUTABLE`. You may try this in your project before you setup the whole CI so you confirm it works with your current unity version :+1:

### Test

```bash
396
UNITY_EXECUTABLE="/Applications/Unity/Hub/Editor/2019.2.11f1/Unity.app/Contents/MacOS/Unity" \
397 398 399 400
  ./local_test.sh
```

### Build
401 402

```bash
403
UNITY_EXECUTABLE="/Applications/Unity/Hub/Editor/2019.2.11f1/Unity.app/Contents/MacOS/Unity" \
404
  ./local_build.sh
405
```
406

407 408
## About the example project

409
This is an updated version of the [Unity's Creator Kit: RPG free asset](https://assetstore.unity.com/packages/templates/tutorials/creator-kit-rpg-149309) which is not affiliated with this project at all. Feel free to explore it, dialogs are updated ;)
410 411 412 413 414

## Get involved

There is a discord `#technical-english` channel at [totema.studio/discord](https://totema.studio/discord). Feel free to join in! I will be looking for maintainers as this project is getting more and more attention :tada:.

415 416
## Shameless plug

417
I made this for free as a gift to the video game community so if this tool helped you and you would like to support me, send your love to [Totema Studio](https://totemastudio.com) on Patreon: :beers:
418 419 420 421 422

[![Totema Studio Logo](./doc/totema-studio-logo-217.png)](https://patreon.com/totemastudio)

[![Become a Patron](./doc/become_a_patron_button.png)](https://www.patreon.com/bePatron?c=1073078)

Gabriel Le Breton's avatar
Gabriel Le Breton committed
423 424 425
## License

[MIT](LICENSE.md) © [Gabriel Le Breton](https://gableroux.com)
426