From 1d2e2f59dd5d2d051eef065fb516b03f0eccbfbf Mon Sep 17 00:00:00 2001
From: Imran Iqbal <iqbalmy@hotmail.com>
Date: Sat, 6 Jul 2019 10:46:03 +0100
Subject: [PATCH] feat(semantic-release): implement for this formula

* Include latest pre-salted images replacing EOL platforms
  - Ref: https://github.com/saltstack-formulas/template-formula/pull/148
---
 .gitignore                                    | 115 +++++++++-
 .kitchen.docker.yml                           |   6 -
 .kitchen.yml                                  |  31 ---
 .travis.yml                                   |  88 ++++++--
 FORMULA                                       |   1 +
 Gemfile                                       |  20 +-
 Rakefile                                      |  31 ---
 bin/kitchen                                   |  29 +++
 commitlint.config.js                          |   3 +
 docs/CONTRIBUTING.rst                         | 158 +++++++++++++
 README.rst => docs/README.rst                 | 114 ++++++++--
 kitchen.yml                                   | 149 ++++++++++++
 mysql/defaults.yaml                           |   4 +
 mysql/salt-user.sls                           |   6 +-
 pre-commit_semantic-release.sh                |  30 +++
 release-rules.js                              |  18 ++
 release.config.js                             | 106 +++++++++
 test/integration/default/README.md            |  50 ++++
 .../default/controls/packages_spec.rb         |  15 ++
 test/integration/default/inspec.yml           |  12 +
 test/salt/pillar/mysql.sls                    | 213 ++++++++++++++++++
 21 files changed, 1072 insertions(+), 127 deletions(-)
 delete mode 100644 .kitchen.docker.yml
 delete mode 100644 .kitchen.yml
 delete mode 100644 Rakefile
 create mode 100755 bin/kitchen
 create mode 100644 commitlint.config.js
 create mode 100644 docs/CONTRIBUTING.rst
 rename README.rst => docs/README.rst (58%)
 create mode 100644 kitchen.yml
 create mode 100755 pre-commit_semantic-release.sh
 create mode 100644 release-rules.js
 create mode 100644 release.config.js
 create mode 100644 test/integration/default/README.md
 create mode 100644 test/integration/default/controls/packages_spec.rb
 create mode 100644 test/integration/default/inspec.yml
 create mode 100644 test/salt/pillar/mysql.sls

diff --git a/.gitignore b/.gitignore
index 7715275..ba07ed8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,113 @@
-*.pyc
-*~
+# 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
+
+# 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
-.kitchen/
+
+# copied `.md` files used for conversion to `.rst` using `m2r`
+docs/*.md
+
+# Vim
+*.sw?
diff --git a/.kitchen.docker.yml b/.kitchen.docker.yml
deleted file mode 100644
index f6c458a..0000000
--- a/.kitchen.docker.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-driver:
-  name: docker
-  hostname: salt-formula.ci.local
-  use_sudo: true
-  require_chef_omnibus: false
diff --git a/.kitchen.yml b/.kitchen.yml
deleted file mode 100644
index b7ac9f4..0000000
--- a/.kitchen.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-<%
-require 'yaml'
-
-formula = YAML.load_file('FORMULA')
-formula_name = formula['name']
-%>
----
-verifier:
-  name: inspec
-
-platforms:
-  - name: ubuntu-16.04
-  - name: ubuntu-18.04
-  - name: debian-9
-  - name: centos-7
-
-provisioner:
-  name: salt_solo
-  salt_install: bootstrap
-  salt_bootstrap_url: https://bootstrap.saltstack.com
-  salt_version: latest
-  salt_pillar_root: pillar.example
-  log_level: <%= ENV['SALT_DEBUG_LEVEL'] || 'info' %>
-  formula: <%= formula_name %>
-  state_top:
-    base:
-      '*':
-        - <%= formula_name %>
-
-suites:
-  - name: default
diff --git a/.travis.yml b/.travis.yml
index 37ac9e4..e26d989 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,26 +1,78 @@
-language: ruby
-
-rvm:
-  - 2.2.5
+stages:
+  - test
+  - commitlint
+  - name: release
+    if: branch = master AND type != pull_request
 
 sudo: required
-services: docker
+cache: bundler
+language: ruby
+dist: xenial
 
+services:
+  - docker
+
+# Make sure the instances listed below match up with
+# the `platforms` defined in `kitchen.yml`
 env:
   matrix:
-  - INSTANCE=default-ubuntu-1604
-  - INSTANCE=default-ubuntu-1804
-  - INSTANCE=default-debian-9
-  - INSTANCE=centos-7
+    - INSTANCE: default-debian-10-develop-py3
+    - INSTANCE: default-ubuntu-1804-develop-py3
+    # - INSTANCE: default-centos-7-develop-py3
+    # - INSTANCE: default-fedora-30-develop-py3
+    # - INSTANCE: default-opensuse-leap-15-develop-py3
+    # - INSTANCE: default-amazonlinux-2-develop-py2
+    - INSTANCE: default-debian-9-2019-2-py3
+    - INSTANCE: default-ubuntu-1804-2019-2-py3
+    # - INSTANCE: default-centos-7-2019-2-py3
+    # - INSTANCE: default-fedora-30-2019-2-py3
+    # - INSTANCE: default-opensuse-leap-15-2019-2-py3
+    # - INSTANCE: default-amazonlinux-2-2019-2-py2
+    - INSTANCE: default-debian-9-2018-3-py2
+    # - INSTANCE: default-ubuntu-1604-2018-3-py2
+    # - INSTANCE: default-centos-7-2018-3-py2
+    # - INSTANCE: default-fedora-29-2018-3-py2
+    # - INSTANCE: default-opensuse-leap-15-2018-3-py2
+    # - INSTANCE: default-amazonlinux-2-2018-3-py2
+    - INSTANCE: default-debian-8-2017-7-py2
+    # - INSTANCE: default-ubuntu-1604-2017-7-py2
+    # - INSTANCE: default-centos-6-2017-7-py2
+    # - INSTANCE: default-fedora-29-2017-7-py2
+    # - INSTANCE: default-opensuse-leap-15-2017-7-py2
+    # - INSTANCE: default-amazonlinux-2-2017-7-py2
 
-# https://github.com/zuazo/kitchen-in-travis-native/issues/1#issuecomment-142455888
-before_script: sudo iptables -L DOCKER || sudo iptables -N DOCKER
+script:
+  - bundle exec kitchen verify ${INSTANCE}
 
-install:
-  # setup ci for test formula
-  - export BUNDLE_GEMFILE=$PWD/Gemfile
-  - bundle install
+jobs:
+  include:
+    # Define the commitlint stage
+    - stage: commitlint
+      language: node_js
+      node_js: lts/*
+      before_install: skip
+      script:
+        - npm install @commitlint/config-conventional -D
+        - npm install @commitlint/travis-cli -D
+        - commitlint-travis
+    # Define the release stage that runs semantic-release
+    - stage: release
+      language: node_js
+      node_js: lts/*
+      before_install: skip
+      script:
+        # Update `AUTHORS.md`
+        - export MAINTAINER_TOKEN=${GH_TOKEN}
+        - go get github.com/myii/maintainer
+        - maintainer contributor
 
-script:
-  # Run unit tests
-  - KITCHEN_LOCAL_YAML=.kitchen.docker.yml bundle exec kitchen verify ${INSTANCE}
+        # Install all dependencies required for `semantic-release`
+        - npm install @semantic-release/changelog@3 -D
+        - npm install @semantic-release/exec@3 -D
+        - npm install @semantic-release/git@7 -D
+      deploy:
+        provider: script
+        skip_cleanup: true
+        script:
+          # Run `semantic-release`
+          - npx semantic-release@15
diff --git a/FORMULA b/FORMULA
index ebf0129..0a2f4ce 100644
--- a/FORMULA
+++ b/FORMULA
@@ -6,3 +6,4 @@ release: 1
 minimum_version: 2015.8
 summary: Formula for installing MySQL
 description: Formula for installing MySQL database client and/or server
+top_level_dir: mysql
diff --git a/Gemfile b/Gemfile
index f74e267..3b36de3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,18 +1,6 @@
-source 'https://rubygems.org'
+source "https://rubygems.org"
 
-gem 'codeclimate-test-reporter', group: :test, require: nil
-gem 'rake'
-gem 'berkshelf', '~> 4.0'
+gem 'kitchen-docker', '>= 2.9'
+gem 'kitchen-salt', '>= 0.6.0'
+gem 'kitchen-inspec', '>= 1.1'
 
-group :integration do
-  gem 'test-kitchen'
-  gem 'kitchen-salt'
-  gem 'kitchen-inspec'
-end
-
-group :docker do
-  gem 'kitchen-docker'
-end
-
-# vi: set ft=ruby :
-gem "kitchen-vagrant"
diff --git a/Rakefile b/Rakefile
deleted file mode 100644
index 2a6eafb..0000000
--- a/Rakefile
+++ /dev/null
@@ -1,31 +0,0 @@
-require 'rake'
-require 'rake/testtask'
-require 'bundler/setup'
-
-Rake::TestTask.new do |t|
-  t.libs << 'lib'
-  t.pattern = 'test/**/*_test.rb'
-  t.verbose = false
-end
-
-desc 'Run Test Kitchen integration tests'
-namespace :integration do
-  desc 'Run integration tests with kitchen-docker'
-  task :docker do
-    require 'kitchen'
-    Kitchen.logger = Kitchen.default_file_logger
-    @loader = Kitchen::Loader::YAML.new(local_config: '.kitchen.docker.yml')
-    Kitchen::Config.new(loader: @loader).instances.each do |instance|
-      instance.test(:always)
-    end
-  end
-end
-
-task default: :test
-
-begin
-  require 'kitchen/rake_tasks'
-  Kitchen::RakeTasks.new
-rescue LoadError
-  puts '>>>>> Kitchen gem not loaded, omitting tasks' unless ENV['CI']
-end
diff --git a/bin/kitchen b/bin/kitchen
new file mode 100755
index 0000000..1cd44f3
--- /dev/null
+++ b/bin/kitchen
@@ -0,0 +1,29 @@
+#!/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", __FILE__)
+
+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/CONTRIBUTING.rst b/docs/CONTRIBUTING.rst
new file mode 100644
index 0000000..5da9ae8
--- /dev/null
+++ b/docs/CONTRIBUTING.rst
@@ -0,0 +1,158 @@
+.. _contributing:
+
+How to contribute
+=================
+
+This document will eventually outline all aspects of guidance to make your contributing experience a fruitful and enjoyable one.
+What it already contains is information about *commit message formatting* and how that directly affects the numerous automated processes that are used for this repo.
+It also covers how to contribute to this *formula's documentation*.
+
+.. contents:: **Table of Contents**
+
+Overview
+--------
+
+Submitting a pull request is more than just code!
+To achieve a quality product, the *tests* and *documentation* need to be updated as well.
+An excellent pull request will include these in the changes, wherever relevant.
+
+Commit message formatting
+-------------------------
+
+Since every type of change requires making Git commits,
+we will start by covering the importance of ensuring that all of your commit
+messages are in the correct format.
+
+Automation of multiple processes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This formula uses `semantic-release <https://github.com/semantic-release/semantic-release>`_ for automating numerous processes such as bumping the version number appropriately, creating new tags/releases and updating the changelog.
+The entire process relies on the structure of commit messages to determine the version bump, which is then used for the rest of the automation.
+
+Full details are available in the upstream docs regarding the `Angular Commit Message Conventions <https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines>`_.
+The key factor is that the first line of the commit message must follow this format:
+
+.. code-block::
+
+   type(scope): subject
+
+
+* E.g. ``docs(contributing): add commit message formatting instructions``.
+
+Besides the version bump, the changelog and release notes are formatted accordingly.
+So based on the example above:
+
+..
+
+   .. raw:: html
+
+      <h3>Documentation</h3>
+
+   * **contributing:** add commit message formatting instructions
+
+
+* The ``type`` translates into a ``Documentation`` sub-heading.
+* The ``(scope):`` will be shown in bold text without the brackets.
+* The ``subject`` follows the ``scope`` as standard text.
+
+Linting commit messages in Travis CI
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This formula uses `commitlint <https://github.com/conventional-changelog/commitlint>`_ for checking commit messages during CI testing.
+This ensures that they are in accordance with the ``semantic-release`` settings.
+
+For more details about the default settings, refer back to the ``commitlint`` `reference rules <https://conventional-changelog.github.io/commitlint/#/reference-rules>`_.
+
+Relationship between commit type and version bump
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This formula applies some customisations to the defaults, as outlined in the table below,
+based upon the `type <https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#type>`_ of the commit:
+
+.. list-table::
+   :name: commit-type-vs-version-bump
+   :header-rows: 1
+   :stub-columns: 0
+   :widths: 1,2,3,1,1
+
+   * - Type
+     - Heading
+     - Description
+     - Bump (default)
+     - Bump (custom)
+   * - ``build``
+     - Build System
+     - Changes related to the build system
+     - –
+     -
+   * - ``chore``
+     - –
+     - Changes to the build process or auxiliary tools and libraries such as
+       documentation generation
+     - –
+     -
+   * - ``ci``
+     - Continuous Integration
+     - Changes to the continuous integration configuration
+     - –
+     -
+   * - ``docs``
+     - Documentation
+     - Documentation only changes
+     - –
+     - 0.0.1
+   * - ``feat``
+     - Features
+     - A new feature
+     - 0.1.0
+     -
+   * - ``fix``
+     - Bug Fixes
+     - A bug fix
+     - 0.0.1
+     -
+   * - ``perf``
+     - Performance Improvements
+     - A code change that improves performance
+     - 0.0.1
+     -
+   * - ``refactor``
+     - Code Refactoring
+     - A code change that neither fixes a bug nor adds a feature
+     - –
+     - 0.0.1
+   * - ``revert``
+     - Reverts
+     - A commit used to revert a previous commit
+     - –
+     - 0.0.1
+   * - ``style``
+     - Styles
+     - Changes that do not affect the meaning of the code (white-space,
+       formatting, missing semi-colons, etc.)
+     - –
+     - 0.0.1
+   * - ``test``
+     - Tests
+     - Adding missing or correcting existing tests
+     - –
+     - 0.0.1
+
+Use ``BREAKING CHANGE`` to trigger a ``major`` version change
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Adding ``BREAKING CHANGE`` to the footer of the extended description of the commit message will **always** trigger a ``major`` version change, no matter which type has been used.
+This will be appended to the changelog and release notes as well.
+To preserve good formatting of these notes, the following format is prescribed:
+
+* ``BREAKING CHANGE: <explanation in paragraph format>.``
+
+An example of that:
+
+.. code-block:: git
+
+   ...
+
+   BREAKING CHANGE: With the removal of all of the `.sls` files under
+   `template package`, this formula no longer supports the installation of
+   packages.
diff --git a/README.rst b/docs/README.rst
similarity index 58%
rename from README.rst
rename to docs/README.rst
index 3944815..e21d996 100644
--- a/README.rst
+++ b/docs/README.rst
@@ -1,42 +1,72 @@
-=====
+.. _readme:
+
 mysql
 =====
 
+|img_travis| |img_sr|
+
+.. |img_travis| image:: https://travis-ci.com/saltstack-formulas/mysql-formula.svg?branch=master
+   :alt: Travis CI Build Status
+   :scale: 100%
+   :target: https://travis-ci.com/saltstack-formulas/mysql-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
+
 Install the MySQL client and/or server on Linux and MacOS.
 
-.. note::
+.. 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 the full `Salt Formulas installation and usage instructions
-   <http://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html>`_.
+See `Formula Versioning Section <https://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html#versioning>`_ for more details.
+
+Contributing to this repo
+-------------------------
+
+**Commit message formatting is significant!!**
+
+Please see :ref:`How to contribute <CONTRIBUTING>` for more details.
 
 Available states
-================
+----------------
 
 .. contents::
     :local:
 
 ``mysql``
----------
+^^^^^^^^^
 
 Meta-state including all server packages in correct order. This meta-state does **not** include ``mysql.remove_test_database``.
 
 ``mysql.macos``
-----------------
+^^^^^^^^^^^^^^^^
 
 Install "MySQL Community Server", "MySQL Workbench", and other related mysql products on MacOS (and create Desktop shortcuts).
 
 ``mysql.macos.remove``
-----------------
+^^^^^^^^^^^^^^^^
 
 Remove "MySQL Community Server", "MySQL Workbench", and any other enabled products from MacOS.
 
 ``mysql.client``
-----------------
+^^^^^^^^^^^^^^^^
 
 Install the MySQL client package on Linux.
 
 ``mysql.server``
-----------------
+^^^^^^^^^^^^^^^^
 
 Install the MySQL server package and start the service.
 
@@ -52,28 +82,28 @@ Debian OS family supports setting MySQL root password during install via debconf
     newly available ``random.get_str`` method.
 
 ``mysql.server_checks``
------------------------
+^^^^^^^^^^^^^^^^^^^^^^^
 
 Enforces a root password to be set.
 
 
 ``mysql.disabled``
-------------------
+^^^^^^^^^^^^^^^^^^
 
 Ensure that the MySQL service is not running.
 
 ``mysql.database``
-------------------
+^^^^^^^^^^^^^^^^^^
 
 Create and manage MySQL databases.
 
 ``mysql.python``
-----------------
+^^^^^^^^^^^^^^^^
 
 Install mysql python bindings.
 
 ``mysql.user``
---------------
+^^^^^^^^^^^^^^
 
 Create and manage MySQL database users with definable GRANT privileges.
 
@@ -88,7 +118,7 @@ priority.
     Make sure to **quote the passwords** in the pillar so YAML doesn't throw an exception.
 
 ``mysql.remove_test_database``
-------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 .. warning::
 
@@ -100,7 +130,7 @@ MySQL installation.  This state is **not** included as part of the meta-state
 above as this name may conflict with a real database.
 
 ``mysql.dev``
--------------
+^^^^^^^^^^^^^
 
 Install the MySQL development libraries and header files.
 
@@ -109,7 +139,7 @@ Install the MySQL development libraries and header files.
     your pillar data accordingly.
 
 ``mysql.repo``
---------------
+^^^^^^^^^^^^^^
 
 Add the official MySQL 5.7 repository.
 
@@ -120,7 +150,7 @@ Add the official MySQL 5.7 repository.
     changed enabled repository accordingly.
 
 ``mysql.config``
-------------------
+^^^^^^^^^^^^^^^^^^
 
 Manage the MySQL configuration.
 
@@ -135,3 +165,49 @@ Manage the MySQL configuration.
     component keys (`mysql.server`, `mysql.galera`, `mysql.libraries`, etc) with optional global
     configuration from `mysql.global`. The monolithic configuration, however, is defined separately
     in `mysql.config`.
+
+
+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 ``mysql`` 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..510cd28
--- /dev/null
+++ b/kitchen.yml
@@ -0,0 +1,149 @@
+# -*- 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 `develop`
+  - name: debian-10-develop-py3
+    driver:
+      image: netmanagers/salt-develop-py3:debian-10
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python3 git develop
+  - name: ubuntu-1804-develop-py3
+    driver:
+      image: netmanagers/salt-develop-py3:ubuntu-18.04
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python3 git develop
+  - name: centos-7-develop-py3
+    driver:
+      image: netmanagers/salt-develop-py3:centos-7
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python3 git develop
+  - name: fedora-30-develop-py3
+    driver:
+      image: netmanagers/salt-develop-py3:fedora-30
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python3 git develop
+  - name: opensuse-leap-15-develop-py3
+    driver:
+      image: netmanagers/salt-develop-py3:opensuse-leap-15
+      provision_command:
+        - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com
+        - sh bootstrap-salt.sh -XdPbfrq -x python3 git develop
+      run_command: /usr/lib/systemd/systemd
+  - name: amazonlinux-2-develop-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
+
+  ## SALT 2019.2
+  - 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-7-2019-2-py3
+    driver:
+      image: netmanagers/salt-2019.2-py3:centos-7
+  - name: fedora-30-2019-2-py3
+    driver:
+      image: netmanagers/salt-2019.2-py3:fedora-30
+  - name: opensuse-leap-15-2019-2-py3
+    driver:
+      image: netmanagers/salt-2019.2-py3:opensuse-leap-15
+      run_command: /usr/lib/systemd/systemd
+  - name: amazonlinux-2-2019-2-py2
+    driver:
+      image: netmanagers/salt-2019.2-py2:amazonlinux-2
+
+  ## SALT 2018.3
+  - 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: fedora-29-2018-3-py2
+    driver:
+      image: netmanagers/salt-2018.3-py2:fedora-29
+  - name: opensuse-leap-15-2018-3-py2
+    driver:
+      image: netmanagers/salt-2018.3-py2:opensuse-leap-15
+      run_command: /usr/lib/systemd/systemd
+  - name: amazonlinux-2-2018-3-py2
+    driver:
+      image: netmanagers/salt-2018.3-py2:amazonlinux-2
+
+  ## 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-29-2017-7-py2
+    driver:
+      image: netmanagers/salt-2017.7-py2:fedora-29
+  - name: opensuse-leap-15-2017-7-py2
+    driver:
+      image: netmanagers/salt-2017.7-py2:opensuse-leap-15
+      run_command: /usr/lib/systemd/systemd
+  - name: amazonlinux-2-2017-7-py2
+    driver:
+      image: netmanagers/salt-2017.7-py2:amazonlinux-2
+
+provisioner:
+  name: salt_solo
+  log_level: info
+  salt_install: none
+  require_chef: false
+  formula: mysql
+  salt_copy_filter:
+    - .kitchen
+    - .git
+  state_top:
+    base:
+      '*':
+        - mysql
+  pillars:
+    top.sls:
+      base:
+        '*':
+          - mysql
+  pillars_from_files:
+    mysql.sls: test/salt/pillar/mysql.sls
+
+verifier:
+  # https://www.inspec.io/
+  name: inspec
+  sudo: true
+  # cli, documentation, html, progress, json, json-min, json-rspec, junit
+  reporter:
+    - cli
+  inspec_tests:
+    - path: test/integration/default
+
+suites:
+  - name: default
diff --git a/mysql/defaults.yaml b/mysql/defaults.yaml
index f8854a0..5d3fac0 100644
--- a/mysql/defaults.yaml
+++ b/mysql/defaults.yaml
@@ -4,7 +4,11 @@ mysql:
   serverpkg: mysql-server
   clientpkg: mysql-client
   service: mysql
+  {%- if grains.pythonversion[0] == 2 %}
   pythonpkg: python-mysqldb
+  {% else %}
+  pythonpkg: python3-mysqldb
+  {% endif %}
   devpkg: mysql-devel
   debconf_utils: debconf-utils
 
diff --git a/mysql/salt-user.sls b/mysql/salt-user.sls
index 31df7f6..ed569df 100644
--- a/mysql/salt-user.sls
+++ b/mysql/salt-user.sls
@@ -25,9 +25,9 @@ mysql_salt_user_with_salt_user:
     - connection_user: '{{ mysql_salt_user }}'
     - connection_pass: '{{ mysql_salt_pass }}'
     - connection_charset: utf8
-    - onlyif:
-      - mysql --user {{ mysql_salt_user }} --password='{{ mysql_salt_pass|replace("'", "'\"'\"'") }}' -h {{ mysql_host }} --execute="SELECT 1;"
-      - VALUE=$(mysql --user {{ mysql_salt_user }} --password='{{ mysql_salt_pass|replace("'", "'\"'\"'") }}' -ss -e "SELECT Grant_priv FROM mysql.user WHERE user = '{{ mysql_salt_user }}' AND host = '{{ host }}';"); if [ "$VALUE" = 'Y' ]; then /bin/true; else /bin/false; fi
+    # - onlyif:
+    #   - mysql --user {{ mysql_salt_user }} --password='{{ mysql_salt_pass|replace("'", "'\"'\"'") }}' -h {{ mysql_host }} --execute="SELECT 1;"
+    #   - VALUE=$(mysql --user {{ mysql_salt_user }} --password='{{ mysql_salt_pass|replace("'", "'\"'\"'") }}' -ss -e "SELECT Grant_priv FROM mysql.user WHERE user = '{{ mysql_salt_user }}' AND host = '{{ host }}';"); if [ "$VALUE" = 'Y' ]; then /bin/true; else /bin/false; fi
 {% if os_family in ['RedHat', 'Suse'] %}
     - require_in:
       - mysql_user: mysql_root_password
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..afa0cb1
--- /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.hash = 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..8019607
--- /dev/null
+++ b/test/integration/default/README.md
@@ -0,0 +1,50 @@
+# Default InSpec Profile
+
+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/controls/packages_spec.rb b/test/integration/default/controls/packages_spec.rb
new file mode 100644
index 0000000..3be6792
--- /dev/null
+++ b/test/integration/default/controls/packages_spec.rb
@@ -0,0 +1,15 @@
+# Override by OS
+package_name = 'mariadb-server'
+if os[:name] == 'suse' or os[:name] == 'opensuse'
+  package_name = 'mariadb'
+elsif os[:name] == 'debian' and os[:release].start_with?('8')
+  package_name = 'mysql-server'
+end
+
+control 'mysql package' do
+  title 'should be installed'
+
+  describe package(package_name) do
+    it { should be_installed }
+  end
+end
diff --git a/test/integration/default/inspec.yml b/test/integration/default/inspec.yml
new file mode 100644
index 0000000..8a3f50e
--- /dev/null
+++ b/test/integration/default/inspec.yml
@@ -0,0 +1,12 @@
+name: mysql
+title: mysql formula
+maintainer: SaltStack Formulas
+license: Apache-2.0
+summary: Verify that the mysql 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
diff --git a/test/salt/pillar/mysql.sls b/test/salt/pillar/mysql.sls
new file mode 100644
index 0000000..13fe377
--- /dev/null
+++ b/test/salt/pillar/mysql.sls
@@ -0,0 +1,213 @@
+mysql:
+  global:
+    client-server:
+      default_character_set: utf8
+
+  clients:
+    mysql:
+      default_character_set: utf8
+    mysqldump:
+      default_character_set: utf8
+
+  library:
+    client:
+      default_character_set: utf8
+
+  server:
+    # Use this account for database admin (defaults to root)
+    # root_user: 'admin'
+    # root_password: '' - to have root@localhost without password
+    root_password: 'somepass'
+    root_password_hash: '*13883BDDBE566ECECC0501CDE9B293303116521A'
+    user: mysql
+    # If you only manage the dbs and users and the server is on
+    # another host
+    # host: 123.123.123.123
+    # my.cnf sections changes
+    mysqld:
+      # you can use either underscore or hyphen in param names
+      bind-address: 0.0.0.0
+      log_bin: /var/log/mysql/mysql-bin.log
+      datadir: /var/lib/mysql
+      port: 3307
+      binlog_do_db: foo
+      auto_increment_increment: 5
+      binlog-ignore-db:
+       - mysql
+       - sys
+       - information_schema
+       - performance_schema
+    mysql:
+      # my.cnf param that not require value
+      no-auto-rehash: noarg_present
+
+  # salt_user:
+  #   salt_user_name: 'salt'
+  #   salt_user_password: 'someotherpass'
+  #   grants:
+  #     - 'all privileges'
+
+  # Manage config
+  config:
+    file: ~/.my.cnf
+    sections:
+      client:
+        port: 33306
+        socket: /var/lib/mysql-socket/mysql.sock
+      mysqld_safe:
+        plugin-dir: '~/mysql/plugins'
+      mysqld:
+        user: myself
+        port: 33306
+        datadir: ~/mysql/datadir
+    apparmor:
+      dir: /etc/apparmor.d/local
+      file: usr.sbin.mysqld
+
+  # Manage databases
+  database:
+    # Simple definition using default charset and collate
+    - foo
+    # Detailed definition
+    - name: bar
+      character_set: utf8
+      collate: utf8_general_ci
+    # Delete DB
+    - name: obsolete_db
+      present: False
+  schema:
+    foo:
+      load: False
+    bar:
+      load: False
+    baz:
+      load: True
+      source: salt://{{ tpldir }}/files/baz.schema.tmpl
+      template: jinja
+    qux:
+      load: True
+      source: salt://{{ tpldir }}/files/qux.schema.tmpl
+      template: jinja
+      context:
+        encabulator: Turbo
+        girdlespring: differential
+    quux:
+      load: True
+      source: salt://{{ tpldir }}/files/qux.schema.tmpl
+      template: jinja
+      context:
+        encabulator: Retro
+        girdlespring: integral
+
+  # Manage users
+  # you can get pillar for existing server using scripts/import_users.py script
+  user:
+    frank:
+      password: 'somepass'
+      host: localhost
+      databases:
+        - database: foo
+          grants: ['select', 'insert', 'update']
+          escape: True
+        - database: bar
+          grants: ['all privileges']
+    # bob:
+    #   password_hash: '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4'
+    #   host: '%' # Any host
+    #   ssl: True
+    #   ssl-X509: True
+    #   ssl-SUBJECT: Subject
+    #   ssl-ISSUER: Name
+    #   ssl-CIPHER: Cipher
+    #   databases:
+    #     # https://github.com/saltstack/salt/issues/41178
+    #     # If you want to refer to databases using wildcards, turn off escape so
+    #     # the renderer does not escape them, enclose the string in '`' and
+    #     # use two '%'
+    #     - database: '`foo\_%%`'
+    #       grants: ['all privileges']
+    #       grant_option: True
+    #       escape: False
+    #     - database: bar
+    #       table: foobar
+    #       grants: ['select', 'insert', 'update', 'delete']
+    nopassuser:
+      password: ~
+      host: localhost
+      databases: []
+    application:
+      password: 'somepass'
+      mine_hosts:
+        target: "G@role:database and *.example.com"
+        function: "network.get_hostname"
+        expr_form: compound
+      databases:
+        - database: foo
+          grants: ['select', 'insert', 'update']
+
+    # Remove a user
+    obsoleteuser:
+      host: localhost
+      # defaults to True
+      present: False
+
+  # Override any names defined in map.jinja
+  # serverpkg: mysql-server
+  # clientpkg: mysql-client
+  # service: mysql
+  # pythonpkg: python-mysqldb
+  # devpkg: mysql-devel
+  # debconf_utils: debconf-utils
+
+  # Install MySQL headers
+  dev:
+    # Install dev package - defaults to False
+    install: False
+
+  macos:
+    products:
+      community_server:
+        enabled: True    # default
+        url: https://downloads.mysql.com/archives/get/file/mysql-8.0.11-macos10.13-x86_64.dmg
+        sum: 'md5=602a84390ecf3d82025b1d99fc594124'
+      workbench:
+        enabled: True    # default
+        url: https://downloads.mysql.com/archives/get/file/mysql-workbench-community-8.0.11-rc-macos-x86_64.dmg
+        sum: 'md5=37c5ae5bd75a4e1804ae6e0127d68611'
+      cluster:
+        enabled: False  #default
+        url: https://downloads.mysql.com/archives/get/file/mysql-cluster-gpl-7.6.6-macos10.13-x86_64.dmg
+        sum: 'md5=0df975908e7d8e4e8c1003d95edf4721'
+      router:
+        enabled: False  #default
+        url: https://downloads.mysql.com/archives/get/file/mysql-router-8.0.11-macos10.13-x86-64bit.dmg
+        sum: 'md5=8dd536f2f223933ecbfb8b19e54ee2f6'
+      utilities:
+        enabled: False  #default
+        url: https://downloads.mysql.com/archives/get/file/mysql-utilities-1.6.5-macos10.12.dmg
+        sum: 'md5=4c8e75bb217b8293dcdeb915b649c2c8'
+      shell:
+        enabled: False  #default
+        url: https://downloads.mysql.com/archives/get/file/mysql-shell-8.0.11-macos10.13-x86-64bit.dmg
+        sum: 'md5=43db4f0fc39f88c1d7be4a4f52cec363'
+      proxy:
+        enabled: False  #default
+        url: https://downloads.mysql.com/archives/get/file/mysql-proxy-0.8.5-osx10.7-x86-32bit.tar.gz
+        sum: 'md5=107df22412aa8c483d2021e1af24ee22'
+      connnector:
+        enabled: False  #default
+        url: https://downloads.mysql.com/archives/get/file/mysql-connector-nodejs-8.0.11.tar.gz
+        sum: 'md5=dece7fe5607918ba68499ef07c31508d'
+      forvisualstudio:
+        enabled: False  #default
+        url: https://downloads.mysql.com/archives/get/file/mysql-for-visualstudio-2.0.4-src.zip
+        sum: 'md5=fcf39316505ee2921e31a431eae77a9c'
+      forexcel:
+        enabled: False  #default
+        url: https://downloads.mysql.com/archives/get/file/mysql-for-excel-1.3.6-src.zip
+        sum: 'md5=2cc8b65eb72a1b07a6e4e2665e2a29e3'
+      notifier:
+        enabled: False  #default
+        url: https://downloads.mysql.com/archives/get/file/mysql-notifier-1.1.6-src.zip
+        sum: 'md5=349f1994681763fd6626a8ddf6be5363'
+
-- 
GitLab