Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cache issues when trying to build iOS apps with parallel Jenkins pipeline builds on a single Mac machine

I have a Jenkins pipeline job that builds iOS code, creates .app file and runs tests against it. these jobs are triggered by PRs in the iOS repository. At a time there can be around 4-5 parallel builds running.

Configuration of build machine:

  • 1 single mac machine with xcode and other dependencies installed on it
  • This mac machine is a Jenkins slave agent
  • When a build is triggered it creates a folder in workspace where the source repository is cloned for building.

For example

jenkins-workspace-folder-on-mac-machine/
-> build/ (folder created by a job that builds .app file for a PR)
-> build@2/ (another folder created by a parallel job that builds .app for a PR)
-> build@3/ (another folder created by a parallel job that builds .app for a PR)

This is my Jenkinsfile script for reference:

stages {

  stage('Clean Workspace') {
   steps {
    cleanWs deleteDirs: true, patterns: [[pattern: '**/Podfile.lock', type: 'EXCLUDE'], [pattern: '**/Pods/**', type: 'EXCLUDE'], [pattern: '**/Podfile', type: 'EXCLUDE'], [pattern: '**/Carthage/**', type: 'EXCLUDE'], [pattern: '**/Cartfile', type: 'EXCLUDE'], [pattern: '**/Cartfile.lock', type: 'EXCLUDE'], [pattern: '**/Cartfile.private', type: 'EXCLUDE'], [pattern: '**/Cartfile.resolved', type: 'EXCLUDE'], [pattern: '**/Gemfile', type: 'EXCLUDE'], [pattern: '**/Gemfile.lock', type: 'EXCLUDE']]
   }
  }

  /* Download and checkout iOS repository in the workplace.
  Also set all the keys for iOS into .env file */
  stage('Checkout iOS Source repository') {
      steps{
            checkout([$class: 'GitSCM', branches: [[name: "${PR_BRANCH}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'abc', url: 'https://github.com/abc']]])
        }
    }

  /* Install all dependencies. These will be skipped if repo folder is not cleaned in the beginning. 
  Full install will be done if an executor has to clone the repository from scratch*/
  stage('Install dependencies') {
    steps {
      sh '''
         bundle install
         make install
         '''
      }
  }

  stage('Build .app file and trigger tests') {
    steps {//This will perform xcode build and build .app file }

Issues I'm facing:

  • Builds are taking too long when I clean workspace every time before starting builds. I was expecting that if I clean workspace except the files and folders Podfile, Pod folder, podfile.lock, Carthage folder, Cartfile, Cartfile.private, Cartfile.resolved, Gemfile, Gemfile.lock this would speed up the build. But that's not working.
  • There are random build failures due to cache issues like:
*** Checking out Nimble at "v8.0.4"
A shell task (/usr/bin/env git checkout --quiet --force v8.0.4 (launched in /Users/user/Library/Caches/org.carthage.CarthageKit/dependencies/Nimble)) failed with exit code 1:
error: pathspec 'v8.0.4' did not match any file(s) known to git

make: *** [carthage-install] Error 1
### Error
Errno::ENOENT - No such file or directory @ rb_file_s_stat - /Users/user/Library/Caches/CocoaPods/Pods/Release/Flurry-iOS-SDK/8.4.0-0c448
bundle exec pod install
Analyzing dependencies
Pre-downloading: `CLImageEditor` from `[email protected]/CLImageEditor.git`, commit `96e78cdf95761170d5bf11653a8257a3ccfeb19a`
[!] Failed to download 'CLImageEditor': Directory not empty @ dir_s_rmdir - /Users/user/Library/Caches/CocoaPods/Pods
make: *** [pod-install] Error 1

It would be great if someone could help understand what I'm doing wrong here.

like image 525
Abhijeet Vaikar Avatar asked Sep 15 '25 10:09

Abhijeet Vaikar


1 Answers

I solved this problem by writing a script to manage cache of dependencies for cocoapods, gems and carthage based on different versions of Gemfile.lock, Podfile.lock & Cartfile.resolved.

Sample script in Jenkinsfile to manage cache

sh '''
      set +x
      mkdir -p ${HOME}/ioscache/pod
      # CocoaPods
      POD_SHASUM=$(shasum Podfile.lock | awk '{print $1}')
      POD_KEY="pod-${POD_SHASUM}"
      POD_CACHE_PATH="${HOME}/ioscache/pod/${POD_KEY}.tar.gz"

      echo "Checking cache for CocoaPods with they key: $POD_KEY"
      if [ ! -e "${POD_CACHE_PATH}" ]; then
        echo "CocoaPods cache not found with the key: $POD_KEY"
        POD_CACHE_FOUND=false
      else
        echo "CocoaPods cache found with the key: $POD_KEY"
        echo "restoring cache.."
        tar xf ${POD_CACHE_PATH}
        POD_CACHE_FOUND=true
      fi

      make pod-install
      if [ "$POD_CACHE_FOUND" = "false" ]; then
        echo "Saving cache for CocoaPods with key: $POD_KEY"
        tar cfz ${POD_CACHE_PATH} Pods/
        echo "Saved."
      fi
    '''

Repeat the same for Gemfile.lock and Cartfile.resolved.

like image 92
Abhijeet Vaikar Avatar answered Sep 18 '25 09:09

Abhijeet Vaikar