Add GitLab Pages post

This commit is contained in:
Rob Watson 2018-03-25 14:22:52 +02:00
parent 5045f0a3d4
commit 696a71a193
1 changed files with 140 additions and 0 deletions

View File

@ -0,0 +1,140 @@
---
title: Some things that I learned making GitLab Pages HTTPS-only
slug: things-I-learnt-gitlab-pages-https-only
layout: post
categories: 'development foss'
date: '2018-03-25 00:00:00 +0200'
---
This week, my most significant contribution yet to the [GitLab project](https://gitlab.com/) was [merged](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/16273) into master.
The contribution adds the ability for [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/index.html) websites to be served only over HTTPS connections, with plain HTTP requests 301-redirected to their secure counterpart.
The changes required to make this work were not trivial, and actually required two separate patches to be merged: one in [Ruby](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/16273) and a second in [Go](https://gitlab.com/gitlab-org/gitlab-pages/merge_requests/50).
Here's a random sampling of some things that I learnt during the development process.
### GitLab is a fun project to hack on
The [GitLab application](http://gitlab.com/gitlab-org/gitlab-ce/) consists of a Rails monolith plus a number of secondary services, including a dedicated [HTTP server for GitLab Pages](https://gitlab.com/gitlab-org/gitlab-pages/) which is written in Go.
GitLab Pages websites are typically auto-generated by the GitLab [CI/CD system](https://about.gitlab.com/features/gitlab-ci-cd/). The artifacts of this process are static website assets, such as HTML files, which are served by the Pages server.
Implementing HTTPS-only pages required two separate changes to the overall application.
Firstly, the Rails monolith had to be altered to write [additional metadata](https://gitlab.com/gitlab-org/gitlab-ce/blob/9d45951fcaeda4f01a2e4be2480d980a3e7cd37e/app/services/projects/update_pages_configuration_service.rb#L19-35) to a per-project configuration file, indicating whether the project's Pages website should be forced to HTTPS or not. Supporting this were the user interface changes to allow a user to enable or disable the behaviour, and the usual layers of automated testing.
Secondly, the Go HTTP server had to be updated to parse the newly-added configuration, and adapt its behaviour accordingly (that is, serve a 301-redirect when appropriate).
I love the challenge of implementing a distributed feature across multiple technical domains. Being forced to consider the interaction between the services, error-handling, reliability and so on means that it's possible to learn much more than the sum of the two individual pull requests.
Additionally, GitLab's code quality in general feels very good. The Rails app is written in a modern style, with heavy use of [service objects](https://hackernoon.com/service-objects-in-ruby-on-rails-and-you-79ca8a1c946e) and comprehensive automated testing, including a very slick parallelized CI flow.
Finally, the GitLab community appears to be very professional and friendly, and contributing a significant feature was a very positive experience. Thanks guys!
### Go is a nice language
Generally I distrust Google as a corporation, and this political bias had led me to be somewhat suspicious about Go as a language. This turns out to have been a fallacy, and it's been great to dispel it.
Go is a much nicer language than I unfairly expected it to be. In its syntax, basic types and use of pointers it immediately reminded me of C, which made me feel comfortable very quickly.
I also found the Go toolchain to be very productive and enjoyable (although given Google's investment in the ultra-slick Android toolchain this probably shouldn't be a surprise). Being able to import modules directly from Git repositories, and auto-format code from the command-line are just two simple examples.
This project helped me to understand why Go has become so popular, and when it might be considered the right tool to choose in the future.
### Parameterized RSpec tests are a great thing
When writing RSpec tests, it is common to start with this kind of pattern:
{% highlight ruby %}
RSpec.describe "something" do
before do
send_request(path, "GET")
end
context "path is /" do
let(:path) { "/" }
it { is_successful }
end
context "path is /abc" do
let(:path) { "/abc" }
it { is_successful }
end
end
{% endhighlight %}
This feels simple and reasonably readable, until a second contextual variable is introduced. Not only do we quickly see code-repetition being introduced, but the nesting also starts to feel unwieldy:
{% highlight ruby %}
RSpec.describe "something" do
before do
send_request(path, method)
end
context "path is /" do
let(:path) { "/" }
context "method is GET" do
let(:method) { "GET" }
it { is_successful }
end
context "method is POST" do
let(:method) { "POST" }
it { is_not_successful }
end
end
context "path is /abc" do
let(:path) { "/abc" }
context "method is GET" do
let(:method) { "GET" }
it { is_successful }
end
context "method is POST" do
let(:method) { "POST" }
it { is_not_successful }
end
end
end
{% endhighlight %}
Introducing even more contextual levels exacerbates the problem further.
Enter [RSpec::Parameterzied](https://github.com/tomykaira/rspec-parameterized), which allows the same examples to be defined using a simple, flat table instead:
{% highlight ruby %}
RSpec.describe "something" do
using RSpec::Parameterized::TableSyntax
where(:path, :method, :success) do
"/" | "GET" | true
"/abc" | "GET" | true
"/" | "POST" | false
"/abc" | "POST" | false
end
with_them do
before do
send_request(path, "GET")
end
it "returns the expected response" do
expect(response.success).to eq success
end
end
end
{% endhighlight %}
RSpec will now run each of the rows in the table as a separate example, with inputs corresponding to the column values.
Although a downside of this approach is that debugging the specs can be more challenging, in test-heavy applications with a lot of contextual variants this feels like a useful option.
### Conclusions
Implementing HTTPS-only GitLab Pages has been a great learning experience, and a lot of fun! I'd highly recommend anybody who wants to hack on a non-trivial, backend-centric Rails app to check out the [GitLab Contributing page](https://about.gitlab.com/contributing/) and get involved.