Deploying Static Sites generated with Swift and Publish with Gitlab CI/CD

By the end of this tutorial, you will be able to build and deploy a static website generated with Swift on Gitlab Pages with a CI/CD pipeline.

Deploying Static Sites generated with Swift and Publish with Gitlab CI/CD

I have been using Publish, a static site generator for Swift developers, by John Sundell in recent months to generate JavaScript-free websites with just HTML and CSS from Markdown files.

Even though there are many static site generators available on various toolchains, I really enjoy using Swift from top to bottom for as much of any project I am working on. To that effect, Publish is a great solution and it works as intended. Publish uses Ink, a Markdown parser written in in Swift, and Plot, a domain-specific language (DSL) for writing type-safe HTML, XML and RSS in Swift, which was recently updated to build HTML components in a more SwiftUI like fashion.

Publish comes with a DeploymentMethod API to deploy the generated website to external services with built-in implementation for Git and GitHub environments. It is as easy as adding a deploy step to the publishing pipeline, such as

try AmazingWebsite().publish(using: [
    ...
    .deploy(using: .gitHub("create-with-swift/amazing-website"))
])

However, for this to work, the deployment steps have to be enabled with a
-- deploy command line flag that can be added to the Xcode build scheme at Product > Scheme > Edit Scheme... or by using the publish deploy command on the command line.

The deployment will take the generated website and all files in the Output folder and commit and push it to the git repository. If the repository is configured to trigger a CI/CD pipeline that will host the files on a webserver, the deployment can easily be automated.

Hosting Static Website on Gitlab Pages

On Gitlab you can use Gitlab pages to host the static website for free. It can be configured as public or private, based on the settings of the Gitlab project, and is an easy way to host a static website that even supports adding a custom domain at no cost.

Easiest way to set it up is by adding a .gitlab-ci.yml file to the repository that will trigger a CI/CD pipeline to be run whenever updates are pushed to the repository. The file configures the steps to be completed each time it is triggered.

.gitlab-ci.yml file

For a simple implementation it could look like this:

pages:
  stage: deploy
  script:
  - mkdir .public
  - cp -r * .public
  - mv .public public
  artifacts:
    paths:
    - public
  only:
  - main

In this case, the pipeline would createa a new .public directory, Then it copies all files in the repository (which are the files of the static website pushed to the repository by Publsih) to the folder and moves the folder to the public default path for the Gitlab page. Once completed, the static site will be served under

https://GITLAB-USER-NAME.gitlab.io/REPOSITORY-URL

The pipeline will only run on commits to the main branch of the repository, called main in this case. In the CI/CD menu of the Gitlab project, all pipelines can be reviewed and also re-run if needed.

Gitlab CI/CD Pipelines

Using this workflow, you could have your Publish project in some other git repository and whenever you want to publish changes to the website, you can use the deploy step to commit and push changes to the dedicated Gitlab project that will then trigger the CI/CD pipeline to copy the files to the correct path to service the website as the page for the repository.

Building Static Website with Gitlab CI/CD

Alternatively, you could also use a repository to store both the Publish project and the static website and build the static website remotely rather than locally. To achieve this, the entire Publish project folder can be added to the repository and the CI/CD pipeline can than use a docker image to build the project, create the static site and copy the generated files to the default path to be served as the Gitlab page.

The .gitlab-ci.yml for such an implamentation could look like this:

image: swift:latest

pages:
  stage: deploy
  script:
  - swift run
  - mkdir .public
  - cp -r Output/* .public
  - mv .public public
  - echo $CI_PAGES_URL
  artifacts:
    paths:
    - public
  only:
  - main

Each time changes are pushed to the repository, the pipeline will pull a docker image for the latest version of Swift, fetch all ressources necessary to build the Publish project, install any necessary plugins, copy ressources and publish the static website in the Output folder. As a last step and similar to the previous process, all files are then moved to the public default path for the Gitlab page.

To extend this approach even further, you could work with branches and have a dedicated branch to serve the website. Adjusting the .gitlab-ci.yml file, you can specify the branch that would trigger the pipeline to run, thereby only updating the static website if a commit to a certain branch is detected.

Of course, there are alterntatives to this approach, e.g. using Github Pages (which more or less work the same) or even service providers such as Netlify, a serverless platform to build and deploy web apps from a git-based workflow. Netlify will take care of the automatizations, however on the free Starter plan, the served site will public. Private sites are only allowed starting from the Pro plan.

For an introcution into static site generation with Swift, consider the tutorial "Static Site Generation with Swift using Publish, Plot and Ink".