diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0bbb03c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,122 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+#  Usually these files are written by a python script from a packager
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.kitchen
+.kitchen.local.yml
+kitchen.local.yml
+junit-*.xml
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# dotenv
+.env
+
+# virtualenv
+.venv
+venv/
+ENV/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+
+# Bundler
+Gemfile.lock
+
+# copied `.md` files used for conversion to `.rst` using `m2r`
+docs/*.md
+
+# Vim
+*.sw?
+
+## Collected when centralising formulas (check and sort)
+# `collectd-formula`
+.pytest_cache/
+/.idea/
+Dockerfile.*_*
+ignore/
+tmp/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..43180fa
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,122 @@
+# -*- coding: utf-8 -*-
+# vim: ft=yaml
+---
+## Machine config
+os: 'linux'
+arch: 'amd64'
+dist: 'bionic'
+version: '~> 1.0'
+
+## Language and cache config
+language: 'ruby'
+cache: 'bundler'
+
+## Services config
+services:
+  - docker
+
+## Script to run for the test stage
+script:
+  - bin/kitchen verify "${INSTANCE}"
+
+## Stages and jobs matrix
+stages:
+  - test
+  - name: 'release'
+    if: 'branch = master AND type != pull_request'
+jobs:
+  include:
+    ## Define the test stage that runs the linters (and testing matrix, if applicable)
+
+    # Run all of the linters in a single job
+    - language: 'node_js'
+      node_js: 'lts/*'
+      env: 'Lint'
+      name: 'Lint: salt-lint, yamllint, rubocop & commitlint'
+      before_install: 'skip'
+      script:
+        # Install and run `salt-lint`
+        - pip install --user salt-lint
+        - git ls-files | grep '\.sls$\|\.jinja$\|\.j2$\|\.tmpl$\|\.tst$'
+                       | xargs salt-lint
+        # Install and run `yamllint`
+        # Need at least `v1.17.0` for the `yaml-files` setting
+        - pip install --user yamllint>=1.17.0
+        - yamllint -s .
+        # Install and run `rubocop`
+        - gem install rubocop
+        - rubocop -d
+        # Install and run `commitlint`
+        - npm i -D @commitlint/config-conventional
+                   @commitlint/travis-cli
+        - commitlint-travis
+
+    ## 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`
+    # NOTE: Please try to select up to six instances that add some meaningful
+    #       testing of the formula's behaviour. If possible, try to refrain from
+    #       the classical "chosing all the instances because I want to test on
+    #       another/all distro/s" trap: it will just add time to the testing (see
+    #       the discussion on #121).  As an example, the set chosen below covers
+    #       the most used distros families, systemd and non-systemd and the latest
+    #       three supported Saltstack versions with python2 and 3.
+    #       As for `kitchen.yml`, that should still contain all of the platforms,
+    #       to allow for comprehensive local testing
+    #       Ref: https://github.com/saltstack-formulas/template-formula/issues/118
+    #       Ref: https://github.com/saltstack-formulas/template-formula/issues/121
+    - env: INSTANCE=default-debian-10-master-py3
+    # - env: INSTANCE=default-ubuntu-1804-master-py3
+    # - env: INSTANCE=default-centos-8-master-py3
+    # - env: INSTANCE=default-fedora-31-master-py3
+    # - env: INSTANCE=default-opensuse-leap-151-master-py3
+    # - env: INSTANCE=default-amazonlinux-2-master-py2
+    # - env: INSTANCE=default-arch-base-latest-master-py2
+    # - env: INSTANCE=default-debian-10-2019-2-py3
+    # - env: INSTANCE=default-debian-9-2019-2-py3
+    - env: INSTANCE=default-ubuntu-1804-2019-2-py3
+    # - env: INSTANCE=default-centos-8-2019-2-py3
+    # - env: INSTANCE=default-fedora-31-2019-2-py3
+    # - env: INSTANCE=default-opensuse-leap-151-2019-2-py3
+    # - env: INSTANCE=default-centos-7-2019-2-py2
+    - env: INSTANCE=default-amazonlinux-2-2019-2-py2
+    - env: INSTANCE=default-arch-base-latest-2019-2-py2
+    - env: INSTANCE=default-fedora-30-2018-3-py3
+    # - env: INSTANCE=default-debian-9-2018-3-py2
+    # - env: INSTANCE=default-ubuntu-1604-2018-3-py2
+    # - env: INSTANCE=default-centos-7-2018-3-py2
+    - env: INSTANCE=default-opensuse-leap-151-2018-3-py2
+    # - env: INSTANCE=default-amazonlinux-2-2018-3-py2
+    # - env: INSTANCE=default-arch-base-latest-2018-3-py2
+    # - env: INSTANCE=default-debian-8-2017-7-py2
+    # - env: INSTANCE=default-ubuntu-1604-2017-7-py2
+    - env: INSTANCE=centos6-centos-6-2017-7-py2
+    # - env: INSTANCE=default-fedora-30-2017-7-py2
+    # - env: INSTANCE=default-opensuse-leap-151-2017-7-py2
+    # - env: INSTANCE=default-amazonlinux-2-2017-7-py2
+    # - env: INSTANCE=default-arch-base-latest-2017-7-py2
+
+    ## Define the release stage that runs `semantic-release`
+    - stage: 'release'
+      language: 'node_js'
+      node_js: 'lts/*'
+      env: 'Release'
+      name: 'Run semantic-release inc. file updates to AUTHORS, CHANGELOG & FORMULA'
+      before_install: 'skip'
+      script:
+        # Update `AUTHORS.md`
+        - export MAINTAINER_TOKEN=${GH_TOKEN}
+        - go get github.com/myii/maintainer
+        - maintainer contributor
+
+        # Install all dependencies required for `semantic-release`
+        - npm i -D @semantic-release/changelog@3
+                   @semantic-release/exec@3
+                   @semantic-release/git@7
+      deploy:
+        provider: 'script'
+        # Using deprecated `skip_cleanup` until `cleanup: false` works reliably
+        # cleanup: false
+        skip_cleanup: true
+        # Run `semantic-release`
+        script: 'npx semantic-release@15'
diff --git a/FORMULA b/FORMULA
new file mode 100644
index 0000000..960fd36
--- /dev/null
+++ b/FORMULA
@@ -0,0 +1,9 @@
+name: nfs
+os: Debian, Ubuntu, Raspbian, RedHat, Fedora, CentOS, Suse, openSUSE
+os_family: Debian, RedHat, Suse, Gentoo
+version: 0.1
+release: 1
+minimum_version: 2017.7
+summary: nfs formula
+description: Formula to install and configure nfs server or client
+top_level_dir: nfs
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..5a232b6
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+gem 'kitchen-docker', '>= 2.9'
+gem 'kitchen-inspec', '>= 1.1'
+gem 'kitchen-salt', '>= 0.6.0'
diff --git a/README.md b/README.md
deleted file mode 100644
index a9d5951..0000000
--- a/README.md
+++ /dev/null
@@ -1,36 +0,0 @@
-nfs-formula
-===========
-
-Available states
-================
-
-.. contents::
-    :local:
-
-``nfs.server``
----------------
-
-Install nfs server components
-
-``nfs.client``
----------------
-
-Install nfs client components
-
-``nfs.mount``
----------------
-
-Mount nfs shares via. pillar using the following parameters:
-* mountpoint
-* location
-* opts: default => "vers=3"
-* persist: default => True
-* mkmnt: default => True
-
-``nfs.unmount``
----------------
-
-Unmount nfs shares via. pillar using the following parameters:
-* mountpoint
-* location
-* persist: default => False
diff --git a/bin/kitchen b/bin/kitchen
new file mode 100755
index 0000000..dcfdb4c
--- /dev/null
+++ b/bin/kitchen
@@ -0,0 +1,32 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'kitchen' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require 'pathname'
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
+                                           Pathname.new(__FILE__).realpath)
+
+bundle_binstub = File.expand_path('bundle', __dir__)
+
+if File.file?(bundle_binstub)
+  if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
+    load(bundle_binstub)
+  else
+    abort(
+      'Your `bin/bundle` was not generated by Bundler, '\
+      'so this binstub cannot run.  Replace `bin/bundle` by running '\
+      '`bundle binstubs bundler --force`, then run this command again.'
+    )
+  end
+end
+
+require 'rubygems'
+require 'bundler/setup'
+
+load Gem.bin_path('test-kitchen', 'kitchen')
diff --git a/commitlint.config.js b/commitlint.config.js
new file mode 100644
index 0000000..2f9d1aa
--- /dev/null
+++ b/commitlint.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+    extends: ['@commitlint/config-conventional'],
+};
diff --git a/docs/README.rst b/docs/README.rst
new file mode 100644
index 0000000..bf3021f
--- /dev/null
+++ b/docs/README.rst
@@ -0,0 +1,129 @@
+.. _readme:
+
+nfs-formula
+================
+
+|img_travis| |img_sr|
+
+.. |img_travis| image:: https://travis-ci.com/saltstack-formulas/nfs-formula.svg?branch=master
+   :alt: Travis CI Build Status
+   :scale: 100%
+   :target: https://travis-ci.com/saltstack-formulas/nfs-formula
+.. |img_sr| image:: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
+   :alt: Semantic Release
+   :scale: 100%
+   :target: https://github.com/semantic-release/semantic-release
+
+A SaltStack formula to install and configure nfs server and client.
+
+.. contents:: **Table of Contents**
+
+General notes
+-------------
+
+See the full `SaltStack Formulas installation and usage instructions
+<https://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html>`_.
+
+If you are interested in writing or contributing to formulas, please pay attention to the `Writing Formula Section
+<https://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html#writing-formulas>`_.
+
+If you want to use this formula, please pay attention to the ``FORMULA`` file and/or ``git tag``,
+which contains the currently released version. This formula is versioned according to `Semantic Versioning <http://semver.org/>`_.
+
+See `Formula Versioning Section <https://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html#versioning>`_ for more details.
+
+If you need (non-default) configuration, please pay attention to the ``pillar.example`` file and/or `Special notes`_ section.
+
+Contributing to this repo
+-------------------------
+
+**Commit message formatting is significant!!**
+
+Please see `How to contribute <https://github.com/saltstack-formulas/.github/blob/master/CONTRIBUTING.rst>`_ for more details.
+
+Special notes
+-------------
+
+None
+
+Available states
+----------------
+
+.. contents::
+   :local:
+
+``nfs.server``
+^^^^^^^^^^^^^^
+
+Install nfs server components
+
+``nfs.client``
+^^^^^^^^^^^^^^
+
+Install nfs client components
+
+``nfs.mount``
+^^^^^^^^^^^^^
+
+Mount nfs shares via. pillar using the following parameters:
+
+* mountpoint
+* location
+* opts: default => "vers=3"
+* persist: default => True
+* mkmnt: default => True
+
+``nfs.unmount``
+^^^^^^^^^^^^^^^
+
+Unmount nfs shares via. pillar using the following parameters:
+
+* mountpoint
+* location
+* persist: default => False
+
+Testing
+-------
+
+Linux testing is done with ``kitchen-salt``.
+
+Requirements
+^^^^^^^^^^^^
+
+* Ruby
+* Docker
+
+.. code-block:: bash
+
+   $ gem install bundler
+   $ bundle install
+   $ bin/kitchen test [platform]
+
+Where ``[platform]`` is the platform name defined in ``kitchen.yml``,
+e.g. ``debian-9-2019-2-py3``.
+
+``bin/kitchen converge``
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Creates the docker instance and runs the ``nfs.server`` main state, ready for testing.
+
+``bin/kitchen verify``
+^^^^^^^^^^^^^^^^^^^^^^
+
+Runs the ``inspec`` tests on the actual instance.
+
+``bin/kitchen destroy``
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Removes the docker instance.
+
+``bin/kitchen test``
+^^^^^^^^^^^^^^^^^^^^
+
+Runs all of the stages above in one go: i.e. ``destroy`` + ``converge`` + ``verify`` + ``destroy``.
+
+``bin/kitchen login``
+^^^^^^^^^^^^^^^^^^^^^
+
+Gives you SSH access to the instance for manual testing.
+
diff --git a/kitchen.yml b/kitchen.yml
new file mode 100644
index 0000000..86e1563
--- /dev/null
+++ b/kitchen.yml
@@ -0,0 +1,196 @@
+# -*- coding: utf-8 -*-
+# vim: ft=yaml
+---
+# For help on this file's format, see https://kitchen.ci/
+driver:
+  name: docker
+  use_sudo: false
+  privileged: true
+  run_command: /lib/systemd/systemd
+
+# Make sure the platforms listed below match up with
+# the `env.matrix` instances defined in `.travis.yml`
+platforms:
+  ## SALT `master`
+  - name: debian-10-master-py3
+    driver:
+      image: netmanagers/salt-master-py3:debian-10
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python3 git master
+  - name: ubuntu-1804-master-py3
+    driver:
+      image: netmanagers/salt-master-py3:ubuntu-18.04
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python3 git master
+  - name: centos-8-master-py3
+    driver:
+      image: netmanagers/salt-master-py3:centos-8
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python3 git master
+  - name: fedora-31-master-py3
+    driver:
+      image: netmanagers/salt-master-py3:fedora-31
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python3 git master
+  - name: opensuse-leap-151-master-py3
+    driver:
+      image: netmanagers/salt-master-py3:opensuse-leap-15.1
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python3 git master
+      run_command: /usr/lib/systemd/systemd
+    # Workaround to avoid intermittent failures on `opensuse-leap-15.1`:
+    # => SCP did not finish successfully (255):  (Net::SCP::Error)
+    transport:
+      max_ssh_sessions: 1
+  # Use the `develop` image temporarily until the `master` image is available
+  # Not changing the name to minimise disruption across all of the formulas
+  - name: amazonlinux-2-master-py2
+    driver:
+      image: netmanagers/salt-develop-py2:amazonlinux-2
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python2 git develop
+  - name: arch-base-latest-master-py2
+    driver:
+      image: netmanagers/salt-master-py2:arch-base-latest
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python2 git master
+      run_command: /usr/lib/systemd/systemd
+
+  ## SALT `2019.2`
+  - name: debian-10-2019-2-py3
+    driver:
+      image: netmanagers/salt-2019.2-py3:debian-10
+  - name: debian-9-2019-2-py3
+    driver:
+      image: netmanagers/salt-2019.2-py3:debian-9
+  - name: ubuntu-1804-2019-2-py3
+    driver:
+      image: netmanagers/salt-2019.2-py3:ubuntu-18.04
+  - name: centos-8-2019-2-py3
+    driver:
+      image: netmanagers/salt-2019.2-py3:centos-8
+  - name: fedora-31-2019-2-py3
+    driver:
+      image: netmanagers/salt-2019.2-py3:fedora-31
+  - name: opensuse-leap-151-2019-2-py3
+    driver:
+      image: netmanagers/salt-2019.2-py3:opensuse-leap-15.1
+      run_command: /usr/lib/systemd/systemd
+    # Workaround to avoid intermittent failures on `opensuse-leap-15.1`:
+    # => SCP did not finish successfully (255):  (Net::SCP::Error)
+    transport:
+      max_ssh_sessions: 1
+  - name: centos-7-2019-2-py2
+    driver:
+      image: netmanagers/salt-2019.2-py2:centos-7
+  - name: amazonlinux-2-2019-2-py2
+    driver:
+      image: netmanagers/salt-2019.2-py2:amazonlinux-2
+  - name: arch-base-latest-2019-2-py2
+    driver:
+      image: netmanagers/salt-2019.2-py2:arch-base-latest
+      run_command: /usr/lib/systemd/systemd
+
+  ## SALT `2018.3`
+  - name: fedora-30-2018-3-py3
+    driver:
+      image: netmanagers/salt-2018.3-py3:fedora-30
+  - name: debian-9-2018-3-py2
+    driver:
+      image: netmanagers/salt-2018.3-py2:debian-9
+  - name: ubuntu-1604-2018-3-py2
+    driver:
+      image: netmanagers/salt-2018.3-py2:ubuntu-16.04
+  - name: centos-7-2018-3-py2
+    driver:
+      image: netmanagers/salt-2018.3-py2:centos-7
+  - name: opensuse-leap-151-2018-3-py2
+    driver:
+      image: netmanagers/salt-2018.3-py2:opensuse-leap-15.1
+      run_command: /usr/lib/systemd/systemd
+    # Workaround to avoid intermittent failures on `opensuse-leap-15.1`:
+    # => SCP did not finish successfully (255):  (Net::SCP::Error)
+    transport:
+      max_ssh_sessions: 1
+  - name: amazonlinux-2-2018-3-py2
+    driver:
+      image: netmanagers/salt-2018.3-py2:amazonlinux-2
+  - name: arch-base-latest-2018-3-py2
+    driver:
+      image: netmanagers/salt-2018.3-py2:arch-base-latest
+      run_command: /usr/lib/systemd/systemd
+
+  ## SALT `2017.7`
+  - name: debian-8-2017-7-py2
+    driver:
+      image: netmanagers/salt-2017.7-py2:debian-8
+  - name: ubuntu-1604-2017-7-py2
+    driver:
+      image: netmanagers/salt-2017.7-py2:ubuntu-16.04
+  - name: centos-6-2017-7-py2
+    driver:
+      image: netmanagers/salt-2017.7-py2:centos-6
+      run_command: /sbin/init
+  - name: fedora-30-2017-7-py2
+    driver:
+      image: netmanagers/salt-2017.7-py2:fedora-30
+  - name: opensuse-leap-151-2017-7-py2
+    driver:
+      image: netmanagers/salt-2017.7-py2:opensuse-leap-15.1
+      run_command: /usr/lib/systemd/systemd
+    # Workaround to avoid intermittent failures on `opensuse-leap-15.1`:
+    # => SCP did not finish successfully (255):  (Net::SCP::Error)
+    transport:
+      max_ssh_sessions: 1
+  - name: amazonlinux-2-2017-7-py2
+    driver:
+      image: netmanagers/salt-2017.7-py2:amazonlinux-2
+  - name: arch-base-latest-2017-7-py2
+    driver:
+      image: netmanagers/salt-2017.7-py2:arch-base-latest
+      run_command: /usr/lib/systemd/systemd
+
+provisioner:
+  name: salt_solo
+  log_level: debug
+  salt_install: none
+  require_chef: false
+  formula: nfs
+  salt_copy_filter:
+    - .kitchen
+    - .git
+
+verifier:
+  # https://www.inspec.io/
+  name: inspec
+  sudo: true
+  # cli, documentation, html, progress, json, json-min, json-rspec, junit
+  reporter:
+    - cli
+
+suites:
+  - name: default
+    excludes:
+      - centos-6-2017-7-py2
+    provisioner:
+      state_top:
+        base:
+          '*':
+            - nfs.server
+      pillars:
+        top.sls:
+          base:
+            '*':
+              - nfs
+      pillars_from_files:
+        nfs.sls: pillar.example
+    verifier:
+      inspec_tests:
+        - path: test/integration/default
diff --git a/pre-commit_semantic-release.sh b/pre-commit_semantic-release.sh
new file mode 100755
index 0000000..9d34d74
--- /dev/null
+++ b/pre-commit_semantic-release.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+###############################################################################
+# (A) Update `FORMULA` with `${nextRelease.version}`
+###############################################################################
+sed -i -e "s_^\(version:\).*_\1 ${1}_" FORMULA
+
+
+###############################################################################
+# (B) Use `m2r` to convert automatically produced `.md` docs to `.rst`
+###############################################################################
+
+# Install `m2r`
+sudo -H pip install m2r
+
+# Copy and then convert the `.md` docs
+cp *.md docs/
+cd docs/
+m2r --overwrite *.md
+
+# Change excess `H1` headings to `H2` in converted `CHANGELOG.rst`
+sed -i -e '/^=.*$/s/=/-/g' CHANGELOG.rst
+sed -i -e '1,4s/-/=/g' CHANGELOG.rst
+
+# Use for debugging output, when required
+# cat AUTHORS.rst
+# cat CHANGELOG.rst
+
+# Return back to the main directory
+cd ..
diff --git a/release-rules.js b/release-rules.js
new file mode 100644
index 0000000..c63c850
--- /dev/null
+++ b/release-rules.js
@@ -0,0 +1,18 @@
+// No release is triggered for the types commented out below.
+// Commits using these types will be incorporated into the next release.
+//
+// NOTE: Any changes here must be reflected in `CONTRIBUTING.md`.
+module.exports = [
+  {breaking: true, release: 'major'},
+  // {type: 'build', release: 'patch'},
+  // {type: 'chore', release: 'patch'},
+  // {type: 'ci', release: 'patch'},
+  {type: 'docs', release: 'patch'},
+  {type: 'feat', release: 'minor'},
+  {type: 'fix', release: 'patch'},
+  {type: 'perf', release: 'patch'},
+  {type: 'refactor', release: 'patch'},
+  {type: 'revert', release: 'patch'},
+  {type: 'style', release: 'patch'},
+  {type: 'test', release: 'patch'},
+];
diff --git a/release.config.js b/release.config.js
new file mode 100644
index 0000000..6af7aa8
--- /dev/null
+++ b/release.config.js
@@ -0,0 +1,106 @@
+module.exports = {
+  branch: 'master',
+  plugins: [
+      ['@semantic-release/commit-analyzer', {
+        preset: 'angular',
+        releaseRules: './release-rules.js',
+      }],
+      '@semantic-release/release-notes-generator',
+      ['@semantic-release/changelog', {
+        changelogFile: 'CHANGELOG.md',
+        changelogTitle: '# Changelog',
+      }],
+      ['@semantic-release/exec', {
+        prepareCmd: 'sh ./pre-commit_semantic-release.sh ${nextRelease.version}',
+      }],
+      ['@semantic-release/git', {
+        assets: ['*.md', 'docs/*.rst', 'FORMULA'],
+      }],
+      '@semantic-release/github',
+  ],
+  generateNotes: {
+    preset: 'angular',
+    writerOpts: {
+      // Required due to upstream bug preventing all types being displayed.
+      // Bug: https://github.com/conventional-changelog/conventional-changelog/issues/317
+      // Fix: https://github.com/conventional-changelog/conventional-changelog/pull/410
+      transform: (commit, context) => {
+          const issues = []
+
+          commit.notes.forEach(note => {
+              note.title = `BREAKING CHANGES`
+          })
+
+          // NOTE: Any changes here must be reflected in `CONTRIBUTING.md`.
+          if (commit.type === `feat`) {
+              commit.type = `Features`
+          } else if (commit.type === `fix`) {
+              commit.type = `Bug Fixes`
+          } else if (commit.type === `perf`) {
+              commit.type = `Performance Improvements`
+          } else if (commit.type === `revert`) {
+              commit.type = `Reverts`
+          } else if (commit.type === `docs`) {
+              commit.type = `Documentation`
+          } else if (commit.type === `style`) {
+              commit.type = `Styles`
+          } else if (commit.type === `refactor`) {
+              commit.type = `Code Refactoring`
+          } else if (commit.type === `test`) {
+              commit.type = `Tests`
+          } else if (commit.type === `build`) {
+              commit.type = `Build System`
+          // } else if (commit.type === `chore`) {
+          //     commit.type = `Maintenance`
+          } else if (commit.type === `ci`) {
+              commit.type = `Continuous Integration`
+          } else {
+              return
+          }
+
+          if (commit.scope === `*`) {
+              commit.scope = ``
+          }
+
+          if (typeof commit.hash === `string`) {
+              commit.shortHash = commit.hash.substring(0, 7)
+          }
+
+          if (typeof commit.subject === `string`) {
+              let url = context.repository
+                  ? `${context.host}/${context.owner}/${context.repository}`
+                  : context.repoUrl
+              if (url) {
+                  url = `${url}/issues/`
+                  // Issue URLs.
+                  commit.subject = commit.subject.replace(/#([0-9]+)/g, (_, issue) => {
+                      issues.push(issue)
+                      return `[#${issue}](${url}${issue})`
+                  })
+              }
+              if (context.host) {
+                  // User URLs.
+                  commit.subject = commit.subject.replace(/\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g, (_, username) => {
+                  if (username.includes('/')) {
+                      return `@${username}`
+                  }
+
+                  return `[@${username}](${context.host}/${username})`
+                  })
+              }
+          }
+
+          // remove references that already appear in the subject
+          commit.references = commit.references.filter(reference => {
+              if (issues.indexOf(reference.issue) === -1) {
+                  return true
+              }
+
+              return false
+          })
+
+          return commit
+      },
+    },
+  },
+};
diff --git a/test/integration/default/README.md b/test/integration/default/README.md
new file mode 100644
index 0000000..37cf963
--- /dev/null
+++ b/test/integration/default/README.md
@@ -0,0 +1,50 @@
+# InSpec Profile: `default`
+
+This shows the implementation of the `default` InSpec [profile](https://github.com/inspec/inspec/blob/master/docs/profiles.md).
+
+## Verify a profile
+
+InSpec ships with built-in features to verify a profile structure.
+
+```bash
+$ inspec check default
+Summary
+-------
+Location: default
+Profile: profile
+Controls: 4
+Timestamp: 2019-06-24T23:09:01+00:00
+Valid: true
+
+Errors
+------
+
+Warnings
+--------
+```
+
+## Execute a profile
+
+To run all **supported** controls on a local machine use `inspec exec /path/to/profile`.
+
+```bash
+$ inspec exec default
+..
+
+Finished in 0.0025 seconds (files took 0.12449 seconds to load)
+8 examples, 0 failures
+```
+
+## Execute a specific control from a profile
+
+To run one control from the profile use `inspec exec /path/to/profile --controls name`.
+
+```bash
+$ inspec exec default --controls package
+.
+
+Finished in 0.0025 seconds (files took 0.12449 seconds to load)
+1 examples, 0 failures
+```
+
+See an [example control here](https://github.com/inspec/inspec/blob/master/examples/profile/controls/example.rb).
diff --git a/test/integration/default/inspec.yml b/test/integration/default/inspec.yml
new file mode 100644
index 0000000..ab4e700
--- /dev/null
+++ b/test/integration/default/inspec.yml
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+# vim: ft=yaml
+---
+name: default
+title: nfs formula
+maintainer: SaltStack Formulas
+license: Apache-2.0
+summary: Verify that the nfs formula is setup and configured correctly
+supports:
+  - platform-name: debian
+  - platform-name: ubuntu
+  - platform-name: centos
+  - platform-name: fedora
+  - platform-name: opensuse
+  - platform-name: suse
+  - platform-name: freebsd
+  - platform-name: amazon
+  - platform-name: arch