Skip to content

Commit acca9ab

Browse files
committed
Initial commit
0 parents  commit acca9ab

19 files changed

Lines changed: 711 additions & 0 deletions
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Update Base Image for AWS Lambda and push to DockerHub
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
8+
push_to_registry:
9+
name: Build and Push to DockerHub Registry
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v2
15+
16+
- name: Log in to Docker Hub
17+
uses: docker/login-action@v1
18+
with:
19+
username: ${{ secrets.DOCKER_USERNAME }}
20+
password: ${{ secrets.DOCKER_PASSWORD }}
21+
22+
- name: Build and Push Base Image
23+
uses: docker/build-push-action@v2
24+
with:
25+
file: app/tools/Dockerfile
26+
context: app/
27+
push: true
28+
tags: ${{ secrets.DOCKER_USERNAME }}/python-lambda-question-type:testing
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: Test & Deploy Grading Script to AWS Lambda
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
workflow_dispatch:
8+
9+
jobs:
10+
11+
test:
12+
name: Test
13+
runs-on: ubuntu-latest
14+
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
python-version: [ 3.8 ]
19+
20+
defaults:
21+
run:
22+
working-directory: app/
23+
24+
steps:
25+
- name: Checkout
26+
uses: actions/checkout@v2
27+
28+
- name: Set up Python ${{ matrix.python-version }}
29+
uses: actions/setup-python@v2
30+
with:
31+
python-version: ${{ matrix.python-version }}
32+
33+
- name: Install dependencies
34+
run: |
35+
python -m pip install --upgrade pip
36+
python -m pip install flake8 pytest
37+
python -m pip install -r tools/tools_requirements.txt
38+
python -m pip install -r requirements.txt
39+
40+
- name: Lint with flake8
41+
run: |
42+
# stop the build if there are Python syntax errors or undefined names
43+
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
44+
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
45+
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
46+
47+
- name: Test Handler functions
48+
run: |
49+
pytest -v tests/handling.py::TestHandlerFunction
50+
- name: Test JSON schema
51+
run: |
52+
pytest -v tests/validation.py::TestSchemaValidation
53+
- name: Test Grading functions
54+
run: |
55+
pytest -v tests/grading.py::TestGradingFunction
56+
57+
58+
deploy:
59+
name: Deploy
60+
needs: test
61+
runs-on: ubuntu-latest
62+
environment: production
63+
64+
steps:
65+
- name: Checkout
66+
uses: actions/checkout@v2
67+
68+
- name: Configure AWS credentials
69+
uses: aws-actions/configure-aws-credentials@v1
70+
with:
71+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
72+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
73+
aws-region: eu-west-2
74+
75+
- name: Login to Amazon ECR
76+
id: login-ecr
77+
uses: aws-actions/amazon-ecr-login@v1
78+
79+
- name: Build, tag, and push image to Amazon ECR
80+
id: build-image
81+
env:
82+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
83+
ECR_REPOSITORY: test-boilerplate-question-type
84+
IMAGE_TAG: latest
85+
run: |
86+
# Build docker image from algorithm, schema and requirements
87+
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG app/
88+
# Push image to ECR
89+
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
90+
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
91+
92+
- name: Update lambda function image
93+
env:
94+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
95+
ECR_REPOSITORY: test-boilerplate-question-type
96+
LAMBDA_FUNCTION_NAME: test_question_type_boilerplate
97+
IMAGE_TAG: latest
98+
run: |
99+
aws lambda update-function-code --function-name $LAMBDA_FUNCTION_NAME --image-uri $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
# Remove all hidden files except for gitgnore and workflow folder
3+
.*
4+
5+
!.gitignore
6+
!.github/
7+
8+
# Remove python caching
9+
__pycache__

app/Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Base image that bundles AWS Lambda Python 3.8 image with some middleware functions
2+
FROM loumstarlearjet/python-lambda-question-type:testing
3+
4+
# To avoid setting up the app in the global space,
5+
# everything is package within an /app directory.
6+
WORKDIR /app
7+
8+
# Copy and install any packages/modules needed for your grading script.
9+
COPY requirements.txt .
10+
RUN pip3 install -r requirements.txt
11+
12+
# Copy the schema needed to check the incoming data is valid
13+
COPY schema.json ./app/
14+
15+
# Copy the grading and testing scripts
16+
COPY algorithm.py ./app/
17+
COPY tests/ ./app/tests/
18+
19+
# Set permissions so files and directories can be accessed on AWS
20+
RUN chmod 644 $(find . -type f)
21+
RUN chmod 755 $(find . -type d)
22+
23+
# The entrypoint for AWS is to invoke the handler function within the app package
24+
CMD ["/app/app.handler"]

app/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .algorithm import grading_function
2+
from .tools import handler, validate_request

app/algorithm.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
def grading_function(body: dict) -> dict:
2+
"""
3+
Function used to grade a student response.
4+
---
5+
The handler function passes only one argument to grading_function(),
6+
which is a dictionary of the structure of the API request body
7+
deserialised from JSON.
8+
9+
The output of this function is what is returned as the API response
10+
and therefore must be JSON-encodable. This is also subject to
11+
standard response specifications.
12+
13+
Any standard python library may be used, as well as any package
14+
available on pip (provided it is added to requirements.txt).
15+
16+
The way you wish to structure you code (all in this function, or
17+
split into many) is entirely up to you. All that matters are the
18+
return types and that grading_function() is the main function used
19+
to output the grading response.
20+
"""
21+
22+
return {
23+
"is_correct": True
24+
}

app/requirements.txt

Whitespace-only changes.

app/schema.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"$schema": "http://json-schema.org/draft/2019-09/schema#",
3+
"title": "Generic schema for the data passed to a grading cloud function.",
4+
"type": "object",
5+
"properties": {
6+
"example": {"const": "property"}
7+
},
8+
"required": ["example"],
9+
"additionalProperties": false
10+
}

app/tests/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .grading import TestGradingFunction
2+
from .validation import TestSchemaValidation

app/tests/grading.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import unittest
2+
3+
from ..algorithm import grading_function
4+
5+
class TestGradingFunction(unittest.TestCase):
6+
"""
7+
TestCase Class used to test the algorithm.
8+
---
9+
Tests are used here to check that the algorithm written
10+
is working as it should.
11+
12+
It's best practise to write these tests first to get a
13+
kind of 'specification' for how your algorithm should
14+
work, and you should run these tests before committing
15+
your code to AWS.
16+
17+
Read the docs on how to use unittest here:
18+
https://docs.python.org/3/library/unittest.html
19+
20+
Use grading_function() to check your algorithm works
21+
as it should.
22+
"""
23+
def test_returns_is_correct_true(self):
24+
body = {}
25+
26+
response = grading_function(body)
27+
28+
self.assertEqual(response.get("is_correct"), True)
29+
30+
if __name__ == "__main__":
31+
unittest.main()

0 commit comments

Comments
 (0)