Handling Carthage Updates

Rajat Vig
3 min readOct 17, 2016

We did get around to automatically handling updates which I have detailed a little below. Though you’re right, the way that post talked about that was manual and pretty much intended that way. If the developer updating the Cartfile.resolved did not commit the archived frameworks, the build may be broken or built with older versions.

Post writing that post and struggling with getting Git LFS to work on Jenkins (I’m stuck with Jenkins and Git LFS didn’t work on Jenkins for me), we’ve now settled on a different approach which takes care of the concern while still keeping almost complete control on how it’ll be done in the code base itself.

The approach we took was not to keep the archives in the repository but instead rely on an rsync or HTTP Server (we used Artifactory) and have the CI update the remote server if it detected any changes in the Cartfile.resovled.

Here’s the changed make targets

FRAMEWORKS_FOLDER=Carthage/PreBuiltFrameworksARTIFACTORY_GLOBAL_OPTIONS=--url $(ARTIFACTORY_URI) --user "$(ARTIFACTORY_USER)" --password "$(ARTIFACTORY_PASSWORD)"ARTIFACTORY_FOLDER=carthage-archivesCARTFILE_CHANGED=`git diff --stat $(GIT_PREVIOUS_COMMIT) $(GIT_COMMIT) | grep '\|' | awk '{print $$1}' | grep Cartfile.resolved`CARTHAGE_FRAMEWORKS=ls Carthage/Build/iOS/*.framework | grep "\.framework" | cut -d "/" -f 4 | cut -d "." -f 1 | xargs -I '{}'CARTHAGE_ARCHIVES=ls $(FRAMEWORKS_FOLDER)/*.zip | grep "\.zip" | cut -d "/" -f 3 | cut -d "." -f 1 | xargs -I '{}'clean: ## clean carthage
rm -rf Carthage
mkdir -p $(FRAMEWORKS_FOLDER)
carthage_bootstrap: ## bootstrap carthage frameworks
carthage bootstrap --platform iOS --no-use-binaries
carthage_update: clean ## update carthage packages
carthage update --platform iOS --no-use-binaries
carthage_archive: carthage_update ## update and archive carthage packages
$(CARTHAGE_FRAMEWORKS) carthage archive '{}' --output $(FRAMEWORKS_FOLDER)/
carthage_upload: ## upload carthage frameworks to artifactory
if test "$(CARTFILE_CHANGED)" ; then \
make carthage_archive carthage_upload_private ; \
fi;
carthage_upload_private:
jfrog rt upload $(ARTIFACTORY_GLOBAL_OPTIONS) "$(FRAMEWORKS_FOLDER)/*.zip" $(ARTIFACTORY_FOLDER)
carthage_extract: ## extract from carthage archives
$(CARTHAGE_ARCHIVES) unzip $(FRAMEWORKS_FOLDER)/'{}'.framework.zip
carthage_fetch: clean ## fetch carthage frameworks from artifactory
jfrog rt download $(ARTIFACTORY_GLOBAL_OPTIONS) $(ARTIFACTORY_FOLDER) $(FRAMEWORKS_FOLDER)/
install: ## install gems, fetch prebuilt carthage frameworks
bundle install
make carthage_fetch carthage_extract
test: ## run unit tests
$(FASTLANE) test

The trick is using Jenkins provided environment variables of to determine if the Cartfile.resovled has changed between the last and current commit SHA.

As I said before, we used JFrog Artifactory as it already existed and jfrog-cli-go is the command line we used to upload. The artifactory related parameters are stored securely with the CI job and stored by the developer in a .envrc loaded by direnv.

The CI configuration is now multiple steps

# clean up
make clean
# determine and upload if required
make carthage_upload
# install and run tests
make install test

This approach works out though there are some caveats, notably…

  1. There’s no versioning in place. Artifactory is storing the zip files as is with no version identifier. I’m thinking on how to best go about doing that but it is not of high concern.
  2. It assumes that dependencies are not removed, mostly added. The fetch target gets all the archives and extracts them. While that in itself isn’t wrong, keeping archives no longer required is not correct. Planning to work on a sync target soon and maybe resolve the versioning issue with it.

In any case, the artifactory driven upload/fetch workflow is more relevant for larger teams and it does cause variance in build times. For developers doing OSS Frameworks, Git LFS with manual uploads is possibly the only way.

Lastly, thanks for the response. I was going to update the post to reflect the changes done since and your reply just spurred me to do it. If I do get around to writing those sync + versioning targets, will update.

--

--

Rajat Vig

developer, reader, ex-Thoughtworks, staff engineer @etsy