Xcode: increment build number per configuration

In your current Xcode project, you might have different configurations and certain configurations might have different product bundle identifier, say you have a product id for staging, another for production, and another for development.

When you push your build for TestFlight for instance you have to update the build number or the version, if you have another app for staging say com.myapp.com.staging and you use agvtool or fastlane action increment_build_number which uses agvtool , the new number will be set for the whole configurations and you will find that your staging or production builds in TestFlight have no clear convention.

we can use this script as a fastlane lane .

desc("increase the current_project_version config based on configuration")
    lane :increase_build do |option|
        
        fastlane_require 'Xcodeproj'
        
        project = "../#{urProjectName.xcodeproj}"
        target = <#targetName#>
        buildConfiguration = <#release_configuration_name#> 
        CUSTOM_BUILD_NUMBER = ''
        
        project = Xcodeproj::Project.open(project)
        project.targets.each do |mtarget|
            if mtarget.name == target
                mtarget.build_configurations.each do |mbuild|
                    if mbuild.name == buildConfiguration
                        CUSTOM_BUILD_NUMBER = mbuild.build_settings['CURRENT_PROJECT_VERSION']
                        mbuild.build_settings['CURRENT_PROJECT_VERSION'] = CUSTOM_BUILD_NUMBER.to_i + 1
                    end
                end
            end
        end
        project.save()
    end

to get the build number for configuration you may use almost the same script like this

lane :get_build_number_for_configuraiton do |option|
        fastlane_require 'Xcodeproj'
        
        project = "../#{urProjectName.xcodeproj}"
        target = <#targetName#>
        buildConfiguration = <#release_configuration_name#> 
        CUSTOM_BUILD_NUMBER = ''

        project = Xcodeproj::Project.open(project)
        project.targets.each do |mtarget|
            if mtarget.name == target
                mtarget.build_configurations.each do |mbuild|
                    if mbuild.name == buildConfiguration
                        CUSTOM_BUILD_NUMBER = mbuild.build_settings['CURRENT_PROJECT_VERSION']
                    end
                end
            end
        end
        CUSTOM_BUILD_NUMBER
    end

it can use some refactoring , but that should do it.

Enjoy.

Deploying through bitbucket pipeline

bitbucket pipelines is a great feature and it can facilitate a lot of work, I won’t say its better than Jenkins or other CI tools, but I like how simple it is.

Here I will be talking about deploying a PHP api codebase into a server, it could be your production code , staging, etc…

The problem I faced is that I wanted to work locally on my php project without worrying about deploying the code into the public server, though you can use netbeans syncing feature, but that means every change you make will be deployed directly without testing, also it would be hard to avoid conflicts if you are working with other developers on the same codebase. Another way to solve it, is to use git, where you push your code and then go to the server and pull your code there, but as you see here , you need to go to the server and pull your code manually.

So the idea here is that whenever I push some code into the master branch or certain branch(s), I want my code to be deployed into the server as fast as possible, without shutting the service for long time.

Bitbucket pipeline can help us tremendously here , as we can trigger the pipeline script(s) on certain triggers (manual, schedules, on commit ), check https://confluence.atlassian.com/bitbucket/configure-bitbucket-pipelines-yml-792298910.html for more info.

after the pipeline is triggered, a certain script will be executed, and there where the work is done.

the pipeline file is a YAML file (https://en.wikipedia.org/wiki/YAML), which is really convenient to use, before we start scripting we need to enable pipeline for our project, so go to settings -> Pipelines -> settings -> click on enable pipeline switch. You will find a button saying configure bitbucket-pipelines.yml, click it.

you will see a page asking you to choose a language template , I will be using php here.

you will see an editor where you can edit the yaml file and on the side there is pipelines templates sections where you can find already made scripts you can use, like deploying to Amazon s3, firebase and so on.

For me I am going to deploy my project through ssh, you may use SFTP here and there is an already made pipeline called SFTP-deploy that you can find in the pipelines templets, but if you have a non trivial code base , it will be slow to move all the files on each commit/file change!!.

So am not going to use any pipeline and stick with the default one as starter. To transfer the data over ssh , am going to use Rsync tool, which is the one used by netbeans to sync your files with the remote server quickly since whenever you make some changes like adding new file or deleting one , rsync can sync only the updated files and does not copy the whole codebase all over again as if you used SFTP-deploy or FTP-deploy pipelines.

you can read more about rsync here “https://en.wikipedia.org/wiki/Rsync” and here https://linux.die.net/man/1/rsync

ok the pipeline code


--- 
image: "php:7.2.13"
pipelines: 
  branches:
    master:
      - step:
          name: "deployment"
          deployment: "staging" 
          caches: 
            - composer
          script:
            - echo "Starting Staging deplyment from master"
            - apt-get update
            - apt-get -qq install sshpass
            - "apt-get update && apt-get install -y unzip"
            - "curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer"
            - "composer install"
            - sshpass -p $FTP_PASSWORD rsync -are "ssh" --delete ./* [email protected]$HOST:$HOST_PATH --exclude runtime/

So in the pipeline configuration file here we ask to download php docker image and use it (it might need to match the one on your server), you see there is branches and under it staging, this means that when new code is updated on the branch named “Staging” run next steps , and we have 1 steps here , the first which will install dependencies and move the code from the bitbucket CI into our server. Note that none of these commands is actually executing on our server.

note that we install sshpass tool , since where moving a the files here using ssh with password , and rsync will prompt you to ask for a password in the terminal , but the script running on the CI is not interactive so we use it to overcome that hurdle.

you see that we use something like $FTP_PASSWORD, these are called repository variables and you can set them from settings->pipelines->repository variables and the cool thing about it is that you can have secured variables for something like password, so you don’t have to put the password in a plain text in the repository.

--delete : is used to be able to delete files when deleted by the source , and --exclude runtime/ means we don’t want to sync this directory since its would be a place for things like logs, and cache and we don’t want to tamper with the web service logs.

so that’s basically it.

hope its been useful for you, took me days to figure it out !^_^.

disclaimer: this is tested on small/medium size monolithic projects only and not on production, so do your testing/research and be careful. I am just sharing my experience, but please let me know if you have suggestions or rectifications.