This blog post is Unfiltered

I have had a passion for technology since before I can remember. Thirteen years ago I took the plunge, quit my day job, and started an IT development and support company called Tickett Enterprises Limited. For the last three years, GitLab has been a part of my journey.

3 Years Ago

We were (and still are) using a helpdesk system we built ourselves. It does exactly what we need it to do - and any time it doesn’t, we change it. The most important feature of the system is reporting. Specifically, facilitating our monthly billing process; with a click of a button, we generate timesheets and invoices for all of our clients.

Though I was aware of Git (and GitHub), I had not heard of GitLab. We were using SVN in its most basic form (single repository for all projects and no branching), with an integration so all commits would create notes in our helpdesk.

2.5 Years Ago

We decided that SVN was no longer fit for purpose. Our top issues were:

While most of these issues were due to the way we were using SVN, we were keen to adopt a more popular system. I don’t remember how I found GitLab, but I did, and spun up a local on-prem instance of Community Edition (CE) using separate projects/repositories and basic branching. If you are considering running a local instance, I recommend the Bitnami appliance/.ova.

It took some time to get used to local vs remote and to remember to push as well as commit, but we picked it up pretty quickly.

2 Years Ago

We wanted to use GitLab to help us improve our processes so we:

1.5 Years Ago

A bit late to the party, but finally we set up the GitLab runner to automate our build, spin up our database, execute our unit tests and report test details and code coverage. GitLab CI for .NET was not as well documented as other use cases leading to a lot of trial and error when setting up the runner.

We are using the Windows runner configured to use a standard shell (which I think is no longer supported). We will either be moving to powershell on windows or possibly using docker images. Here’s a sample .gitlab-ci.yml

stages:
  - build
  - test

variables:
  CI_DEBUG_TRACE: "false"
  ASSEMBLY_VERSION: "1.0.4"
  
build:
 stage: build
 script:
  - 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\nuget restore'
  - '"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\bin\msbuild" /t:Restore,Clean,ReBuild /t:Database:Publish /p:Configuration=Debug;Platform="Any CPU" /p:SqlPublishProfilePath=Database.publish.xml'
  - 'ping 192.168.99.99 -n 1 -w 10000 2>nul || type nul>nul'
 artifacts:
  paths:
   - Tests/bin/

test:
 stage: test
 script:
  - 'c:\GitLab-Runner\opencover\OpenCover.Console.exe -returntargetcode:1000 -filter:"+[*]* -[nunit*]* -[*Tests*]*" -register -target:"C:\Program Files (x86)\NUnit.org\nunit-console\nunit3-console.exe" -targetargs:"Tests\Tests.csproj --result=testresult.xml;transform=C:\gitlab-runner\nunit3-junit.xslt"'
 coverage: '/^Visited Branches .*(\(\d+\.?\d*\))/'
 dependencies:
  - build
 artifacts:
  reports:
   junit: testresult.xml

We were building another customization to allow us to search for code across all repositories. Unfortunately, we hit a limitation because the API did not allow searching anything but the default branch.

At this point, while Googling for help getting CI up and running, I learned that GitLab is open-source. So I thought maybe I could extend the API to support searching any branch. This lead to my first contribution.

1 Year Ago

At this point, I was completely new to all of the technologies, techniques, and best practices used by GitLab but found myself participating in my first GitLab hackathon. Somehow, I managed to take joint first prize!

My first few contributions were achieved by modifying my production GitLab installation (not ideal). So it was time to get the GitLab Development Kit (GDK) up and running. This was certainly not without its challenges (many of which I suspect stem from me being in the minority of GitLab contributors running Windows).

I have since contributed to the GDK project and joined the GDK office hour calls to help shape the way forward and resolve some of the problems and frustrations.

At this point, I was leearning a lot. Not just about the tools and languages but about the best practices and work ethos within the GitLab team. Better yet, I was able to start taking some of these learnings back to the office.

0.5 Years Ago

I attended GitLab Commit - London 2019. This really helped to confirm my suspicions; we are only scraping the surface of GitLab's capabilities.

On a few occasions, I wondered whether GitLab may not be a good fit for my company as I watched huge companies like Porsche and Goldman Sachs present. A presentation by Huss El-Sheikh from startup 9fin helped ease my concerns.

Around this time, I moved from Windows to Ubuntu to make it easier to work with GDK.

I continued to learn a lot from my contributions, feedback, and interactions with the GitLab team, again applying what I could back in the office. Much around the languages/technologies I hadn’t previously worked with (namely ruby, postgres and vue), but also other takeaways such as:

I am a firm believer of documenting processes, decisions, and rationale. There’s nothing worse than someone saying “we do it this way” without being able to back that up with reasoning. With that in mind, we implemented Merge Request Templates to ensure our team was consistent in our approach to coding, testing, and releasing.

By now our development team had plenty of experience with GitLab and we were starting to move our support team over. To help our team leads monitor merge requests, we adopted 2 simple departmental labels (Support/Development) and used our webhook engine to ensure every MR is automatically labelled.

Today / What’s Next

In preparation for a transition to .NET core, deprecation of the Windows shell runner and a desire to start testing our frontend (web), I started putting a CI script together using docker and the mcr.microsoft.com/dotnet/core/sdk:latest image. The .gitlab-ci.yml looks like;

stages:  
  - build
  - test

variables:
  CI_DEBUG_TRACE: "false"
  ASSEMBLY_VERSION: "1.0.1"

build:
 stage: build
 tags:
  - docker
 script:
  - 'dotnet build'

test:
 stage: test
 tags:
  - docker
 script:
  - 'nohup dotnet run --project Web &'
  - 'apt-get update'
  - 'apt-get install -y unzip'
  - 'wget https://chromedriver.storage.googleapis.com/83.0.4103.14/chromedriver_linux64.zip'
  - 'unzip chromedriver_linux64.zip -d ~/'
  - 'rm chromedriver_linux64.zip'
  - 'mv -f ~/chromedriver /usr/local/bin/chromedriver'
  - 'chown root:root /usr/local/bin/chromedriver'
  - 'chmod 0755 /usr/local/bin/chromedriver'
  - 'wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
  - 'sh -c ''echo "deb https://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'''
  - 'apt-get update'
  - 'apt-get install -y google-chrome-stable'
  - 'dotnet test -l:trx Tests/Tests.csproj /p:CollectCoverage=true'
 coverage: '/Total\s*\|.*\|\s(\d+\.?\d*)%\s*\|.*\|/'

And the tests look something like;

    public class UiTests : IDisposable
    {
        private readonly Process _webServerProcess;
        private readonly IWebDriver _driver;

        [Fact]
        public void ClickNavPrivacyPolicy()
        {
            _driver.Navigate()
                .GoToUrl("http://localhost:5000/");

            var link = _driver.FindElement(By.LinkText("Privacy"));
            link.Click();

            Assert.Equal("http://localhost:5000/Home/Privacy", _driver.Url);
        }

        public UiTests()
        {
            ChromeOptions chromeOptions = new ChromeOptions();
            chromeOptions.AddArguments("headless", "no-sandbox");
            _driver = new ChromeDriver(chromeOptions);

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return;

            _webServerProcess = new Process
            {
                StartInfo = {
                    WorkingDirectory = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "..", "Web"),
                    FileName = $"dotnet.exe",
                    Arguments = " run",
                    UseShellExecute = true,
                }
            };
            _webServerProcess.Start();
        }

        private void KillWebServer()
        {
            if (_webServerProcess != null && !_webServerProcess.HasExited)
            {
                _webServerProcess.Kill();
            }
        }

        public void Dispose()
        {
            _driver.Dispose();
            KillWebServer();
        }
    }

You can see some conditional code in there which allows Selenium tests to work both locally on our development machines and remotely on our GitLab runner. If you have a better way of achieving this, please leave a comment. I would love to chat and learn!

I also want to start introducing some linting like we see in the GitLab project to enforce rules around code formatting (spaces, carriage returns, indentation, etc.). I have started to look at JetBrains Resharper (R#) command-line but haven’t had enough time to implement it yet. Ideally. I would like to start with just a rule or two and then slowly introduce more, but it looks quite tricky to take this approach. Please let me know if you’ve been able to achieve this!

I would also like to lose our helpdesk and start using GitLab issues, service desk, timelogs, etc. I am working on identifying the gaps and working with the product managers to understand whether it is realistic to fill those gaps within the GitLab product. Alternatively, I will be looking to build some additional “bolt-ons” using webhooks and the API.

While investigating gaps, I stumbled upon the GitLab-Triage project and I expect we'll use this to automate various workflows. I managed to help close a few issues and even create a few additional features which would make it work for us by contributing to the GitLab-Triage project.

We also added more labels (needs code review & needs functional review) for our merge request approval process now. We can see where we are and what needs to be done at a glance. We previously relied on an MR checklist that we are deprecating.

Merge request checklist

Merge requests with labels

Contributing to GitLab

I am very proud to have joined the GitLab Core Team. Thanks to everyone who has held my hand and patiently assisted me with contributions.

With the release of Microsoft Windows Subsystem for Linux v2, I have gone back to running Windows on my laptop with GDK running in Ubuntu on WSL2. This is working brilliantly for me at the moment (the way Visual Studio Code handles things especially is really cool).

I now have 95 merged merge requests! and have been helping several others get started contributing (getting GDK up and running etc). Once this crazy pandemic is over and we can start to socialise again, I would like to try and start some sort of local meetup/group.

I would like to help make it easier to connect GitLab users. I have visions of a mechanism to search for others based:

At present, we have several tools (Gitter, Issues, Forum etc) but there is a strong reliance on being engaged and stumbling on questions/support requests. I suspect many of us would be happy to have other users reach out directly.

If you need any more information around:

…or would like to see a demo of anything discussed above, I would be happy to oblige!

I would love to connect with others who are either looking to, or already using GitLab for:

Thanks for reading! Here's a picture of me and the family repping with our GitLab merch!

The tickett family repping GitLab

Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license