├── .gitignore ├── README.md ├── Vagrantfile └── scripts └── start-simulator.sh /.gitignore: -------------------------------------------------------------------------------- 1 | /.vagrant -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Xcode GitLab runner 2 | 3 | A Vagrantfile to build a fully functional macOS / Xcode GitLab runner 4 | 5 | ## TL;DR 6 | 7 | ### Build and run the runner 8 | Once VirtualBox and Vagrant are installed, use the following command to build and run the box : 9 | 10 | XCODE_XIP_FILE="/path-to-Xcode.xip" \ 11 | GITLAB_URL="https://gitlab.com/" \ 12 | GITLAB_REGISTRATION_TOKEN="your-token" \ 13 | GITLAB_RUNNER_NAME="macMachine" \ 14 | GITLAB_RUNNER_TAGS="macos,xcode11" \ 15 | vagrant up 16 | 17 | Note that an Xcode .xip install archive is required to perform Xcode installation. 18 | 19 | ### Test and anlayse a project 20 | Add and configure a sonar-project.properties as explained [here](https://github.com/Backelite/sonar-swift) 21 | 22 | Then use the following **.gitlab-ci.yml** file to perform a code analysis (and publication to SonarQube): 23 | 24 | analyse: 25 | tags: 26 | - xcode11 27 | script: 28 | - pod install 29 | - start-simulator.sh "iPhone 11 Pro" 30 | - run-sonar-swift.sh -sonarurl=$SONAR_URL -sonarlogin=$SONAR_TOKEN 31 | 32 | **start-simulator.sh** pre-launches the simulator for tests. Be careful to use the same simulator as the one defined in you **sonar-project.properties**. 33 | 34 | **run-sonar-swift.sh** builds, tests, analyses and publishes results to a SonarQube server. **SONAR_URL** and **SONAR_TOKEN** are defined as GitLab CI/CD variables. 35 | 36 | ## What's in the box ? 37 | 38 | Here is a list of tools included in the box : 39 | - Xcode 40 | - fastlane 41 | - flutter 42 | - sonar-swift 43 | - sonar-scanner 44 | - xcpretty 45 | - gcovr 46 | - CocoaPods 47 | - Carthage 48 | - XCode 49 | - slather 50 | - OCLint 51 | - SwiftLint 52 | - applesimutils 53 | 54 | ## Prerequisites 55 | 56 | ### VirtualBox 57 | 58 | A recent version of VirtualBox and extension pack is required to run the generated virtual machine. 59 | 60 | VirtualBox can be downloaded from [here](https://www.virtualbox.org/). 61 | 62 | Or installed using [Homebrew](https://brew.sh/): 63 | 64 | brew cask install virtualbox 65 | brew cask install virtualbox-extension-pack 66 | 67 | ### Vagrant 68 | 69 | Vagrant and its reload plugin are required to run the Vagrantfile. 70 | 71 | It can be installed using [Homebrew](https://brew.sh/): 72 | 73 | brew cask install vagrant 74 | vagrant plugin install vagrant-reload 75 | 76 | ### Xcode .xip file 77 | 78 | A Xcode .xip install archive is required to build the box. 79 | 80 | It can be downloaded from [here](https://developer.apple.com/download/more/) (Apple ID required). 81 | 82 | ## Parameters 83 | 84 | Parameters are set as environmeent variables when running "vagrant up" command: 85 | 86 | PARAM1="stringvalue" PARAM2=numbervalue ... vagrant up 87 | 88 | Here is a list of available parameters 89 | 90 | | Parameter | Default value | 91 | |---------------------------|:--------------------:| 92 | | XCODE_XIP_FILE | none (manadatory) | 93 | | GITLAB_URL | https://gitlab.com/ | 94 | | GITLAB_REGISTRATION_TOKEN | none (mandatory) | 95 | | GITLAB_RUNNER_NAME | none (mandatory) | 96 | | GITLAB_RUNNER_TAGS | none (mandatory) | 97 | | CPU_COUNT | 2 | 98 | | RAM_SIZE | 4096 | 99 | 100 | ## Reminder : OS X Licensing 101 | Apple's EULA states that you can install your copy on your actual Apple-hardware, plus up to two VMs running on your Apple-hardware. So using this box on another hardware is may be illegal and you should do it on your own risk. 102 | 103 | By using it you agree with all macOS Sierra and XCode license agreements. 104 | 105 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | 9 | XCODE_XIP_FILE=ENV['XCODE_XIP_FILE'] 10 | GITLAB_URL=ENV['GITLAB_URL'] || "https://gitlab.com/" 11 | GITLAB_REGISTRATION_TOKEN=ENV['GITLAB_REGISTRATION_TOKEN'] 12 | GITLAB_RUNNER_NAME=ENV['GITLAB_RUNNER_NAME'] 13 | GITLAB_RUNNER_TAGS=ENV['GITLAB_RUNNER_TAGS'] 14 | CPU_COUNT=ENV['CPU_COUNT'] || 2 15 | RAM_SIZE=ENV['RAM_SIZE'] || 4096 16 | 17 | Vagrant.configure("2") do |config| 18 | 19 | # Get box 20 | config.vm.box = "leav3/macos_mojave" 21 | 22 | # Configuration 23 | config.vm.provider 'virtualbox' do |vb| 24 | vb.customize ["modifyvm", :id, "--ostype", "MacOS_64"] 25 | vb.customize ["modifyvm", :id, "--ioapic", "on"] 26 | vb.customize ["modifyvm", :id, "--nestedpaging", "off"] 27 | vb.gui = false 28 | vb.name = 'mojave-xcode' 29 | vb.cpus = "#{CPU_COUNT}" 30 | vb.memory = "#{RAM_SIZE}" 31 | config.vm.synced_folder ".", "/vagrant", disabled: true 32 | end 33 | 34 | # Set boot timeout to 600 seconds 35 | config.vm.boot_timeout = 600 36 | 37 | # Copy Xcode install package 38 | config.vm.provision "file", source: "#{XCODE_XIP_FILE}", destination: "/tmp/Xcode.xip" 39 | 40 | # Copy scripts 41 | config.vm.provision "file", source: "./scripts", destination: "/tmp/scripts" 42 | 43 | # Environment variables 44 | config.vm.provision "shell", privileged: true, name: 'environment variables', inline: <<-SHELL 45 | echo export BINARIES_DIRECTORY='/opt/local/bin' >> /etc/profile 46 | echo export BUILD_TOOLS_REPOSITORY=build-ios-simple-shell >> /etc/profile 47 | echo export USERNAME='vagrant' >> /etc/profile 48 | echo export LANG='en_US.UTF-8' >> /etc/profile 49 | echo export LANGUAGE='en_US.UTF-8' >> /etc/profile 50 | echo export LC_ALL='en_US.UTF-8' >> /etc/profile 51 | echo export 'PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin' >> /etc/profile 52 | SHELL 53 | 54 | # Disable sleep mode 55 | config.vm.provision "shell", privileged: false, name: 'disable sleep mode', inline: <<-SHELL 56 | sudo systemsetup -setcomputersleep Never 57 | SHELL 58 | 59 | # Developer mode activation 60 | config.vm.provision "shell", privileged: false, name: 'developer mode activation', inline: <<-SHELL 61 | sudo /usr/sbin/DevToolsSecurity -enable 62 | sudo /usr/sbin/dseditgroup -o edit -t group -a staff _developer 63 | SHELL 64 | 65 | # Install scripts 66 | config.vm.provision "shell", privileged: true, name: 'scripts', inline: <<-SHELL 67 | mkdir -p /usr/local/opt 68 | mv /tmp/scripts/ /usr/local/opt 69 | chmod +x /usr/local/opt/scripts/*.sh 70 | echo export PATH=/usr/local/opt/scripts:\$PATH >> /etc/profile 71 | SHELL 72 | 73 | # Install brew 74 | config.vm.provision "shell", privileged: false, name: 'homebrew with command line tools', inline: <<-SHELL 75 | /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 76 | SHELL 77 | 78 | # Install command line tools with brew 79 | config.vm.provision "shell", privileged: false, name: 'brew tools', inline: <<-SHELL 80 | /usr/local/bin/brew tap oclint/formulae 81 | /usr/local/bin/brew install xz ruby wget gcovr doxygen graphviz sonar-scanner carthage python@2 imagemagick ghostscript oclint 82 | SHELL 83 | 84 | # Install brew tools path 85 | config.vm.provision "shell", privileged: true, name: 'brew tools path', inline: <<-SHELL 86 | echo export PATH=/usr/local/opt/python@2/libexec/bin:\$PATH >> /etc/profile 87 | SHELL 88 | 89 | # Install Lizard 90 | config.vm.provision "shell", privileged: true, name: 'pip tools', inline: <<-SHELL 91 | pip install lizard 92 | SHELL 93 | 94 | # Install gem tools 95 | config.vm.provision "shell", privileged: false, name: 'gem tools', inline: <<-SHELL 96 | /usr/local/opt/ruby/bin/gem install xcpretty slather cocoapods jazzy 97 | /usr/local/opt/ruby/bin/gem install bundler --force 98 | /usr/local/opt/ruby/bin/gem install xcodeproj 99 | /usr/local/opt/ruby/bin/gem install fileutils 100 | sudo /usr/local/opt/ruby/bin/gem install fastlane -NV 101 | SHELL 102 | 103 | # Install gem tools path 104 | config.vm.provision "shell", privileged: true, name: 'gem tools path', inline: <<-SHELL 105 | GEM_TOOL_BIN_PATH=`/usr/local/opt/ruby/bin/gem environment | awk -F ' *: *' '$1 ~ /EXECUTABLE DIRECTORY/{print $2}'` 106 | echo export PATH=\$GEM_TOOL_BIN_PATH:\$PATH >> /etc/profile 107 | SHELL 108 | 109 | # sonar-swift script 110 | config.vm.provision "shell", privileged: true, name: 'sonar-swift script', env: {"SONAR_PUBLIC_REPOSITORY" => "sonar-swift"}, inline: <<-SHELL 111 | git clone -b master https://github.com/insideapp-oss/$SONAR_PUBLIC_REPOSITORY.git ~/$SONAR_PUBLIC_REPOSITORY 112 | cd ~/$SONAR_PUBLIC_REPOSITORY 113 | git checkout develop 114 | mv ~/$SONAR_PUBLIC_REPOSITORY/sonar-swift-plugin/src/main/shell/ /usr/local/opt/$SONAR_PUBLIC_REPOSITORY 115 | rm -rf ~/$SONAR_PUBLIC_REPOSITORY 116 | chmod +x /usr/local/opt/$SONAR_PUBLIC_REPOSITORY/run-sonar-swift.sh 117 | echo export PATH=/usr/local/opt/$SONAR_PUBLIC_REPOSITORY:\$PATH >> /etc/profile 118 | SHELL 119 | 120 | # Install java 121 | config.vm.provision "shell", privileged: false, name: 'java', inline: <<-SHELL 122 | /usr/local/bin/brew tap caskroom/versions 123 | /usr/local/bin/brew cask install java 124 | SHELL 125 | 126 | # Enable auto login 127 | config.vm.provision "shell", privileged: false, name: 'enable auto login', inline: <<-SHELL 128 | /usr/local/bin/brew tap xfreebird/utils 129 | /usr/local/bin/brew install kcpassword 130 | enable_autologin "${USERNAME}" "${USERNAME}" 131 | SHELL 132 | 133 | # Reboot (to enable auto login) 134 | #config.vm.provision :reload 135 | 136 | # Xcode 137 | config.vm.provision "shell", privileged: false, name: 'xcode installation', inline: <<-SHELL 138 | open -FWga "Archive Utility" --args /tmp/Xcode.xip 139 | # Move Xcode to Applications directory 140 | sudo mv ~/Downloads/Xcode.app /Applications/ 141 | # Clean Xcode installation file 142 | rm /tmp/Xcode.xip 143 | # Accept Xcode licence 144 | sudo xcode-select -s /Applications/Xcode.app/Contents/Developer 145 | sudo xcodebuild -license accept 146 | # Install XCode additional required components 147 | for pkg in /Applications/Xcode.app/Contents/Resources/Packages/*.pkg; do sudo installer -pkg "$pkg" -target /; done 148 | SHELL 149 | 150 | 151 | # Simulator tools (require Xcode to be installed) 152 | config.vm.provision "shell", privileged: false, name: 'ios simulator tools', inline: <<-SHELL 153 | /usr/local/bin/brew tap wix/brew 154 | /usr/local/bin/brew install applesimutils 155 | /usr/local/bin/brew tap facebook/fb 156 | SHELL 157 | 158 | # swiftlint (require Xcode to be installed) 159 | config.vm.provision "shell", privileged: false, name: 'swiftlint installation', inline: <<-SHELL 160 | /usr/local/bin/brew install swiftlint 161 | SHELL 162 | 163 | # flutter (require Xcode to be installed) 164 | config.vm.provision "shell", privileged: false, name: 'flutter installation', inline: <<-SHELL 165 | /usr/local/bin/brew tap MiderWong/flutter 166 | /usr/local/bin/brew install flutter 167 | SHELL 168 | 169 | # Cocoapods repository setup 170 | config.vm.provision "shell", privileged: false, name: 'pod repository setup', inline: <<-SHELL 171 | pod setup 172 | SHELL 173 | 174 | # GitLab runner install 175 | config.vm.provision "shell", privileged: false, name: 'gitlab-runner installation', inline: <<-SHELL 176 | /usr/local/bin/brew install gitlab-runner 177 | /usr/local/bin/brew services start gitlab-runner 178 | # Registration 179 | gitlab-runner register --non-interactive --url "#{GITLAB_URL}" --registration-token "#{GITLAB_REGISTRATION_TOKEN}" --executor "shell" --name "#{GITLAB_RUNNER_NAME}" --tag-list "#{GITLAB_RUNNER_TAGS}" 180 | SHELL 181 | 182 | # Reboot 183 | config.vm.provision :reload 184 | 185 | end 186 | -------------------------------------------------------------------------------- /scripts/start-simulator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script boots and starts an iOS simulator using its name as parameter 3 | # It requires applesimutils to be installed (https://github.com/wix/AppleSimulatorUtils) 4 | 5 | if [ $# -eq 0 ]; then 6 | echo "Usage $0 [name]" 7 | exit 1 8 | fi 9 | 10 | simulator_name=$1 11 | 12 | # Test is simulator is already booted 13 | booted_udid=$(applesimutils --byName "$simulator_name" --booted -l | awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'udid'\042/){print $(i+1)}}}' | tr -d '"' | sed -n 1p| tr -d '[:space:]') 14 | 15 | # If no : boot it 16 | if [ "$booted_udid" = "" ]; then 17 | udid=$(applesimutils --byName "$simulator_name" -l | awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'udid'\042/){print $(i+1)}}}' | tr -d '"' | sed -n 1p| tr -d '[:space:]') 18 | if [ "$udid" = "" ]; then 19 | # Device not found 20 | echo "No simulator with name \"$simulator_name\" found" 21 | exit 1 22 | fi 23 | xcrun simctl boot $udid 24 | fi 25 | 26 | # Then start it 27 | open /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app/ --------------------------------------------------------------------------------