2022/07/03

Make use of free tier gitlab pages for hosting with openapi document & coverage report

1. Goal

In this blog, I am going to make use of gitlab pages for hosting my openapi documents & coverage reports.

TL;DR,

FYI, this is a follow up blog for my flask learning. Before this blog, I have written a blog for showing how to setup the vscode’s debugger from scratch. Make sure to check them out if they are helpful for your cases.

1.1 Contents overview

  • In section 2, I will explain how to build the openapi document in cicd
  • In section 3, I will explain how to build the coverage report in html in cicd
  • In section 4, I will explain how to wrap up everything, and upload to the gitlab pages
  • In bonus section, I will write down my advices on writing openapi.yaml from scratch

2. Build OpenAPI document in cicd

In this section, I assume you have a valid openapi.yaml at the first place. If you don’t, please read my advices in bonus section before writing this file from scratch. It may help you a bit.

General idea

  • Convert the yaml to html files
  • Upload the html files to gitlab pages
  • Do this only if I am updating master / tagging

In order to build the OpenAPI document in gitlab cicd, you need following yaml

...
stages:
  - build
  - test
  - buildPages
  - deploy
...
buildOpenapiPages:
  image: node:18-alpine
  stage: buildPages
  dependencies: []
  script:
    - wget https://github.com/swagger-api/swagger-ui/archive/refs/tags/v4.12.0.tar.gz -O swagger.tar.gz
    - tar xvf swagger.tar.gz
    - mkdir -p build/openapi/
    - cp -fr swagger*/dist/* build/openapi/
    - npm install @apidevtools/swagger-cli
    - ./node_modules/.bin/swagger-cli bundle -o build/openapi/openapi.json ./openapi.yaml
    - sed -i
      "s#https://petstore\.swagger\.io/v2/swagger\.json#${OPENAPI_JSON_FILE_URL}#g"
      build/openapi/swagger-initializer.js
  artifacts:
    untracked: false
    expire_in: 1 hour
    paths:
      - build/openapi/
  only:
    - main
    - tags

Before explaining script, I will explain rest of the fields first

  • I have defined a new stage buildPages for building the related pages
    • Ensure we build pages only if it passed the pipeline
  • I only upload build/openapi/ since I only need files there
    • untracked is suggested from the IDE. It does not really matter
    • Set expire_in to a relative short period since I don’t need them after the pipeline
  • Use only to ensure this task will only be run on main branch, or tags (tagging)
  • Set dependencies to empty array in order to speed up the pipeline process. Otherwise, it will download the artifacts in the test stage

In script, there are 2 things happening

  • Installing a standalone swagger version as suggested by the official guide
  • Convert openapi.yaml to openapi.json as required by the standalone swagger ui
    • By using @apidevtools/swagger-cli
    • That’s why I need image node:18-alpine. Version is not important as long as it can run the above tool

After the installation & conversion, I put everything under build/openapi for uploading as gitlab’s artifacts.

A side note on ${OPENAPI_JSON_FILE_URL}. Since the swagger ui need this file in order to render my APIs properly, I need to make sure the swagger ui can find this file in the runtime. So, I copy this json file next to the swagger ui folder. Then, it will shares the same gitlab pages url with swagger ui.

3. Build coverage report in cicd

Back in 2017, my old blog described how to do that in general. So, in 2022, I will just modified a bit from my old works.
The yaml snippet required in this section.

runTests:
  ....
      - coverage html -d build/coverage
  ...
  artifacts:
   ...
    untracked: false
    expire_in: 1 hour
    paths:
      - build/coverage/
  • For artifacts, it is similar to section 2. But, I need build/coverage/ this time
  • I generate the coverage report by using coverage html -d build/coverage
  • A side note one the stage.
    • I generate the document at the end of task in test stage instead of creating a buildCoverageReport task.
    • This can save me some pipeline time for rerunning the coverage again.

That’s it.

4. Upload to gitlab pages

Finally, I need to copy all artifacts from previous stages to public/ in a specific pages task.

pages:
  stage: deploy
  image: alpine:3.16
  variables:
    GIT_STRATEGY: none
  script:
    - mkdir -p public
    - cp -r build/* public/
  artifacts:
    untracked: false
    expire_in: 1 hour
    paths:
      - public
  dependencies:
    - runTests
    - buildOpenapiPages
  only:
    - main
    - tags
  • Set dependencies explicitly. Personal habit. It inherits all artifacts from previous stages by default
  • Set GIT_STRATEGY to none for speeding up the pipeline process since I just need artifacts and nothing else
  • Rest of the keys are explained in previous stages

That’s it. After the pipeline’s run, I will have 2 different documentations under public/ that will hosted by gitlab pages

  • public/coverage/
  • public/openapi/

Check out the links in section 1 for the demo.

A side note on writing gitlab pages. Old gitlab pages will be erased whenever you publish new gitlab pages. So, please do not assume it will keep your stuff forever.

5. Bonus Section advices on writing openapi.yaml

5.1 Get an IDE

Personally, I am using vscode with extension 42Crunch.vscode-openapi. Features like linting, code hinting, and previewing with style are really important for writing documents (Or, codes). You don’t need to follow my IDE setup but I strongly recommend you to get an IDE that support above features. It will save you many time for debugging your syntax etc.

At least, you can use the online editor from swagger

5.2 Essential websites for openapi reference

IMO, there are no quick ways for learning openapi’s writing. It really takes time for studying openapi specifications. Otherwise, you cannot just really write something you want.

Personally, I will suggest you to go through their basic openapi guide first. It provide certain common snippets for you to start with.

Then, after you gathering certain set of snippets, I suggest you to start reading the schema section in openapi specification. As the meaning of the specification, it describes every bits in your snippets clearly.

Finally, you will behave just like me. You will keep jumping between schema & guide.

  • In schema, you will have a general idea about what fields you need
  • Go to guide, you will probably get some examples for your idea
  • Back to schema, try to tweak from the examples by understanding the schema throughly
  • Loop until you completed the yaml

Of cause, IDE helps you a lot in this process. For example, you can read what your changes IMMEDIATELY.

That’s it. I wish you can complete this yaml file soon. In my case, I spent couple hours lol…

References