Skip to content

Commit 6b5b71c

Browse files
authored
Use GitHub actions instead of Travis (#469)
1 parent ab2b07c commit 6b5b71c

File tree

15 files changed

+117
-124
lines changed

15 files changed

+117
-124
lines changed

.github/workflows/actions.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: MapSwipe Workers
2+
3+
on: [push]
4+
5+
jobs:
6+
build:
7+
8+
runs-on: ubuntu-latest
9+
strategy:
10+
matrix:
11+
python-version: [3.8]
12+
13+
steps:
14+
- uses: actions/checkout@v2
15+
- name: Set up Python ${{ matrix.python-version }}
16+
uses: actions/setup-python@v2
17+
with:
18+
python-version: ${{ matrix.python-version }}
19+
- name: Install dependencies
20+
working-directory: ./mapswipe_workers
21+
run: |
22+
python -m pip install --upgrade pip
23+
pip install flake8 black==19.10b0 isort
24+
- name: Code style
25+
working-directory: ./mapswipe_workers
26+
run: |
27+
black --check mapswipe_workers
28+
flake8 --count --config setup.cfg mapswipe_workers/
29+
isort --check --settings-file setup.cfg mapswipe_workers/
30+
- name: Setup Postgres Database Container
31+
env:
32+
POSTGRES_PASSWORD: test
33+
POSTGRES_USER: test
34+
POSTGRES_DB: test
35+
run: |
36+
# Create a mock file for wal-g setup
37+
touch postgres/serviceAccountKey.json
38+
docker-compose up --build --detach postgres
39+
- name: Deploy Firebase Rules and Functions
40+
env:
41+
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
42+
FIREBASE_DB: ${{ secrets.FIREBASE_DB }}
43+
run: |
44+
# Create a mock file for wal-g setup
45+
docker-compose up --build firebase_deploy
46+
- name: Decrypt Service Account Key File
47+
working-directory: ./
48+
run: |
49+
openssl enc -aes-256-cbc -d -K "$OPENSSL_KEY" -iv "$OPENSSL_IV" -in ci-mapswipe-firebase-adminsdk-80fzw-ebce84bd5b.json.enc -out mapswipe_workers/serviceAccountKey.json
50+
env:
51+
OPENSSL_PASSPHRASE: ${{ secrets.OPENSSL_PASSPHRASE }}
52+
OPENSSL_KEY: ${{ secrets.OPENSSL_KEY }}
53+
OPENSSL_IV: ${{ secrets.OPENSSL_IV }}
54+
- name: Run Tests
55+
working-directory: ./mapswipe_workers
56+
env:
57+
FIREBASE_API_KEY: ${{ secrets.FIREBASE_API_KEY }}
58+
FIREBASE_DB: ${{ secrets.FIREBASE_DB }}
59+
POSTGRES_PASSWORD: test
60+
POSTGRES_USER: test
61+
POSTGRES_DB: test
62+
run: |
63+
docker-compose run mapswipe_workers_creation python -m unittest discover --verbose --start-directory tests/unittests/
64+
docker-compose run mapswipe_workers_creation python -m unittest discover --verbose --start-directory tests/integration/

.travis.yml

Lines changed: 0 additions & 58 deletions
This file was deleted.
2.28 KB
Binary file not shown.

docs/source/deployment_overview.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,9 @@ This is done by using Travis script deployment (https://docs.travis-ci.com/user/
2525
To be able to connect to the MapSwipe server the Travis instance uses an encrypted SSH private key (Which can be found in the directory `travis/`).
2626

2727
In the `deploy.sh` script an Ansible Playbook is run (https://docs.ansible.com/ansible/latest/index.html). Ansible is an automation tool which utilizes a SSH connection (`ansible/ansible.cfg`) to run commands defined in the Playbook (`ansible/playbook.yml`) on hosts defined in the Inventory (`ansible/inventory.yml`).
28+
29+
## Continuous Deployment with Github Actions
30+
We use an encrypted service account key file. The file has been generated with this commands:
31+
32+
`openssl enc -aes-256-cbc -e -p -nosalt -in=ci-mapswipe-firebase-adminsdk-80fzw-ebce84bd5b.json -out=ci-mapswipe-firebase-adminsdk-80fzw-ebce84bd5b.json.enc`
33+

mapswipe_workers/mapswipe_workers/firebase_to_postgres/update_data.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,16 @@ def set_progress_in_firebase(project_id: str):
133133
query = """
134134
-- Calculate overall project progress as
135135
-- the average progress for all groups.
136-
-- This is not hundred percent exact, since groups can have a different number of tasks
136+
-- This is not hundred percent exact
137+
-- since groups can have a different number of tasks
137138
-- but it is still "good enough" and gives almost correct progress.
138139
-- But it is easier to compute
139140
-- than considering the actual number of tasks per group.
140141
select
141142
project_id
142143
,avg(group_progress)::integer as progress
143144
from
144-
(
145+
(
145146
-- Get all groups for this project and
146147
-- add progress for groups that have been worked on already.
147148
-- Set progress to 0 if no user has worked on this group.
@@ -155,7 +156,7 @@ def set_progress_in_firebase(project_id: str):
155156
else group_progress
156157
end as group_progress
157158
from groups g
158-
left join
159+
left join
159160
(
160161
-- Here we get the progress for all groups
161162
-- for which results have been submitted already.
@@ -170,13 +171,13 @@ def set_progress_in_firebase(project_id: str):
170171
else 100 * count(distinct user_id) / p.verification_number
171172
end as group_progress
172173
from results r, projects p
173-
where r.project_id = p.project_id
174-
group by group_id, r.project_id, p.verification_number
174+
where r.project_id = p.project_id
175+
group by group_id, r.project_id, p.verification_number
175176
) bar
176177
on bar.group_id = g.group_id and bar.project_id = g.project_id
177-
where g.project_id = %s
178-
) foo
179-
group by project_id
178+
where g.project_id = %s
179+
) foo
180+
group by project_id
180181
"""
181182
data = [project_id]
182183
progress = pg_db.retr_query(query, data)[0][1]
@@ -195,15 +196,17 @@ def set_contributor_count_in_firebase(project_id: str):
195196
select
196197
project_id
197198
,count(distinct user_id) contributor_count
198-
from results r
199-
where
200-
project_id = %s
201-
group by project_id
199+
from results r
200+
where
201+
project_id = %s
202+
group by project_id
202203
"""
203204
data = [project_id]
204205
contributor_count = pg_db.retr_query(query, data)[0][1]
205206

206207
fb_db = auth.firebaseDB()
207208
project_progress_ref = fb_db.reference(f"v2/projects/{project_id}/contributorCount")
208209
project_progress_ref.set(contributor_count)
209-
logger.info(f"set contributorCount attribute for project {project_id}: {contributor_count}")
210+
logger.info(
211+
f"set contributorCount attribute for project {project_id}: {contributor_count}"
212+
)

mapswipe_workers/mapswipe_workers/generate_stats/project_stats.py

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import datetime
2-
import os
3-
from typing import List
42
import gzip
3+
import os
54
import tempfile
5+
from typing import List
66

77
import pandas as pd
88
from psycopg2 import sql
@@ -34,12 +34,12 @@ def write_sql_to_gzipped_csv(filename: str, sql_query: sql.SQL):
3434
"""
3535

3636
# generate temporary file which will be automatically deleted at the end
37-
tmp_csv_file = os.path.join(tempfile._get_default_tempdir(), 'tmp.csv')
37+
tmp_csv_file = os.path.join(tempfile._get_default_tempdir(), "tmp.csv")
3838
pg_db = auth.postgresDB()
3939
with open(tmp_csv_file, "w") as f:
4040
pg_db.copy_expert(sql_query, f)
4141

42-
with open(tmp_csv_file, 'rb') as f_in, gzip.open(filename, 'wb') as f_out:
42+
with open(tmp_csv_file, "rb") as f_in, gzip.open(filename, "wb") as f_out:
4343
f_out.writelines(f_in)
4444

4545
logger.info(f"wrote gzipped csv file from sql: {filename}")
@@ -52,11 +52,7 @@ def load_df_from_csv(filename: str) -> pd.DataFrame:
5252
"""
5353
dtype_dict = {"project_id": str, "group_id": str, "task_id": str}
5454

55-
df = pd.read_csv(
56-
filename,
57-
dtype=dtype_dict,
58-
compression="gzip"
59-
)
55+
df = pd.read_csv(filename, dtype=dtype_dict, compression="gzip")
6056
logger.info(f"loaded pandas df from {filename}")
6157
return df
6258

@@ -337,7 +333,9 @@ def get_per_project_statistics(project_id: str, project_info: pd.Series) -> dict
337333
results_filename = f"{DATA_PATH}/api/results/results_{project_id}.csv.gz"
338334
tasks_filename = f"{DATA_PATH}/api/tasks/tasks_{project_id}.csv.gz"
339335
groups_filename = f"{DATA_PATH}/api/groups/groups_{project_id}.csv.gz"
340-
agg_results_filename = f"{DATA_PATH}/api/agg_results/agg_results_{project_id}.csv.gz"
336+
agg_results_filename = (
337+
f"{DATA_PATH}/api/agg_results/agg_results_{project_id}.csv.gz"
338+
)
341339
agg_results_by_user_id_filename = f"{DATA_PATH}/api/users/users_{project_id}.csv.gz"
342340
project_stats_by_date_filename = f"{DATA_PATH}/api/history/history_{project_id}.csv"
343341

@@ -358,15 +356,12 @@ def get_per_project_statistics(project_id: str, project_info: pd.Series) -> dict
358356

359357
# aggregate results by task id
360358
agg_results_df = get_agg_results_by_task_id(results_df, tasks_df)
361-
agg_results_df.to_csv(
362-
agg_results_filename,
363-
index_label="idx"
364-
)
359+
agg_results_df.to_csv(agg_results_filename, index_label="idx")
365360

366361
geojson_functions.gzipped_csv_to_gzipped_geojson(
367362
filename=agg_results_filename,
368363
geometry_field="geom",
369-
add_metadata=add_metadata
364+
add_metadata=add_metadata,
370365
)
371366
logger.info(f"saved agg results for {project_id}: {agg_results_filename}")
372367

@@ -377,8 +372,7 @@ def get_per_project_statistics(project_id: str, project_info: pd.Series) -> dict
377372
results_df, agg_results_df
378373
)
379374
agg_results_by_user_id_df.to_csv(
380-
agg_results_by_user_id_filename,
381-
index_label="idx"
375+
agg_results_by_user_id_filename, index_label="idx"
382376
)
383377
logger.info(
384378
f"saved agg results for {project_id}: {agg_results_by_user_id_filename}"
@@ -404,8 +398,7 @@ def get_per_project_statistics(project_id: str, project_info: pd.Series) -> dict
404398
logger.info(f"do NOT generate tasking manager geometries for {project_id}")
405399
else:
406400
tasking_manager_geometries.generate_tasking_manager_geometries(
407-
project_id=project_id,
408-
agg_results_filename=agg_results_filename
401+
project_id=project_id, agg_results_filename=agg_results_filename
409402
)
410403

411404
# prepare output of function

mapswipe_workers/mapswipe_workers/generate_stats/project_stats_by_date.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ def get_progress_by_date(
6464
- sum of daily number of results up to that day
6565
6666
progress:
67-
- relative progress per day (e.g. overall progress increased by 0.15 on that day)
67+
- relative progress per day
68+
(e.g. overall progress increased by 0.15 on that day)
6869
- not used in firebase
6970
7071
cum_progress:

mapswipe_workers/mapswipe_workers/mapswipe_workers.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,7 @@ def run_create_projects():
100100
except UnboundLocalError:
101101
project_id = None
102102

103-
send_slack_message(
104-
MessageType.FAIL, project_name, project_id, str(e)
105-
)
103+
send_slack_message(MessageType.FAIL, project_name, project_id, str(e))
106104
logger.exception("Failed: Project Creation ({0}))".format(project_name))
107105
sentry.capture_exception()
108106
continue
@@ -386,15 +384,15 @@ def run_delete_project(project_id, project_ids):
386384

387385
@cli.command("run")
388386
@click.option(
389-
"--analysis_type",
390-
"-a",
391-
default="all",
392-
help=(
393-
f"Will either execute all or just the specified functions of the analysis "
394-
f"choices here"
395-
),
396-
type=click.Choice(["all", "creation", "stats"]),
397-
)
387+
"--analysis_type",
388+
"-a",
389+
default="all",
390+
help=(
391+
"Will either execute all or just the specified functions of the analysis "
392+
"choices here"
393+
),
394+
type=click.Choice(["all", "creation", "stats"]),
395+
)
398396
@click.option("--schedule", is_flag=True, help="Schedule jobs to run every 10 minutes.")
399397
@click.pass_context
400398
def run(context, analysis_type, schedule):

mapswipe_workers/mapswipe_workers/project_types/base/tile_server.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,3 @@ def check_imagery_url(self):
5151
return True
5252
else:
5353
return False
54-

mapswipe_workers/mapswipe_workers/utils/geojson_functions.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import gzip
12
import json
23
import os
3-
import gzip
44
import shutil
55
import subprocess
66
import tempfile
@@ -11,9 +11,7 @@
1111

1212

1313
def gzipped_csv_to_gzipped_geojson(
14-
filename: str,
15-
geometry_field: str = "geom",
16-
add_metadata: bool = False
14+
filename: str, geometry_field: str = "geom", add_metadata: bool = False
1715
):
1816
"""Convert gzipped csv file to gzipped GeoJSON.
1917
@@ -22,13 +20,13 @@ def gzipped_csv_to_gzipped_geojson(
2220
Last, the generated geojson file is again compressed using gzip.
2321
"""
2422
# generate temporary files which will be automatically deleted at the end
25-
tmp_csv_file = os.path.join(tempfile._get_default_tempdir(), 'tmp.csv')
26-
tmp_geojson_file = os.path.join(tempfile._get_default_tempdir(), 'tmp.geojson')
23+
tmp_csv_file = os.path.join(tempfile._get_default_tempdir(), "tmp.csv")
24+
tmp_geojson_file = os.path.join(tempfile._get_default_tempdir(), "tmp.geojson")
2725

2826
outfile = filename.replace(".csv", f"_{geometry_field}.geojson")
2927

3028
# uncompress content of zipped csv file and save to csv file
31-
with gzip.open(filename, 'rb') as f_in:
29+
with gzip.open(filename, "rb") as f_in:
3230
with open(tmp_csv_file, "wb") as f_out:
3331
shutil.copyfileobj(f_in, f_out)
3432

@@ -56,7 +54,7 @@ def gzipped_csv_to_gzipped_geojson(
5654
with open(tmp_geojson_file, "r") as f:
5755
json_data = json.load(f)
5856

59-
with gzip.open(outfile, 'wt') as fout:
57+
with gzip.open(outfile, "wt") as fout:
6058
json.dump(json_data, fout)
6159

6260
logger.info(f"converted {filename} to {outfile} with ogr2ogr.")

0 commit comments

Comments
 (0)