Skip to content

Commit

Permalink
Merge pull request #1 from cdcadman/pr_workflow
Browse files Browse the repository at this point in the history
Add PR workflow
  • Loading branch information
cdcadman authored Oct 30, 2024
2 parents 1453b2b + f9ad37e commit 96c529b
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 3 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/code_checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
on:
pull_request:
branches: main
schedule:
- cron: '25 2 * * 6'
jobs:
code-checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install python packages
run: |
python3.12 -m pip install --upgrade pip
python3.12 -m pip install -r requirements-dev.txt
- name: Run code checks
run: ./code_checks.sh
45 changes: 45 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,48 @@
# Contributing to 247 bishops

By contributing to 247 bishops, you agree that your contributions will be licensed under its GNU AGPL 3.
If you are adding something to this web app which is not your own, it must either in the public domain or have
a license which is compatible with the GNU AGPL 3.

## Guidelines

To contribute code changes to this repo, create a pull request into the main branch.
The following checks have to pass before it can merge (defined in `code_checks.yml`).

* licensecheck - confirms that all python packages in requirements.txt are compatible with this project's license.
* pip_audit - confirms that no python packages used by this project (including in `requirements-dev.txt`) have reported vulnerabilities.
* If any vulnerabilities are reported and if there is a fix version, update `requirements.txt` by running `calc_deterministic.sh`.
* bandit - checks for unsafe python code in this repo.
* To ignore a reported issue, please use the code. For example, putting `# nosec B608` on a line will ignore a potential SQL injection issue.
* If you have to insert the value of a variable into a query string, please ensure that the variable is trusted or checked. For example:

```python
# `positions` is an untrusted list of strings. The values are passed as parameters, but the right number of markers needs to be inserted into the query.
result = conn.exec_driver_sql(
f"select * from position_data where position in ({', '.join('%s' for _ in positions)})", # nosec B608
tuple(positions),
)
```

* black - enforces black formatting. Please run `python -m black .` before creating a pull request.
* isort - enforces import sorting. Please run `python -m isort .` before creating a pull request.
* pylint - checks for errors or warnings. If you have to ignore a message, please include the code.
For example: `from webapp_python import app # pylint:disable=unused-import`
* pytest - fails on warnings and checks for 100% code coverage.
* If you are unable to prevent a warning, please ignore it in `pyproject.toml` in `filterwarnings` using the precise line number.
For example: `"ignore:Use list:DeprecationWarning:msal.token_cache:164",`
* If you are unable to ensure 100% code coverage, please use `# pragma: no cover` sparingly, preferably only in tests. For example:

```python
# expected_condition() should return True, possibly after a brief delay
while True:
if expected_condition():
break
time.sleep(0.1) # pragma: no cover
```

## Adding packages

To add a python package, place it in `base_reqs.txt` with no version specifier. Then run `calc_deterministic.sh` to update `requirements.txt`.

If you are adding a javascript package in an html file, please ensure that it has an open source license compatible with the GNU AGPL 3.
2 changes: 1 addition & 1 deletion app.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from webapp_python import app
from webapp_python import app # pylint:disable=unused-import
10 changes: 10 additions & 0 deletions code_checks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
set -e
python3.12 -m licensecheck --zero
python3.12 -m pip_audit
python3.12 -m bandit -c pyproject.toml -r .
python3.12 -m black . --check
python3.12 -m isort . --check
python3.12 -m pylint .
python3.12 -m pytest --cov=. --cov-report=term-missing
python3.12 -m coverage report --fail-under=100
21 changes: 21 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[tool.bandit]
exclude_dirs = ["tests", "run_flask.py", "venv"]

[tool.pytest.ini_options]
filterwarnings=[
"error",
]

[tool.licensecheck]
using = "requirements:requirements.txt"

[project]
license = "AGPL"

[tool.isort]
profile = "black"

[tool.pylint]
ignore = ["venv"]
recursive = "y"
disable = "C,R,I"
10 changes: 10 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-r requirements.txt
pytest>=7.3.2
pytest-cov>=4.1.0
pylint>=2.17.4
black>=23.3.0
isort>=5.12.0
pip-audit>=2.7.0
bandit>=1.7.5
licensecheck>=2024
requests>=2.32.2
2 changes: 2 additions & 0 deletions run_flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
`python run_flask.py 5001` runs it on port 5001
Direct your webbrowser to http://127.0.0.1:5001 to view the app (if you ran it on port 5001).
"""

import sys

from app import app

PORT = sys.argv[1] if len(sys.argv) > 1 else 5000
Expand Down
Empty file added tests/__init__.py
Empty file.
42 changes: 42 additions & 0 deletions tests/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import signal
import subprocess as sp
import sys
from contextlib import contextmanager

TIMEOUT = 5


def close_server(server: sp.Popen, check_status=True):
server.send_signal(signal.SIGINT)
for line in iter(server.stderr.readline, ""):
sys.stderr.write(line)
server.stderr.close()
assert server.wait(TIMEOUT) in (0, -2) or not check_status


@contextmanager
def get_server_url():
port = 5000
while True:
server = sp.Popen(
[
sys.executable,
"run_flask.py",
str(port),
],
stderr=sp.PIPE,
text=True,
universal_newlines=True,
bufsize=1,
)
out = server.stderr.readline()
sys.stderr.write(out)
if "Address already in use" in out:
close_server(server, check_status=False)
port += 1
else:
break
try:
yield f"http://127.0.0.1:{port}"
finally:
close_server(server)
12 changes: 12 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import requests

from .server import get_server_url


def test_main():
with get_server_url() as webapp_url:
response = requests.get(f"{webapp_url}", timeout=60)
assert response.status_code == 200
assert "24/7 Bishops" in response.text
response = requests.get(f"{webapp_url}/favicon.svg?v=1729", timeout=60)
assert response.status_code == 200
9 changes: 9 additions & 0 deletions tests/test_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .server import get_server_url


def test_port_increment():
with get_server_url() as first_url:
first_port = int(first_url.split(":")[2])
with get_server_url() as second_url:
second_port = int(second_url.split(":")[2])
assert second_port > first_port
11 changes: 9 additions & 2 deletions webapp_python/main.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
from pathlib import Path

import flask

app = flask.Flask(__name__)


@app.route("/")
def main():
return flask.send_file(Path(__file__).parent.absolute().parent / "html" / "main.html")
return flask.send_file(
Path(__file__).parent.absolute().parent / "html" / "main.html"
)


@app.route("/favicon.svg")
def favicon():
"""If this is updated, you also need to increment the version in the link tag in the html file.
See https://stackoverflow.com/questions/2208933/how-do-i-force-a-favicon-refresh"""
return flask.send_file(Path(__file__).parent.absolute().parent / "html" / "Chess_tile_bl.svg")
return flask.send_file(
Path(__file__).parent.absolute().parent / "html" / "Chess_tile_bl.svg"
)

0 comments on commit 96c529b

Please sign in to comment.