Repository: bird-house/twitcher (language: python)

Issue:
Test and Dependencies pre-valiation (branch 0.6.x)
## Motivation

There is no way to know if something breaks or if the generated Docker image still works when doing a PR. 
This PR adds a full test suite using Github Actions to validate that deployed images will work. 

## Changes

- Also apply `pyramid>=1.10,<2` (`<2` is the important part) that was omitted in PRs #104 / #105. 
  The `pyramid.compat` modules is removed since v2 and cannot be found when starting Twitcher. 
- Add Github Action workflow that allows testing (local, lint, docker) to ensure features don't break stuff before PR integration.
  (workflow was taken from https://github.com/Ouranosinc/Magpie repo and adjusted/trimmed down for available targets in the current `Makefile`)
- Add Github Templates to help define issues and PR contents in the future.
- Fix references/format in ``CHANGES.rst`` so links are generated both on Github and ReadTheDocs side.

## Extra fixes

- Specific to master / 0.6.x branch: resolve incorrect use of `decode()` with `PyJWT>=2` that directly returns strings (issue discovered using above Github test workflow)

## See also

For branch 0.5.x: #107 


Discussion / hints:

Fix patch:
diff --git a/.dockerignore b/.dockerignore
index 6851520..81d160c 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -24,6 +24,7 @@ Makefile.config
 # Unit test / Coverage reports
 **/*.cache
 **/*.coverage
+**/coverage.*
 **/*.pytest_cache
 **/*.tox
 **/nosetests.xml
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
new file mode 100644
index 0000000..beaae95
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -0,0 +1,39 @@
+---
+
+name: Bug Report
+about: Create a report to describe a problem
+labels: triage/bug
+assignees: cehbrecht
+
+---
+
+## Describe the bug
+
+<!-- A clear and concise description of what the bug is. -->
+
+## To Reproduce
+
+<!-- 
+Steps to reproduce the behavior:
+1. Deploy process with payload '...'
+2. Execute using payload '....'
+3. Result '....'
+4. Error message '...'
+5. etc.
+-->
+
+## Expected behavior
+
+<!-- A clear and concise description of what you expected to happen. -->
+
+## Context
+
+<!-- 
+    If applicable, add screenshots or drag-drop files to help explain your problem.
+    Also, please complete the following information.
+-->
+
+- OS: \[e.g. Linux|Windows] (if running locally)
+- Browser \[e.g. chrome, safari] (if running as a service)
+- Instance: \[ADES|EMS|Hybrid] and URL
+- Version \["1.2.3", see `/versions` endpoint]
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
new file mode 100644
index 0000000..345fbda
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -0,0 +1,27 @@
+---
+
+name: Feature Request
+about: Suggest an idea for this project
+labels: triage/feature
+assignees: cehbrecht
+
+---
+
+## Description
+
+<!-- 
+
+- Is your feature request related to a missing implementation or functionality?
+- What is the expected solution or behaviour?
+- Describe alternative approaches you have considered.
+
+-->
+
+## References
+
+<!-- 
+Provide any external references or similar issue links here.
+
+- issue #<issue-number>
+- external https://link
+-->
diff --git a/.github/PULL_REQUEST_TEMPLATE/pull-request-template.md b/.github/PULL_REQUEST_TEMPLATE/pull-request-template.md
new file mode 100644
index 0000000..85210ae
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE/pull-request-template.md
@@ -0,0 +1,27 @@
+---
+
+name: Pull Request
+about: Create a pull request to resolve issues or add new features.
+
+---
+
+## Changes
+
+<!-- Provide a summary of changes.
+- ...
+- ...
+-->
+
+## Features and Fixes
+
+<!--
+Add any applicable references. 
+
+- Fixes #<issue number>
+- Relates to #<issue number>
+-->
+
+## Checklist
+
+- [ ] Included fixes and related issue references in changes.
+- [ ] Tests added/updated to validate fixes and/or new features.
diff --git a/.gitignore b/.gitignore
index b45dd9c..21bd2e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@ __pycache__
 nosetests.xml
 unit_tests/testdata.json
 coverage/
+coverage.*
 
 # R
 *.Rhistory
diff --git a/CHANGES.rst b/CHANGES.rst
index d3399b4..e278f9d 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,10 +4,15 @@ Changes
 Unreleased
 ==========
 
+Changes:
+
+* Add Github Actions workflow to run local tests and Docker smoke tests for pre-validation of features and changes.
+* Add Github issue, feature request and pull request templates.
+
 Fixes:
 
-* Pin packages ``zope.sqlalchemy>=1.5`` and ``sqlalchemy>=1.4,<2`` to avoid errors with conflicting and upcoming
-  release and features employed in code.
+* Pin packages ``pyramid<2``, ``zope.sqlalchemy>=1.5`` and ``sqlalchemy>=1.4,<2`` to avoid errors with conflicting
+  and upcoming release and features employed in code.
 * Fix failing ``cryptography`` package build step in Docker image due to missing ``g++`` and ``rust`` dependencies
   (``rust`` installed via ``cargo``).
 
@@ -16,7 +21,7 @@ Fixes:
 
 Fixes:
 
-* Update invalid reference to `python3-dev` in docker image.
+* Update invalid reference to ``python3-dev`` in docker image.
   Travis-CI is also updated to run a smoke test build of this docker image prior to merge to help early detection
   of problems prior to deploy triggers from tags.
 
@@ -40,13 +45,13 @@ Changes:
 
 New Features:
 
-* Adds route `/info` which returns contents of `twitcher.__version__`.
+* Adds route ``/info`` which returns contents of ``twitcher.__version__``.
 * Adds route `/versions` which returns version details such as `Twitcher` app version and employed adapter version.
 
 Changes:
 
-* Updated `README.rst` to match recent development, reference and docker image link.
-* Adds URI of `/info` and `/versions` routes in the frontpage response.
+* Updated ``README.rst`` to match recent development, reference and docker image link.
+* Adds URI of ``/info`` and ``/versions`` routes in the frontpage response.
 * Corresponding HTTP status codes are returned for raised ``OWSException``.
 
 Fixes:
@@ -56,7 +61,7 @@ Fixes:
 
 New Features:
 
-* Add `postgres` extra requirements for when it is used as database driver with `sqlalchemy`.
+* Add `postgres` extra requirements for when it is used as database driver with ``sqlalchemy``.
 
 Changes:
 
@@ -64,203 +69,213 @@ Changes:
 
 Fixes:
 
-* Improve the adapter import methodology to work with more use cases (https://github.com/Ouranosinc/Magpie/issues/182).
-* Fix incorrect setup for bump version within `Makefile`.
-* Fix Twitcher `main` including ``twitcher.<module>`` instead of ``.<module>``.
+* Improve the adapter import methodology to work with more
+  use cases (`Ouranosinc/Magpie#182 <https://github.com/Ouranosinc/Magpie/issues/182>`_).
+* Fix incorrect setup for bump version within ``Makefile``.
+* Fix Twitcher ``main`` including ``twitcher.<module>`` instead of ``.<module>``.
 
 0.5.0 (2019-05-22)
 ==================
 
 Changes:
 
-* Skipped Buildout (#49).
-* Replaced mongodb by sqlalchemy (#51).
-* Simplified `Makefile` and skipped conda targets (#75).
-* Add `Makefile` targets for `docker`, `bumpversion` and `coverage` analysis related tasks (#67).
-* Removed unused `config` module (#70).
+* Skipped Buildout (`#49 <https://github.com/bird-house/twitcher/issues/49>`_).
+* Replaced mongodb by sqlalchemy (`#51 <https://github.com/bird-house/twitcher/issues/51>`_).
+* Simplified ``Makefile`` and skipped conda
+  targets (`#75 <https://github.com/bird-house/twitcher/issues/75>`_).
+* Add ``Makefile`` targets for ``docker``, ``bumpversion`` and ``coverage`` analysis
+  related tasks (`#67 <https://github.com/bird-house/twitcher/issues/67>`_).
+* Removed unused ``config`` module (`#70 <https://github.com/bird-house/twitcher/issues/70>`_).
 
 New Features:
 
-* Provided a `Dockerfile` for building `Twitcher` (#67).
-* Provide ``AdapterInterface`` to allow overriding store implementations with configuration setting ``twitcher.adapter`` (#67).
-* Add version auto-update (number and date) of these 'changes' with ``bump2version`` (#67).
+* Provided a ``Dockerfile`` for building `Twitcher`
+  (`#67 <https://github.com/bird-house/twitcher/issues/67>`_).
+* Provide ``AdapterInterface`` to allow overriding store implementations with configuration
+  setting ``twitcher.adapter`` (`#67 <https://github.com/bird-house/twitcher/issues/67>`_).
+* Add version auto-update (number and date) of these 'changes' with ``bump2version``
+  (`#67 <https://github.com/bird-house/twitcher/issues/67>`_).
 
 Fixes:
 
 * Update requirements with missing dependencies when building docker image.
-* Various fixes (#74, #73, #72, #71)
+* Various fixes (
+  `#71 <https://github.com/bird-house/twitcher/issues/71>`_,
+  `#72 <https://github.com/bird-house/twitcher/issues/72>`_,
+  `#73 <https://github.com/bird-house/twitcher/issues/73>`_,
+  `#74 <https://github.com/bird-house/twitcher/issues/74>`_)
 
 0.4.0 (2019-05-02)
 ==================
 
 Changes:
 
-* Skipped Python 2.7 support (#61).
-* Added public URL "purl" (#58).
-* Added SSL verify option (#55).
-* Skipped internal WPS (#52).
-* Moved tests to top-level folder (#47).
+* Skipped Python 2.7 support (`#61 <https://github.com/bird-house/twitcher/issues/61>`_).
+* Added public URL "purl" (`#58 <https://github.com/bird-house/twitcher/issues/58>`_).
+* Added SSL verify option (`#55 <https://github.com/bird-house/twitcher/issues/55>`_).
+* Skipped internal WPS (`#52 <https://github.com/bird-house/twitcher/issues/52>`_).
+* Moved tests to top-level folder (`#47 <https://github.com/bird-house/twitcher/issues/47>`_).
 
 0.3.8 (2018-09-11)
 ==================
 
 Fixes:
 
-* Fixed the wps DataInputs params encoding (#42).
-* Fixed error 400 Contradictory scheme headers (#40).
+* Fixed the wps DataInputs params encoding (`#42 <https://github.com/bird-house/twitcher/issues/42>`_).
+* Fixed error 400 Contradictory scheme headers (`#40 <https://github.com/bird-house/twitcher/issues/40>`_).
 
 New Features:
 
-* make protected path configurable (#36).
+* make protected path configurable (`#36 <https://github.com/bird-house/twitcher/issues/36>`_).
 
 0.3.7 (2018-03-13)
 ==================
 
 Fixes:
 
-* fixed exclude filter in MANIFEST.in.
+* Fixed exclude filter in ``MANIFEST.in``.
 
 New Features:
 
-* Feature #28: use request upstream when not using wps (e.g download file through thredds).
+* Feature `#28 <https://github.com/bird-house/twitcher/issues/28>`_: use request upstream when not using WPS
+  (e.g download file through ``thredds``).
 
 0.3.6 (2018-03-08)
 ==================
 
-* pep8
-* removed unused ``c4i`` option.
-* added ``auth`` option to set authentication method.
-* updated docs for usage of x509 certificates.
+* Fix PEP8
+* Removed unused ``c4i`` option.
+* Added ``auth`` option to set authentication method.
+* Updated docs for usage of x509 certificates.
 
 New Features:
 
-* Feature #25: using x509 certificates for service authentication.
+* Feature `#25 <https://github.com/bird-house/twitcher/issues/25>`_: using x509 certificates for service authentication.
 
 0.3.5 (2018-03-01)
 ==================
 
-* pep8
-* updated makefile
-* updated buildout recipes
-* fixed nginx dependency
-* updated mongodb 3.4
-* configured csrf in xmlrpc
-* fixed tutorial example
-* added readthedocs, licence and chat badges
+* Fix PEP8
+* Updated makefile
+* Updated buildout recipes
+* Fixed nginx dependency
+* Updated mongodb 3.4
+* Configured csrf in xmlrpc
+* Fixed tutorial example
+* Added readthedocs, licence and chat badges
 
 0.3.4 (2017-05-05)
 ==================
 
-* updated logging.
-* fixed: creates workdir if it does not exist.
+* Updated logging.
+* Fixed: creates workdir if it does not exist.
 
 0.3.3 (2017-04-27)
 ==================
 
-* fixed fetching of access token when service is public.
+* Fixed fetching of access token when service is public.
 
 0.3.2 (2017-01-31)
 ==================
 
-* set header X-X509-User-Proxy.
-
+* Set header ``X-X509-User-Proxy``.
 
 0.3.1 (2017-01-26)
 ==================
 
-* pep8.
-* set permission of certfile.
-* added option ows-proxy-delegate.
+* Fix PEP8.
+* Set permission of certfile.
+* Added option ``ows-proxy-delegate``.
 
 0.3.0 (2017-01-11)
 ==================
 
-* pep8.
-* changed rpc interface.
-* added twitcher.client module.
-* using esgf scls service to get credentials.
-* updated internal pywps to version 4.0.0.
-* using default port 5000.
-* added ipython notebook examples.
-* moved namesgenerator to top-level.
-* added _compat module for python 3.x/2.x compatibility.
-* added twitcher.api and cleaned up rpcinterface.
-* added twitcher.store with mongodb and memory implementation.
-* added twitcher.datatype with AccessToken and Service.
-* using https port only.
-* using OWSExceptions on errors in owsproxy.
+* Fix PEP8.
+* Changed rpc interface.
+* Added twitcher.client module.
+* Using esgf scls service to get credentials.
+* Updated internal pywps to version 4.0.0.
+* Using default port 5000.
+* Added ipython notebook examples.
+* Moved ``namesgenerator`` to top-level.
+* Added ``_compat`` module for Python 3.x/2.x compatibility.
+* Added ``twitcher.api`` and cleaned up rpcinterface.
+* Added ``twitcher.store`` with mongodb and memory implementation.
+* Added ``twitcher.datatype`` with ``AccessToken`` and ``Service``.
+* Using https port only.
+* Using ``OWSExceptions`` on errors in owsproxy.
 
 0.2.4 (2016-12-23)
 ==================
 
-* pep8.
-* using replace_caps_url in owsproxy.
-* pinned mongodb=2.6*|3.3.9.
-* replaced service_url by proxy_url.
-* added wms_130 and renamed wms_111.
+* Fix PEP8.
+* Using ``replace_caps_url`` in ``owsproxy``.
+* Pinned ``mongodb=2.6*|3.3.9``.
+* Replaced ``service_url`` by ``proxy_url``.
+* Added ``wms_130`` and renamed ``wms_111``.
 
 0.2.3 (2016-11-18)
 ==================
 
-* pep8
-* using doc2dict, renamed get_service_by_name().
-* added support for c4i tokens.
-* updated deps: pytest, mongodb.
-* updated buildout recipes.
-* fixed functional tests.
+* Fix PEP8.
+* Using ``doc2dict``, renamed ``get_service_by_name()``.
+* Added support for c4i tokens.
+* Updated deps: ``pytest``, ``mongodb``.
+* Updated buildout recipes.
+* Fixed functional tests.
 
 0.2.2 (2016-08-18)
 ==================
 
-* pep8
-* don't allow dupliate service names.
+* Fix PEP8.
+* Don't allow duplicate service names.
 
 0.2.1 (2016-08-05)
 ==================
 
-* register service with public access.
+* Register service with public access.
 * WMS services can be registered.
 
 0.2.0 (2016-07-18)
 ==================
 
-* updated to new buildout with seperated conda environment.
-* replaced nose by pytest.
-* updated installation docs.
+* Updated to new buildout with separated conda environment.
+* Replaced nose by pytest.
+* Updated installation docs.
 
 0.1.7 (2016-06-09)
 ==================
 
-Bugfixes:
+Fixes:
 
-* update of service failed (#17).
+* Update of service failed (`#17 <https://github.com/bird-house/twitcher/issues/17>`_).
 
 0.1.6 (2016-06-01)
 ==================
 
-* updated docs.
-* renamed python package to pyramid_twitcher.
-* conda envionment.yml added.
-* using get_sane_name().
-* replaced httplib2 by requests.
+* Updated docs.
+* Renamed Python package to ``pyramid_twitcher``.
+* Conda ``envionment.yml`` added.
+* Using ``get_sane_name()``.
+* Replaced ``httplib2`` by ``requests``.
 
-Bugfixes:
+Fixes:
 
-* don't check token for allowed requests (#14).
-* ignore decoding errors of response content (#13).
-* fixed twitcher app config: wrong egg name.
+* Don't check token for allowed requests (`#14 <https://github.com/bird-house/twitcher/issues/14>`_).
+* Ignore decoding errors of response content (`#13 <https://github.com/bird-house/twitcher/issues/13>`_).
+* Fixed twitcher app config: wrong egg name.
 
 0.1.5 (2016-04-22)
 ==================
 
-* fixed docs links
+* Fixed docs links
 
 0.1.4 (2016-04-19)
 ==================
 
-* Fixed MANIFEST.in
+* Fixed ``MANIFEST.in``
 * Fixed service database index.
-* Updated makefile.
+* Updated ``Makefile``.
 * Added more links to appendix.
 
 0.1.0 (2015-12-07)
diff --git a/Dockerfile b/Dockerfile
index ba63576..23c96b6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -31,7 +31,7 @@ RUN apk update \
         libxslt-dev \
         libxml2 \
         libffi-dev \
-        libressl-dev \
+        openssl-dev \
     && apk add --virtual .build-deps \
         python3-dev \
         py-pip \
diff --git a/Makefile b/Makefile
index 18e21d5..e63374a 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,7 @@ INI_FILE ?= development.ini
 
 DOCKER_TAG := birdhouse/twitcher:v$(VERSION)
 DOCKER_TEST := smoke-test-twitcher
+DOCKER_BUILD_XARGS ?=
 
 # Bumpversion 'dry' config
 # if 'dry' is specified as target, any bumpversion call using 'BUMP_XARGS' will not apply changes
@@ -37,6 +38,8 @@ help:
 	@echo "  docker-push       to push the built docker image to the tagged repository."
 	@echo "\nTesting targets:"
 	@echo "  test              to run tests (but skip long running tests)."
+	@echo "  test-local        to run only local tests (skip online tests)."
+	@echo "  test-docker       to run smoke test of docker build and execution."
 	@echo "  test-all          to run all tests (including long running tests)."
 	@echo "  lint              to run code style checks with flake8."
 	@echo "  coverage          to generate an HTML report from tests coverage analysis."
@@ -121,12 +124,12 @@ clean-dist: clean
 .PHONY: docker-build
 docker-build:
 	@echo "Building docker image: $(DOCKER_TAG)"
-	@-docker build "$(APP_ROOT)" -t "$(DOCKER_TAG)"
+	@docker build $(DOCKER_BUILD_XARGS) "$(APP_ROOT)" -t "$(DOCKER_TAG)"
 
 .PHONY: docker-push
 docker-push:
 	@echo "Pushing docker image: $(DOCKER_TAG)"
-	@-docker push "$(DOCKER_TAG)"
+	@docker push "$(DOCKER_TAG)"
 
 .PHONY: docker-stop
 docker-stop:
@@ -137,9 +140,9 @@ docker-stop:
 .PHONY: docker-test
 docker-test: docker-build docker-stop
 	@echo "Smoke test of docker image: $(DOCKER_TAG)"
-	docker run --name $(DOCKER_TEST) -p 8000:8000 -d $(DOCKER_TAG)
-	sleep 2
-	echo "Testing docker image..."
+	docker run --pull never --name $(DOCKER_TEST) -p 8000:8000 -d $(DOCKER_TAG)
+	@sleep 2
+	@echo "Testing docker image..."
 	@(curl http://localhost:8000 | grep "Twitcher Frontpage" && \
 	  $(MAKE) docker-stop --no-print-directory || \
  	 ($(MAKE) docker-stop --no-print-directory && \
@@ -177,6 +180,7 @@ lint:
 coverage: .coverage
 	@bash -c 'coverage report -m'
 	@bash -c 'coverage html -d coverage'
+	@bash -c 'coverage xml -i -o coverage/coverage.xml'
 	@-echo "Coverage report: open file://$(APP_ROOT)/coverage/index.html"
 
 ## Sphinx targets
@@ -200,4 +204,4 @@ dist: clean
 	@echo "Builds source and wheel package ..."
 	@-python setup.py sdist
 	@-python setup.py bdist_wheel
-	ls -l dist
+	@ls -l dist
diff --git a/requirements.txt b/requirements.txt
index a4e4e80..5ea36b5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-pyramid>=1.10
+pyramid>=1.10,<2
 pyramid_rpc
 webob
 requests
diff --git a/setup.py b/setup.py
index fb8c05f..030ac71 100644
--- a/setup.py
+++ b/setup.py
@@ -17,11 +17,19 @@
       description=about['__doc__'],
       long_description=README + '\n\n' + CHANGES,
       classifiers=[
-          "Programming Language :: Python",
+          "Development Status :: 4 - Beta",
           "Framework :: Pyramid",
+          "Intended Audience :: Developers",
+          "License :: OSI Approved :: Apache Software License",
+          "Natural Language :: English",
+          "Programming Language :: Python",
+          "Programming Language :: Python :: 2.7",
+          "Programming Language :: Python :: 3.5",
+          "Programming Language :: Python :: 3.6",
+          "Programming Language :: Python :: 3.7",
+          "Programming Language :: Python :: 3.8",
           "Topic :: Internet :: WWW/HTTP",
           "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
-          "Development Status :: 4 - Beta",
       ],
       author=about['__author__'],
       author_email=about['__email__'],
@@ -32,6 +40,7 @@
       include_package_data=True,
       zip_safe=False,
       test_suite='twitcher',
+      python_requires=">=3.6, <4",
       install_requires=reqs,
       extras_require={
           "dev": dev_reqs,              # pip install ".[dev]"


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..b1c5e5d
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,100 @@
+# run test suites
+
+name: Tests
+on:
+  - pull_request
+  - push
+  - release
+  - workflow_dispatch
+
+jobs:
+  # see: https://github.com/fkirc/skip-duplicate-actions
+  skip_duplicate:
+    continue-on-error: true
+    runs-on: ubuntu-latest
+    outputs:
+      should_skip: ${{ steps.skip_check.outputs.should_skip && ! contains(github.ref, 'refs/tags') }}
+    steps:
+      - id: skip_check
+        uses: fkirc/skip-duplicate-actions@master
+        with:
+          concurrent_skipping: "same_content_newer"
+          skip_after_successful_duplicate: "true"
+          do_not_skip: '["pull_request", "workflow_dispatch", "schedule", "release"]'
+
+  # see: https://github.com/actions/setup-python
+  tests:
+    # FIXME: https://github.com/fkirc/skip-duplicate-actions/issues/90
+    #   disable for now because the tests never run... somehow similar config works in Magpie...
+    # needs: skip_duplicate
+    # if: ${{ needs.skip_duplicate.outputs.should_skip != 'true' }}
+    runs-on: ${{ matrix.os }}
+    continue-on-error: ${{ matrix.allow-failure }}
+    env:
+      # override make command to install directly in active python
+      CONDA_CMD: ""
+    services:
+      # Label used to access the service container
+      mongodb:
+        image: mongo:3.4.23  # DockerHub
+        ports:
+          - "27017:27017"
+    strategy:
+      matrix:
+        os: [ubuntu-latest]
+        python-version: ["3.6", "3.7", "3.8"]
+        allow-failure: [false]
+        test-case: [test-local]
+        include:
+          # linter tests
+          - os: ubuntu-latest
+            python-version: 3.7
+            allow-failure: false
+            test-case: lint
+          # coverage test
+          - os: ubuntu-latest
+            python-version: 3.7
+            allow-failure: false
+            test-case: coverage
+          # smoke test of Docker image
+          - os: ubuntu-latest
+            python-version: None  # doesn't matter which one (in docker), but match default of repo
+            allow-failure: false
+            test-case: docker-test
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: "0"
+      - name: Setup Python
+        uses: actions/setup-python@v2
+        if: ${{ matrix.python-version != 'None' }}
+        with:
+          python-version: ${{ matrix.python-version }}
+      - name: Install Dependencies
+        if: ${{ matrix.python-version != 'None' }}
+        # install package and dependencies directly,
+        # skip sys/conda setup to use active python
+        run: make install develop
+      - name: Display Packages
+        if: ${{ matrix.python-version != 'None' }}
+        run: pip freeze
+      #- name: Setup Environment Variables
+      #  uses: c-py/action-dotenv-to-setenv@v2
+      #  with:
+      #    env-file: ./ci/weaver.env
+      - name: Display Environment Variables
+        run: |
+          hash -r
+          env | sort
+      - name: Run Tests
+        run: make --no-keep-going ${{ matrix.test-case }}
+      - name: Stop Workers
+        if: ${{ matrix.python-version == 'None' }}
+        run: make docker-stop
+      - name: Upload coverage report
+        uses: codecov/codecov-action@v1
+        if: ${{ success() && matrix.test-case == 'coverage' }}
+        with:
+          files: ./coverage/coverage.xml
+          fail_ci_if_error: true
+          verbose: true