Recently I described, how to keep in sync with GitLab latest releases on the Raspberry Pi. And of course it lead me to a problem after unsuccessful update to version 8.17-rc3. This release has the PostgreSQL 9.6.2 embedded and apparently everything got broken in the middle of the upgrade process. After all my tries to revert to previous GitLab version, lots of time wasted (yes, each call to apt-get upgrade or install specified GitLab version was taking several hours!), I still stayed with totally unresponsive instance.

Then again I came back to basics.

  1. I rebooted the device
    sudo shutdown –r now
  2. Installed latest GitLab-CE
    sudo apt-get upgrade
  3. Asked it to revert PostgreSQL to previous version
    sudo gitlab-ctl revert-pg-upgrade
  4. At this stage, it was showing some strange errors about inability to connect to psql service via TCP/IP, that was pretty strange.
    So I checked the status.
    sudo gitlab-ctl status

    run: gitlab-workhorse: (pid 3099) 7362s; run: log: (pid 604) 1487541047s
    run: logrotate: (pid 11405) 160s; run: log: (pid 602) 1487541047s
    run: nginx: (pid 1917) 7686s; run: log: (pid 608) 1487541047s
    down: postgresql: 1s
    run: redis: (pid 1930) 7685s; run: log: (pid 603) 1487541047s
    run: sidekiq: (pid 3079) 7364s; run: log: (pid 607) 1487541047s
    run: unicorn: (pid 3257) 7282s; run: log: (pid 606) 1487541047s
  5. And then logs!
    sudo gitlab-ctl tail postgresql
  6. And it was continuously repeating an error, while parsing line 210 of the configuration file, what was all the time stopping the service.
    sudo vi /var/opt/gitlab/postgresql/data/postgresql.con
  7. Since it was about replication, I commented it out and service started normally.
  8. Then manually upgraded PostgreSQL
    sudo gitlab-ctl pg-upgrade
  9. This time all went OK.


I recently noticed that my GitLab installed on Raspberry Pi (running Jessy) stopped updating and stick to version 8.7.9, however the latest one as of today is 8.16.4.

Normally apt-get updateand apt-get upgradeshould do the trick. But it turned out there was a change in the build system and newer packages don’t get uploaded into ‘raspbian’ version of repository. For details - take a look on issue #1303. Although quick patch is following and short:


Edit configuration file located at: /etc/apt/sources.list.d/gitlab_raspberry-pi2.list

And redirect the repository path from ‘raspbian/’ to ‘debian/’.




I wasted far more time than originally expected on simple email-notifications configuration for GitLab. I use Webio hosting and somehow following part of config file (at “/etc/gitlab/gitlab.rb”) is the only one that works. Hopefully it will be useful to you, too.


gitlab_rails['smtp_enable'] =true
gitlab_rails['smtp_address'] ="poczta.webio.pl"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] ="xyz@codetitans.pl"
gitlab_rails['smtp_password'] ="xyz"
gitlab_rails['smtp_domain'] ="codetitans.pl"
gitlab_rails['smtp_authentication'] ="login"
gitlab_rails['smtp_enable_starttls_auto'] =true
gitlab_rails['smtp_tls'] =true
gitlab_rails['smtp_openssl_verify_mode'] ='peer'
gitlab_rails['smtp_ca_path'] ="/etc/ssl/certs"
gitlab_rails['smtp_ca_file'] ="/etc/ssl/certs/ca-certificates.crt"

gitlab_rails['gitlab_email_display_name'] ='CodeTitans'
gitlab_rails['gitlab_email_from'] ='xyz@codetitans.pl'
gitlab_rails['gitlab_email_reply_to'] ='xyz@codetitans.pl'


Setting up GitLab was pretty easy on a Raspberry PI 3. The installation process is straightforward, it only took very long time to unpack (prepare for several hours!). And once running, its a brilliant combination comparing to all those noisy servers (aka my old PCs) I should have kept running. For the most Pi uses SD card, giving an immediate access at any time of day and doesn’t need to awake and start to spin its disks.


Moving to HTTPS configuration.
I have installed letsencrypt-auto successfully, created a config file with webroot authenticator and inside listed my domain. The real problem appeared, when I actually failed to pass the authentication challenge. Since I use the Synology NAS at the same domain, which occupies the port 80, the required web folder ‘/.well-known’ was unavailable. This unit I can’t just throw away, I wish to make both devices running smoothly together. Luckily Synology DSM 6.0 uses Let’s Encrypt too, so its nginx server is already preconfigured. What I did was to tweak a bit the config.


On the NAS side:

  1. Create shared Samba folder /volume1/acme(it might be hidden and only one user could have rights to write there)
  2. Make sure the path exists: /volume1/acme/letsencrypt/
  3. Edit /etc/nginx/nginx.conf and for location “/.well-known/acme-challenge” redefine the root from “/var/lib/letsencrypt” to “/volume1/acme/letsencrypt”


Now on the Raspberry PI

  1. Mount the folder
    sudo mount -t cifs //<nas_ip>/acme /var/www/acme -o username=<user_name>,password=<password>
  2. Retry certificate generation, it should pass this time
  3. Update GitLab config (“sudo vi /etc/gitlab/gitlab.rb”) adding following lines into:

    nginx['ssl_client_certificate'] = "/etc/gitlab/ssl/ca.crt" # Most root CA's are included by default
    nginx['ssl_certificate'] = "/etc/letsencrypt/live/<domain>/fullchain.pem"
    nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/<domain>/privkey.pem"

  4. Finally run “gitlab-ctl reconfigure” to refresh running instance (or only “sudo gitlab-ctl restart nginx” to restart nginx, if you renew certificate 3 months later…)



To remember, try first against acme-staging servers before switching to production one to generate real certificate.


I am a really big fan of JetBrain’s TeamCity product. I use it a lot at work and also for my hobby projects. But unfortunately I found it lacks one important, yet very basic feature – proper (and easy) application version management. Someone might say, that this is not totally true, there is a build-in AssemblyInfo Patcher. Yes, OK, although this one is extremely limited and can mostly be used for very simple projects, created by Visual Studio New Project Wizard and never modified.


What are my special requirements then?

Well, in my world I really wish to:


#1. Make TeamCity fully responsible for assigning versions to all the software components.

Let’s say the hardcoded version inside the application and its libraries is “0.1.*”, so the builds created on developers’ machines are quickly discoverable. Just in case someone totally accidentally with all the good reasons in mind tries to install it on customer’s machine. All official public builds should at least be greater than “1.0.*“ though.


#2. Each code branch should have a different build version.

For example the current application version build on ‘master’ branch is ‘1.7.*’, while artifacts of ‘develop’ branch should be ‘1.5.*’, comparing to feature branches, could be even lower, alike ‘0.9.*’.

This plays nicely with the #1 requirement stated above, as since all versioning management is handled by TeamCity, there should never be a merge conflicts between any of those branches and versions, nor any other manual source-code plumbing required.


#3. It should be possible to set BuildNumer to default, what C# compiler does.

BuildNumber is third part (number after second dot) of the version string. By default, if left as a star (1.0.*) C# compiler will put there today’s date, counted as days elapsed since 1st January 2000. It is extremely useful information, what I would love to preserve. This value automatically increases each day, and at any time can help find, how old any public release package used by customer was.


#4. It should be possible to also store the version info inside regular text file.

For a Web (or Web API) project, it’s much easier to store the current version inside a static file (as it never changes until the new release, so can be server-side cached) and let the client apps (that actually communicate with mentioned server part) download at startup to check, if there are any updates etc. Also it might play a label role, if resides next to compiled binaries.



This is the very quick way of saying, how I’ve chosen to complete this task:

I designed a PowerShell script, launched as the very-first work item, just after the sources being downloaded from repository and NuGet packages updated.




It’s flexible enough (as accepting lots of startup parameters from TeamCity) to locate the AssemblyInfo.cs file (or other variants), read current version stored there, update it according to wishes and project spec. Then it stores newly generated version back into the original file, optionally also into a text file and most importantly sends this new info back to TeamCity. Version is then generated in one place, simply based on given inputs and then spread to all required locations.




Of course to avoid any influences, repository checkout is configured to always load full sources from remote, so any local changes done previously during this process are reversed and never included into the current run.


Check the code at my gist and have fun using it!


Sample calls


PS> .\update-buildnumber.ps1 -ProjectPath 'src/ToolsApp' -BuildRevision 15

##teamcity[buildNumber '']


PS>  .\update-buildnumber.ps1 -ProjectPath 'src/Apps/DevToolsApp' -BuildNumber 0 -BuildRevision 21

##teamcity[buildNumber '1.0.6162.21']


PS> .\update-buildnumber.ps1 -ProjectPath 'src/Apps/DevToolsApp' -BuildNumber 0 -BuildRevision 29 -SkipAssemblyFileVersionUpdate $True

##teamcity[buildNumber '1.0.6162.29']