diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..975482394de7d3f0442d95771ac295a2dfe5e0cc
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,152 @@
+# -*- coding: utf-8 -*-
+# vim: ft=yaml
+---
+###############################################################################
+# Define all YAML node anchors
+###############################################################################
+.node_anchors:
+  # `only` (also used for `except` where applicable)
+  only_branch_master_parent_repo: &only_branch_master_parent_repo
+    - 'master@saltstack-formulas/salt-formula'
+  # `stage`
+  stage_lint: &stage_lint 'lint'
+  stage_release: &stage_release 'release'
+  stage_test: &stage_test 'test'
+  # `image`
+  image_commitlint: &image_commitlint 'myii/ssf-commitlint:11'
+  image_dindruby: &image_dindruby 'myii/ssf-dind-ruby:2.7.1-r3'
+  image_precommit: &image_precommit
+    name: 'myii/ssf-pre-commit:2.9.2'
+    entrypoint: ['/bin/bash', '-c']
+  image_semantic-release: &image_semanticrelease 'myii/ssf-semantic-release:15.14'
+  # `services`
+  services_docker_dind: &services_docker_dind
+    - 'docker:dind'
+  # `variables`
+  # https://forum.gitlab.com/t/gitlab-com-ci-caching-rubygems/5627/3
+  # https://bundler.io/v1.16/bundle_config.html
+  variables_bundler: &variables_bundler
+    BUNDLE_CACHE_PATH: '${CI_PROJECT_DIR}/.cache/bundler'
+    BUNDLE_WITHOUT: 'production'
+  # `cache`
+  cache_bundler: &cache_bundler
+    key: '${CI_JOB_STAGE}'
+    paths:
+      - '${BUNDLE_CACHE_PATH}'
+
+###############################################################################
+# Define stages and global variables
+###############################################################################
+stages:
+  - *stage_lint
+  - *stage_test
+  - *stage_release
+variables:
+  DOCKER_DRIVER: 'overlay2'
+
+###############################################################################
+# `lint` stage: `commitlint` & `pre-commit`
+###############################################################################
+commitlint:
+  stage: *stage_lint
+  image: *image_commitlint
+  script:
+    # Add `upstream` remote to get access to `upstream/master`
+    - 'git remote add upstream ${CI_PROJECT_URL}.git'
+    - 'git fetch --all'
+    # Set default commit hashes for `--from` and `--to`
+    - 'export COMMITLINT_FROM="$(git merge-base upstream/master HEAD)"'
+    - 'export COMMITLINT_TO="${CI_COMMIT_SHA}"'
+    # `coqbot` adds a merge commit to test PRs on top of the latest commit in
+    # the repo; amend this merge commit message to avoid failure
+    - |
+      if [ "${GITLAB_USER_LOGIN}" = "coqbot" ] \
+      && [ "${CI_COMMIT_BRANCH}" != "master" ]; then
+        git commit --amend -m \
+          'chore: reword coqbot merge commit message for commitlint'
+        export COMMITLINT_TO=HEAD
+      fi
+    # Run `commitlint`
+    - 'commitlint --from "${COMMITLINT_FROM}"
+                  --to   "${COMMITLINT_TO}"
+                  --verbose'
+
+pre-commit:
+  stage: *stage_lint
+  image: *image_precommit
+  # https://pre-commit.com/#gitlab-ci-example
+  variables:
+    PRE_COMMIT_HOME: '${CI_PROJECT_DIR}/.cache/pre-commit'
+  cache:
+    key: '${CI_JOB_NAME}'
+    paths:
+      - '${PRE_COMMIT_HOME}'
+  script:
+    - 'pre-commit run --all-files --color always --verbose'
+
+###############################################################################
+# Define `test` template
+###############################################################################
+.test_instance:
+  stage: *stage_test
+  image: *image_dindruby
+  services: *services_docker_dind
+  variables: *variables_bundler
+  cache: *cache_bundler
+  before_script:
+    # TODO: This should work from the env vars above automatically
+    - 'bundle config set path "${BUNDLE_CACHE_PATH}"'
+    - 'bundle config set without "${BUNDLE_WITHOUT}"'
+    - 'bundle install'
+  script:
+    # Alternative value to consider: `${CI_JOB_NAME}`
+    - 'bin/kitchen verify "${DOCKER_ENV_CI_JOB_NAME}"'
+
+###############################################################################
+# `test` stage: each instance below uses the `test` template above
+###############################################################################
+## Define the rest of the matrix based on Kitchen testing
+# Make sure the instances listed below match up with
+# the `platforms` defined in `kitchen.yml`
+v3001-py3-debian-10-3001-py3: {extends: '.test_instance'}
+# v3001-py3-debian-9-3001-py3: {extends: '.test_instance'}
+v3001-py3-ubuntu-2004-3001-py3: {extends: '.test_instance'}
+# v3001-py3-ubuntu-1804-3001-py3: {extends: '.test_instance'}
+v3001-py3-centos-8-3001-py3: {extends: '.test_instance'}
+# v3001-py3-centos-7-3001-py3: {extends: '.test_instance'}
+v3001-py3-fedora-32-3001-py3: {extends: '.test_instance'}
+# v3001-py3-fedora-31-3001-py3: {extends: '.test_instance'}
+# v3001-py3-opensuse-leap-152-3001-py3: {extends: '.test_instance'}
+# v3001-py3-amazonlinux-2-3001-py3: {extends: '.test_instance'}
+v3001-py3-oraclelinux-8-3001-py3: {extends: '.test_instance'}
+# v3001-py3-oraclelinux-7-3001-py3: {extends: '.test_instance'}
+v3001-py3-gentoo-stage3-latest-3001-py3: {extends: '.test_instance'}
+v3001-py3-gentoo-stage3-systemd-3001-py3: {extends: '.test_instance'}
+# v3000-py3-debian-10-3000-3-py3: {extends: '.test_instance'}
+# v3000-py3-debian-9-3000-3-py3: {extends: '.test_instance'}
+# v3000-py3-ubuntu-1804-3000-3-py3: {extends: '.test_instance'}
+# v3000-py3-centos-8-3000-3-py3: {extends: '.test_instance'}
+# v3000-py3-centos-7-3000-3-py3: {extends: '.test_instance'}
+v3000-py3-opensuse-leap-152-3000-3-py3: {extends: '.test_instance'}
+v3000-py3-amazonlinux-2-3000-3-py3: {extends: '.test_instance'}
+# v3000-py3-oraclelinux-8-3000-3-py3: {extends: '.test_instance'}
+v3000-py3-oraclelinux-7-3000-3-py3: {extends: '.test_instance'}
+v3000-py2-ubuntu-1804-3000-3-py2: {extends: '.test_instance'}
+# v3000-py2-ubuntu-1604-3000-3-py2: {extends: '.test_instance'}
+# v3000-py3-gentoo-stage3-latest-3000-3-py3: {extends: '.test_instance'}
+# v3000-py3-gentoo-stage3-systemd-3000-3-py3: {extends: '.test_instance'}
+
+###############################################################################
+# `release` stage: `semantic-release`
+###############################################################################
+semantic-release:
+  only: *only_branch_master_parent_repo
+  stage: *stage_release
+  image: *image_semanticrelease
+  variables:
+    MAINTAINER_TOKEN: '${GH_TOKEN}'
+  script:
+    # Update `AUTHORS.md`
+    - '${HOME}/go/bin/maintainer contributor'
+    # Run `semantic-release`
+    - 'semantic-release'
diff --git a/.travis.yml b/.travis.yml
index 6eacb04cf3ded7f3646569a477c0839b5690dc1c..99dcd8b49cfd7e103e442ef834b6976878161279 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,15 @@
 # -*- coding: utf-8 -*-
 # vim: ft=yaml
 ---
+################################################################################
+# NOTE: This file is UNMAINTAINED; it is provided for references purposes only.
+#       No guarantees are tendered that this structure will work after 2020.
+################################################################################
+# * https://en.wikipedia.org/wiki/Travis_CI:
+#   - "... free open-source plans were removed in [sic] the end of 2020"
+#   - https://blog.travis-ci.com/2020-11-02-travis-ci-new-billing
+#   - https://ropensci.org/technotes/2020/11/19/moving-away-travis/
+################################################################################
 ## Machine config
 os: 'linux'
 arch: 'amd64'
@@ -22,8 +31,10 @@ script:
 ## Stages and jobs matrix
 stages:
   - test
-  - name: 'release'
-    if: 'branch = master AND type != pull_request'
+  # # As part of the switch away from Travis CI, ensure that the `release` stage
+  # # is not run inadvertently
+  # - name: 'release'
+  #   if: 'branch = master AND type != pull_request'
 jobs:
   include:
     ## Define the test stage that runs the linters (and testing matrix, if applicable)
@@ -91,7 +102,6 @@ jobs:
     # - env: INSTANCE=v3000-py3-ubuntu-1804-3000-3-py3
     # - env: INSTANCE=v3000-py3-centos-8-3000-3-py3
     # - env: INSTANCE=v3000-py3-centos-7-3000-3-py3
-    - env: INSTANCE=v3000-py3-fedora-31-3000-3-py3
     - env: INSTANCE=v3000-py3-opensuse-leap-152-3000-3-py3
     - env: INSTANCE=v3000-py3-amazonlinux-2-3000-3-py3
     # - env: INSTANCE=v3000-py3-oraclelinux-8-3000-3-py3
@@ -100,17 +110,6 @@ jobs:
     # - env: INSTANCE=v3000-py2-ubuntu-1604-3000-3-py2
     # - env: INSTANCE=v3000-py3-gentoo-stage3-latest-3000-3-py3
     # - env: INSTANCE=v3000-py3-gentoo-stage3-systemd-3000-3-py3
-    # - env: INSTANCE=v201902-py3-debian-10-2019-2-py3
-    - env: INSTANCE=v201902-py3-debian-9-2019-2-py3
-    # - env: INSTANCE=v201902-py3-ubuntu-1804-2019-2-py3
-    - env: INSTANCE=v201902-py3-ubuntu-1604-2019-2-py3
-    # - env: INSTANCE=v201902-py3-centos-8-2019-2-py3
-    - env: INSTANCE=v201902-py3-centos-7-2019-2-py3
-    # - env: INSTANCE=v201902-py3-fedora-31-2019-2-py3
-    # - env: INSTANCE=v201902-py3-opensuse-leap-152-2019-2-py3
-    # - env: INSTANCE=v201902-py3-amazonlinux-2-2019-2-py3
-    - env: INSTANCE=v201902-py2-centos-6-2019-2-py2
-    # - env: INSTANCE=v201902-py2-amazonlinux-1-2019-2-py2
 
     ## Define the release stage that runs `semantic-release`
     - stage: 'release'
diff --git a/.yamllint b/.yamllint
index 9470339f4612e9e7c168d4fd6a61d4363e88d108..34ee0e36ad8890153a52a79769d57145a63b2f00 100644
--- a/.yamllint
+++ b/.yamllint
@@ -10,6 +10,7 @@ extends: default
 # 3. Any YAML files under directory `.kitchen/`, introduced during local testing
 # 4. All YAML files heavily reliant on Jinja; these can be tackled in a subsequent PR
 ignore: |
+  .cache/
   node_modules/
   test/**/states/**/*.sls
   .kitchen/
diff --git a/CODEOWNERS b/CODEOWNERS
index 9952e94ae8379ababe2918868e1afe786697c04d..b2f3e714ce104192e3f1ecc16de95826bd6e2e53 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -16,12 +16,13 @@
 /docs/AUTHORS.rst                           @saltstack-formulas/ssf
 /docs/CHANGELOG.rst                         @saltstack-formulas/ssf
 /docs/TOFS_pattern.rst                      @saltstack-formulas/ssf
-/salt/libsaltcli.jinja                      @saltstack-formulas/ssf
-/salt/libtofs.jinja                         @saltstack-formulas/ssf
+/*/libsaltcli.jinja                         @saltstack-formulas/ssf
+/*/libtofs.jinja                            @saltstack-formulas/ssf
 /test/integration/**/inspec.yml             @saltstack-formulas/ssf
 /test/integration/**/README.md              @saltstack-formulas/ssf
 /.gitignore                                 @saltstack-formulas/ssf
 /.cirrus.yml                                @saltstack-formulas/ssf
+/.gitlab-ci.yml                             @saltstack-formulas/ssf
 /.pre-commit-config.yaml                    @saltstack-formulas/ssf
 /.rstcheck.cfg                              @saltstack-formulas/ssf
 /.rubocop.yml                               @saltstack-formulas/ssf
diff --git a/kitchen.yml b/kitchen.yml
index 46a99ce39976f9197bf89e9ac391fb2b3401a1d4..d7519ceba0c6b0c58ffd663b06756f118aae2a7c 100644
--- a/kitchen.yml
+++ b/kitchen.yml
@@ -77,9 +77,6 @@ platforms:
   - name: centos-7-3000-3-py3
     driver:
       image: saltimages/salt-3000.3-py3:centos-7
-  - name: fedora-31-3000-3-py3
-    driver:
-      image: saltimages/salt-3000.3-py3:fedora-31
   - name: opensuse-leap-152-3000-3-py3
     driver:
       image: saltimages/salt-3000.3-py3:opensuse-leap-15.2
@@ -214,7 +211,6 @@ suites:
       - ubuntu-1804-3000-3-py3
       - centos-8-3000-3-py3
       - centos-7-3000-3-py3
-      - fedora-31-3000-3-py3
       - opensuse-leap-152-3000-3-py3
       - amazonlinux-2-3000-3-py3
       - oraclelinux-8-3000-3-py3
@@ -263,56 +259,3 @@ suites:
     verifier:
       inspec_tests:
         - path: test/integration/v3000-py2
-  - name: v201902-py3
-    includes:
-      - debian-10-2019-2-py3
-      - debian-9-2019-2-py3
-      - ubuntu-1804-2019-2-py3
-      - ubuntu-1604-2019-2-py3
-      - centos-8-2019-2-py3
-      - centos-7-2019-2-py3
-      - fedora-31-2019-2-py3
-      - opensuse-leap-152-2019-2-py3
-      - amazonlinux-2-2019-2-py3
-    provisioner:
-      state_top:
-        base:
-          '*':
-            - salt.pkgrepo
-            - salt.master
-            - salt.minion
-      pillars:
-        top.sls:
-          base:
-            '*':
-              - salt
-              - v201902-py3
-      pillars_from_files:
-        salt.sls: test/salt/pillar/salt.sls
-        v201902-py3.sls: test/salt/pillar/v201902-py3.sls
-    verifier:
-      inspec_tests:
-        - path: test/integration/v201902-py3
-  - name: v201902-py2
-    includes:
-      - centos-6-2019-2-py2
-      - amazonlinux-1-2019-2-py2
-    provisioner:
-      state_top:
-        base:
-          '*':
-            - salt.pkgrepo
-            - salt.master
-            - salt.minion
-      pillars:
-        top.sls:
-          base:
-            '*':
-              - salt
-              - v201902-py2
-      pillars_from_files:
-        salt.sls: test/salt/pillar/salt.sls
-        v201902-py2.sls: test/salt/pillar/v201902-py2.sls
-    verifier:
-      inspec_tests:
-        - path: test/integration/v201902-py2
diff --git a/pre-commit_semantic-release.sh b/pre-commit_semantic-release.sh
index ba8053520b2795e3cc870440537a2e388f73d5fa..458b7b649cd0de1ca91b446cf9de26e00ab0d87d 100755
--- a/pre-commit_semantic-release.sh
+++ b/pre-commit_semantic-release.sh
@@ -11,7 +11,7 @@ sed -i -e "s_^\(version:\).*_\1 ${1}_" FORMULA
 ###############################################################################
 
 # Install `m2r`
-sudo -H pip install m2r
+pip3 install m2r
 
 # Copy and then convert the `.md` docs
 cp ./*.md docs/
diff --git a/release.config.js b/release.config.js
index 6af7aa8f046665bd6128abae3afa7c030a7c1301..c508402008018491f91bc720d78e0ad0e7c4d39f 100644
--- a/release.config.js
+++ b/release.config.js
@@ -1,5 +1,6 @@
 module.exports = {
   branch: 'master',
+  repositoryUrl: 'https://github.com/saltstack-formulas/salt-formula',
   plugins: [
       ['@semantic-release/commit-analyzer', {
         preset: 'angular',