Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
6886dde
Create workflow1.yml
moulid15 Apr 8, 2023
866b3d3
Update workflow1.yml
moulid15 Apr 8, 2023
4acc687
Create workflow2.yml
moulid15 Apr 9, 2023
acfb224
Create Dockerfile
moulid15 Apr 9, 2023
0a67414
Update workflow2.yml
moulid15 Apr 9, 2023
7ad7876
Update workflow2.yml
moulid15 Apr 9, 2023
8337acb
Update workflow2.yml
moulid15 Apr 9, 2023
2027ca1
Update workflow2.yml
moulid15 Apr 9, 2023
f16e6bd
Update workflow2.yml
moulid15 Apr 9, 2023
bd09758
Update workflow2.yml
moulid15 Apr 9, 2023
3ed94f8
Update workflow1.yml
moulid15 Apr 9, 2023
8f73142
Update app.py
moulid15 Apr 9, 2023
8d636b0
Update app.py
moulid15 Apr 9, 2023
c0d433f
Update rps.py
moulid15 Apr 9, 2023
7da17f9
Update workflow1.yml
moulid15 Apr 9, 2023
0967b11
Update test_app.py
moulid15 Apr 9, 2023
0612a41
Update workflow1.yml
moulid15 Apr 9, 2023
6a6805f
Update workflow1.yml
moulid15 Apr 9, 2023
f5cbb61
Update test_rps.py
moulid15 Apr 9, 2023
6ad0aea
Update workflow1.yml
moulid15 Apr 9, 2023
f122e5d
Create workflow2.yml
moulid15 Apr 9, 2023
9254edd
Update workflow2.yml
moulid15 Apr 9, 2023
949dc80
Create Dockerfile
moulid15 Apr 9, 2023
6df3509
Update workflow2.yml
moulid15 Apr 9, 2023
a35471f
Update workflow2.yml
moulid15 Apr 9, 2023
d2bb014
Update workflow2.yml
moulid15 Apr 9, 2023
aab3499
Update workflow2.yml
moulid15 Apr 9, 2023
f88304c
k8s workflow
moulid15 Apr 9, 2023
d35e7f6
Rename kind to kind.yml
moulid15 Apr 9, 2023
2bb4e6d
Update kind.yml
moulid15 Apr 9, 2023
465f61a
Merge branch 'main' into workflow1
moulid15 Apr 9, 2023
ddbf512
Merge pull request #1 from moulid15/workflow1
moulid15 Apr 9, 2023
3034971
Update workflow2.yml
moulid15 Apr 9, 2023
9f46d91
Create integration_test.py
moulid15 Apr 9, 2023
35f069a
Update kind.yml
moulid15 Apr 9, 2023
a4da78e
Update kind.yml
moulid15 Apr 9, 2023
8fb68c7
Update integration_test.py
moulid15 Apr 9, 2023
f8f6536
Update kind.yml
moulid15 Apr 9, 2023
c3aa092
Update kind.yml
moulid15 Apr 9, 2023
2c2266e
Update kind.yml
moulid15 Apr 9, 2023
4577523
Update integration_test.py
moulid15 Apr 10, 2023
8abd313
Update workflow1.yml
moulid15 Apr 10, 2023
959f297
Update workflow1.yml
moulid15 Apr 10, 2023
e50c85e
Update integration_test.py
moulid15 Apr 10, 2023
5fa77ed
Update kind.yml
moulid15 Apr 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/kind.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: deploy k8s
on:
workflow_run:
workflows: [docker build]
types:
- completed

jobs:
kind:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- uses: actions/checkout@v3
- name: Create a k8s Kind Cluster
uses: helm/[email protected]
- name: Testing
run: |
kubectl wait nodes --for condition=Ready --all
kubectl cluster-info
kubectl get pods -n kube-system
echo "current-context:" $(kubectl config current-context)
echo "environment-kubeconfig:" ${KUBECONFIG}
- name: Deploy Application
run: |
kubectl create deployment rps --image=${{ secrets.DOCKERHUB_USERNAME }}/rps:latest
kubectl wait pods --for condition=Ready --timeout=90s --all
kubectl expose deployment/rps --type=NodePort --port 5000
- name: install dependencies for integration testing
run: |
pip install pytest
pip install pytest-cov
- name: Test Deployment
run: |
export NODE_PORT=$(kubectl get services/rps -o go-template='{{(index .spec.ports 0).nodePort}}')
echo NODE_PORT=${NODE_PORT}
kubectl describe services/rps
export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
kubectl port-forward service/rps 5000:5000 > /dev/null &
export URL=http://localhost:5000
pytest tests/integration
PYTHONPATH="${PYTHONPATH}:./src" coverage run -m pytest -v tests/integration
coverage report -m
- name: Cleanup
if: always()
run: |
kind delete cluster --name test-cd
37 changes: 37 additions & 0 deletions .github/workflows/workflow1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Pylint

on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint
pip install black
pip install pytest-cov
pip install requests
export URL=http://localhost:5000
pip install -r $(git ls-files 'requirements.txt')
- name: using black to format
run: |
black $(git ls-files '*.py')
- name: testing with coverage
run: |
PYTHONPATH="${PYTHONPATH}:./src" coverage run -m pytest -v tests/unit
PYTHONPATH="${PYTHONPATH}:./src" coverage run -m pytest -v tests/functional
- name: Get coverage report
run: coverage report -m
- name: Analysing the code with pylint
run: |
PYTHONPATH="${PYTHONPATH}:./src" pylint $(git ls-files '*.py')
32 changes: 32 additions & 0 deletions .github/workflows/workflow2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: docker build

on: [push, pull_request]

jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/rps:latest
${{ secrets.DOCKERHUB_USERNAME }}/rps:${{ github.sha }}
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM python:3.10.10-slim

WORKDIR /app

COPY ./src ./src

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

CMD ["flask", "--app", "src/rock_paper_scissors/app", "run"]
24 changes: 16 additions & 8 deletions src/rock_paper_scissors/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,40 @@ class InvalidMove(Exception):
Invalid Move
"""


app = Flask(__name__)


@app.route("/health")
def health():
"""
returns the health of the server
"""
return "OK"

@app.route("/rps", methods = ['POST'])

@app.route("/rps", methods=["POST"])
def rps():
"""
returns results of rock paper scissors game.
"""
# Create number to choice mapping
mapping = ["Rock", "Paper", "Scissors"]

move = request.json.get('move', '')
move = request.json.get("move", "")
try:
user_choice = mapping.index(move.lower().capitalize())
except ValueError:
raise InvalidMove(f"{move} is invalid. Valid moves: {mapping}")
except ValueError as exc:
raise InvalidMove(f"{move} is invalid. Valid moves: {mapping}") from exc

game_result, pc_choice = rock_paper_scissors(user_choice)
game_result, pc_choice = rock_paper_scissors(user_choice)
if game_result == 0:
result = "Tie"
elif game_result == -1:
result = f"I win, {mapping[pc_choice]} beats {move}"
elif game_result == 1:
result = f"You win, {move} beats {mapping[pc_choice]}"

return json.dumps({'result': result,
'game_result': game_result,
'pc_choice': pc_choice})
return json.dumps(
{"result": result, "game_result": game_result, "pc_choice": pc_choice}
)
3 changes: 2 additions & 1 deletion src/rock_paper_scissors/rps.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ def rock_paper_scissors(user_choice: int) -> int:
"""
# Generate computer choice
pc_choice = random.randint(0, 2)
if pc_choice == user_choice:
if pc_choice == user_choice: # pylint: disable=R1705
return 0, pc_choice
elif (user_choice + 1) % 3 == pc_choice % 3:
return -1, pc_choice
else:
return 1, pc_choice

28 changes: 20 additions & 8 deletions tests/functional/test_app.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
"""
Importing modules
"""
import json

from rock_paper_scissors.app import app


def test_rps():
"""
Test Flask Application and API for Rock Paper Scissors
Test Flask Application and API for Rock Paper Scissors..
"""


with app.test_client() as test_client:
response = test_client.post('/rps',
data=json.dumps(dict(move='Rock')),
content_type='application/json')
assert response.status_code == 200
moves = ["Rock", "Paper", "Scissors"]
for move in moves:
response = test_client.post(
"/rps", data=json.dumps({"move": move}), content_type="application/json"
)
assert response.status_code == 200
assert test_client.get("/health").data.decode("utf-8") == "OK"

try:
response = test_client.post(
"/rps",
data=json.dumps({"move": "wrong"}),
content_type="application/json",
)
except ValueError:
pass
25 changes: 25 additions & 0 deletions tests/integration/integration_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
Importing dependencies
"""

import os
import requests

URL = os.environ["URL"]


def test_health(): # pylint: disable=W3101
"""
Testing the /health endpoint
"""
response = requests.get(f"{URL}/health", timeout=60)
assert response.status_code == 200
assert response.content == b"OK"


def test_rps():
"""
Testing deployed application for Rock Paper Scissors..
"""
res = requests.post(URL + "/rps", json={"move": "rock"}, timeout=60)
assert res.status_code == 200
14 changes: 14 additions & 0 deletions tests/unit/test_rps.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""
importing modules
"""
from rock_paper_scissors.rps import rock_paper_scissors


Expand All @@ -7,3 +10,14 @@ def test_rps():
"""

assert rock_paper_scissors(1) is not None
assert rock_paper_scissors(3) in [
(-1, 1),
(-1, 0),
(-1, 2),
(1, 0),
(1, 1),
(1, -1),
(1, 2),
(2, 1),
(0, 1),
]