Skip to content

Commit

Permalink
Add Github Actions
Browse files Browse the repository at this point in the history
Add better reporitng of code coverage and trivy report comment
  • Loading branch information
piotr-grodek-dsai committed Nov 9, 2023
1 parent 0a1bffb commit 38f70e6
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 7 deletions.
6 changes: 5 additions & 1 deletion cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
"repo_name": "{{cookiecutter.__client_name_slug}}-{{cookiecutter.__project_name_slug}}",
"ci": [
"GitLab",
"Github",
"None"
],
"jupytext": [
"No",
"Yes"
],
"python_package_name": "{{ cookiecutter.__project_name_slug.replace('-', '_') }}",
"__package_name": "{{ cookiecutter.python_package_name }}"
"__package_name": "{{ cookiecutter.python_package_name }}",
"_copy_without_render": [
".github/workflows/*.yml"
]
}
20 changes: 17 additions & 3 deletions hooks/post_gen_project.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
from pathlib import Path
import stat
import shutil

print("Running post generation...")

ci = "{{ cookiecutter.ci }}"

REMOVE_PATHS = []

gitlab_files = [
".gitlab-ci.yml"
".gitlab-ci.yml",
"docker/precommit"
]

github_files = [
".github/",
]

{% if cookiecutter.ci != "GitLab" %}
REMOVE_PATHS.extend(gitlab_files)
{% endif %}

{% if cookiecutter.ci != "Github" %}
REMOVE_PATHS.extend(github_files)
{% endif %}

{% if cookiecutter.jupytext != "Yes" %}
REMOVE_PATHS.extend(["notebooks/example.py"])
{% endif %}
Expand All @@ -24,10 +35,13 @@
if path.exists() and path.is_file():
print(f"Clean up file: '{path}'")
path.unlink()
elif path.exists() and path.is_dir():
print(f"Clean up directory: '{path}'")
shutil.rmtree(path)

#Solves problems when template fails to keep linux permissions. (e.g. after zipping template)
# Solves problems when template fails to keep linux permissions. (e.g. after zipping template)
print("Updating permissions... 🚀")
for path in Path("").rglob("*.sh"):
path.chmod(path.stat().st_mode | stat.S_IXUSR)

print("DONE 🎆")
27 changes: 27 additions & 0 deletions tests/test_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,33 @@ def test_template_project_with_gitlab(cookies):
assert (rpath / ".gitlab-ci.yml").exists() is True


def test_template_project_no_github(cookies):
result = cookies.bake(extra_context={
"client_name": "no",
"project_name": "gitlab",
"ci": "None"
})
assert result.exit_code == 0
assert result.exception is None

rpath: Path = result.project_path
assert (rpath / ".github").exists() is False


def test_template_project_with_github(cookies):
result = cookies.bake(extra_context={
"client_name": "with",
"project_name": "gitlab",
"ci": "Github"
})
assert result.exit_code == 0
assert result.exception is None

rpath: Path = result.project_path
assert (rpath / ".gitlab-ci.yml").exists() is False
assert (rpath / ".github").exists() is True


def test_template_project_with_jupytext(cookies):
result = cookies.bake(extra_context={
"client_name": "no",
Expand Down
199 changes: 199 additions & 0 deletions {{ cookiecutter.repo_name }}/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
name: Continuous Integration

on:
push:
branches: [main, master]
pull_request:

jobs:
lints:
name: Run linters
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
checks: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: "3.11"

- name: Cache pre-commit
uses: actions/cache@v3
with:
path: ~/.cache/pre-commit
key: pre-commit-3|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }}

- name: Install pre-commit
run: pip3 install pre-commit

- name: Run pre-commit checks
run: pre-commit run --all-files --show-diff-on-failure --color always

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: "fs"
ignore-unfixed: true
exit-code: 0 # change if you want to fail build on vulnerabilities
severity: "CRITICAL,HIGH,MEDIUM"
format: "table"
output: "trivy-scanning-results.txt"

- name: Format trivy message
run: |
echo "Trivy scanning results." >> trivy.txt
cat trivy-scanning-results.txt >> trivy.txt
- name: Add trivy report to PR
uses: thollander/actions-comment-pull-request@v2
continue-on-error: true
if: ${{ github.event_name == 'pull_request' }}
with:
filePath: trivy.txt
reactions: ""
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
comment_tag: trivy

- name: Create venv
run: . ./setup_dev_env.sh

- name: Check licenses
run: ./check_licenses.sh

- name: Generate pip freeze
run: |
source venv/bin/activate
pip freeze > requirements-freeze.txt
- name: Publish Artefacts
uses: actions/upload-artifact@v3
if: always()
continue-on-error: true
with:
name: results
path: |
requirements-freeze.txt
licenses.txt
trivy-scanning-results.txt
retention-days: 30

- name: Publish Test Report
uses: actions/upload-artifact@v3
if: always()
continue-on-error: true
with:
name: test-report
path: report.xml
retention-days: 10

- name: Validate package build
run: |
source venv/bin/activate
python -m pip install -U build
python -m build
- name: Publish Package
uses: actions/upload-artifact@v3
continue-on-error: true
if: success()
with:
name: packages
path: dist/**
retention-days: 3

tests:
name: Run tests
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
checks: write
pull-requests: write
contents: write # required for advanced coverage reporting (to keep branch)
strategy:
fail-fast: false # do not stop all jobs if one fails
matrix:
include:
- python-version: "3.11"
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Cache Dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements-dev.txt') }}-${{ hashFiles('**/setup.cfg') }}-${{ hashFiles('**/pyproject.toml') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install Dependencies
run: pip install -r requirements-dev.txt

- name: Run Tests With Coverage
run: |
# run with coverage to not execute tests twice
coverage run -m pytest -v -p no:warnings --junitxml=report.xml tests/
coverage report
coverage xml
- name: Test Report
uses: mikepenz/action-junit-report@v4
continue-on-error: true
if: always()
with:
report_paths: 'report.xml'

- name: Publish Test Report
uses: actions/upload-artifact@v3
continue-on-error: true
if: always()
with:
name: test-report
path: report.xml
retention-days: 10

# simpler version for code coverage reporting
# - name: Produce Coverage report
# uses: 5monkeys/cobertura-action@v13
# continue-on-error: true
# with:
# path: coverage.xml
# minimum_coverage: 70
# fail_below_threshold: false

# more complex version for better coverage reporting
- name: Produce the coverage report
uses: insightsengineering/coverage-action@v2
continue-on-error: true
with:
# Path to the Cobertura XML report.
path: coverage.xml
# Minimum total coverage, if you want to the
# workflow to enforce it as a standard.
# This has no effect if the `fail` arg is set to `false`.
threshold: 60
# Fail the workflow if the minimum code coverage
# reuqirements are not satisfied.
fail: false
# Publish the rendered output as a PR comment
publish: true
# Create a coverage diff report.
diff: true
# Branch to diff against.
# Compare the current coverage to the coverage
# determined on this branch.
diff-branch: ${{ github.event.repository.default_branch }}
# make report togglable
togglable-report: true
# This is where the coverage reports for the
# `diff-branch` are stored.
# Branch is created if it doesn't already exist'.
diff-storage: _xml_coverage_reports
# A custom title that can be added to the code
# coverage summary in the PR comment.
coverage-summary-title: "Code Coverage Summary"
36 changes: 36 additions & 0 deletions {{ cookiecutter.repo_name }}/.github/workflows/documentation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Build documentation

on:
push:
branches: [main, master]

jobs:
pages:
runs-on: ubuntu-latest
container: python:3.11

steps:
- uses: actions/checkout@v4

- name: Cache Dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements-dev.txt') }}
restore-keys: |
${{ runner.os }}-pip-
# for best results, it is better to generate
# documentation within development environment
- name: Create venv
run: . ./setup_dev_env.sh

- name: Build docs
run: ./build_docs.sh

# Uncomment below to deploy to GitHub Pages
# - name: Deploy
# uses: peaceiris/actions-gh-pages@v3
# with:
# github_token: ${{ secrets.GITHUB_TOKEN }}
# publish_dir: ./public
20 changes: 17 additions & 3 deletions {{ cookiecutter.repo_name }}/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,23 @@ Only people with repository access can view it.

Please read more about it [here](https://docs.gitlab.com/ee/user/project/pages/index.html).

{% endif %}
{%- endif -%}

{%- if cookiecutter.ci == "Github" %}

### Github Actions Documentation

By default **Github Actions** pipelines have `documentation` workflow which will build sphinx documentation automatically on main branch - and it will push it to a branch - it can be hosted on **Github Pages** if you enable it.

To access it, you need to enable it, on **Github repository -> Settings -> Pages** page select **Deploy from a branch** and select **gh-pages**. Link will appear here after deployment.

{% if cookiecutter.jupytext == "Yes" %}
**WARNING:** Only on Github Enterprise you can make it private so only people with repository access can view it.

Please read more about it [here](https://docs.github.com/en/pages/quickstart).

{%- endif -%}

{%- if cookiecutter.jupytext == "Yes" %}

# Jupyter notebooks and jupytext

Expand All @@ -88,7 +102,7 @@ There is pre-commit hook which automatically generates and syncs notebooks with
Please ensure you do not edit/modify manually or by other means generated py:percent files as they will conflict with jupytext change detection and lead to endless loop.
Treat them as read-only files and edit only notebooks.

{% endif %}
{%- endif -%}

# Semantic version bump

Expand Down

0 comments on commit 38f70e6

Please sign in to comment.