Skip to content

Commit 98a35b0

Browse files
authored
Adding example application and pipeline (#1)
1 parent b55b693 commit 98a35b0

File tree

8 files changed

+194
-1
lines changed

8 files changed

+194
-1
lines changed

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
__pycache__/
2+
.pytest_cache
3+
*.py[cod]
4+
*.log
5+
db.sqlite3
6+
.env
7+
.venv
8+
venv/
9+
10+
.idea/

.iceci.yaml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
globals:
2+
onFailure:
3+
# This failure handler will be called failed of any step in the pipeline
4+
# comment this out if you do not want to integrate pipeline with slack
5+
- handlerName: slack-notify-error
6+
7+
failureHandlers:
8+
- name: debug-env
9+
image: busybox
10+
script: |
11+
echo "### PWD"
12+
pwd
13+
echo "### ENV"
14+
env
15+
echo "ls -la"
16+
ls -la
17+
18+
- name: slack-notify-error
19+
image: iceci/utils
20+
script: |
21+
cat <<EOF > slacknotify.json
22+
{
23+
"text" : "Build $ICE_BUILD_NUMBER on branch $ICE_GIT_BRANCH_NAME failed on step $ICE_FAILED_STEP_NAME commited by $ICE_GIT_AUTHOR_NAME"
24+
}
25+
EOF
26+
curl -X POST -H 'Content-type: application/json' --data "@slacknotify.json" $SLACK_WEBHOOK
27+
environment:
28+
SLACK_WEBHOOK: "{{ slack-webhook }}"
29+
30+
# Service with postgres will run during whole pipeline
31+
services:
32+
- name: db
33+
image: postgres:11
34+
environment:
35+
POSTGRES_DB: testdb
36+
POSTGRES_PASSWORD: dbpass
37+
POSTGRES_USER: dbuser
38+
39+
40+
steps:
41+
- name: run-tests
42+
dockerRun:
43+
image: python:3.7
44+
script: |
45+
pip install -r requirements.txt
46+
pip install -r requirements-test.txt
47+
flask initdb
48+
pytest quotes_tests.py
49+
environment:
50+
QUOTES_DB_URI: "postgresql+psycopg2://dbuser:dbpass@db:5432/testdb"
51+
FLASK_APP: quotes.py
52+
53+
- name: build-docker-image
54+
dockerBuild:
55+
dockerSecret: dockerhub
56+
registry: docker.io
57+
# TODO: change user and image name to repository that you have access to
58+
user: iceci
59+
imageName: example-python-webapp
60+
tag: latest
61+
62+
# comment this step out if you do not want to integrate this pipeline with slack
63+
- name: slack-notify
64+
dockerRun:
65+
image: iceci/utils
66+
script: |
67+
cat <<EOF > slacknotify.json
68+
{
69+
"text" : "Build $ICE_BUILD_NUMBER on branch $ICE_GIT_BRANCH_NAME finished successfully!"
70+
}
71+
EOF
72+
curl -X POST -H 'Content-type: application/json' --data "@slacknotify.json" $SLACK_WEBHOOK
73+
environment:
74+
SLACK_WEBHOOK: "{{ slack-webhook }}"
75+

Dockerfile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
FROM python:3.7
2+
3+
EXPOSE 8080
4+
WORKDIR /code/
5+
ENV PYTHONPATH /code/
6+
7+
ADD requirements.txt .
8+
9+
RUN pip install --no-cache-dir -r requirements.txt && \
10+
pip install gunicorn gevent
11+
12+
ADD quotes.py /code/quotes.py
13+
14+
CMD ["gunicorn", "--worker-class", "gevent", "--access-logfile", "-", "--capture-output", "--enable-stdio-inheritance", "-b", "0.0.0.0:8080", "quotes:app"]

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,18 @@
1-
# example-python-flask-api
1+
# IceCI Python example - Flask API
2+
3+
This repository is a small example to help you get started building **IceCI** pipelines for Python applications.
4+
5+
The application itself is a very simplified example of a web API with tests. It's not by any means a guideline on building Python applications - its only purpose is showcasing how to build IceCI pipelines for Python applications.
6+
7+
This repository is a *GitHub template repository*, so please feel free to create new repositories based on it and mess around with the code and the pipeline config. Please also check the information below for a list of prerequisites needed to run the pipeline in IceCI.
8+
9+
# Setting up IceCI
10+
11+
12+
To launch the pipeline in IceCI you have to create 2 secrets - both of which are explicitly referenced in the `.iceci.yaml` file.
13+
14+
* `dockerhub` - docker hub credentials with `docker.io` set as registry.
15+
16+
* `slack-webhook` - a generic secret with hook for Slack notifications - it can be ignored by commenting out the `slack-notify` step as well as the `slack-notify-error` failure handler in the pipeline definition file.
17+
18+
You can also find some additional info in the comments of the `.iceci.yaml` file itself.

quotes.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import os
2+
3+
from flask import Flask
4+
from flask_sqlalchemy import SQLAlchemy
5+
6+
dburi = os.getenv('QUOTES_DB_URI')
7+
if not dburi:
8+
raise Exception('QUOTES_DB_URI environment variable not set')
9+
10+
app = Flask('fakeapp')
11+
app.config['SQLALCHEMY_DATABASE_URI'] = dburi
12+
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
13+
14+
db = SQLAlchemy(app)
15+
16+
17+
class Quote(db.Model):
18+
id = db.Column(db.Integer, primary_key=True)
19+
quote = db.Column(db.Text)
20+
author = db.Column(db.String(60))
21+
22+
def __repr__(self):
23+
return '<User %r - %r>' % (self.author, self.quote)
24+
25+
26+
@app.route('/')
27+
def hello_world():
28+
return {'message': 'Hello, World!'}
29+
30+
31+
@app.route('/quote')
32+
def quote():
33+
quotes = Quote.query.all()
34+
res = []
35+
for q in quotes:
36+
res.append({
37+
'author': q.author,
38+
'quote': q.quote
39+
})
40+
return {'quotes': res}
41+
42+
43+
@app.cli.command("initdb")
44+
def initdb():
45+
db.create_all()

quotes_tests.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import pytest
2+
import quotes
3+
4+
5+
@pytest.fixture()
6+
def app():
7+
app = quotes.app
8+
return app
9+
10+
11+
@pytest.fixture()
12+
def create_quote():
13+
q = quotes.Quote(author='Guido van Rossum',
14+
quote="Python is an experiment in how much freedom programmers need. Too much freedom and nobody can read another's code; too little and expressiveness is endangered.")
15+
quotes.db.session.add(q)
16+
quotes.db.session.commit()
17+
18+
19+
def test_index(client):
20+
assert client.get('/').status_code == 200
21+
22+
23+
@pytest.mark.usefixtures('create_quote')
24+
def test_quote(client):
25+
result = client.get('/quote')
26+
assert result.status_code == 200
27+
data = result.json
28+
assert len(data['quotes']) == 1

requirements-test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pytest-flask

requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
flask
2+
flask-sqlalchemy
3+
psycopg2-binary

0 commit comments

Comments
 (0)