Skip to content

Commit d42190b

Browse files
authored
add CI/CD setup, improve github tests
run lint, typecheck and tests on CI. Deploy on merge to main
1 parent 3d95750 commit d42190b

File tree

9 files changed

+357
-11
lines changed

9 files changed

+357
-11
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Build Test and Lint
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
build-test-and-lint:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v3
16+
17+
- name: Set up Docker Buildx
18+
uses: docker/setup-buildx-action@v2
19+
20+
- name: Cache Docker layers
21+
uses: actions/cache@v3
22+
with:
23+
path: /tmp/.buildx-cache
24+
key: ${{ runner.os }}-buildx-${{ github.sha }}
25+
restore-keys: |
26+
${{ runner.os }}-buildx-
27+
28+
- name: Build Docker image
29+
run: |
30+
make docker/build
31+
32+
- name: Run Docker container for tests
33+
run: |
34+
docker run --rm \
35+
-e DJANGO_SETTINGS_MODULE=intbot.settings \
36+
-e DATABASE_URL=postgres://testuser:testpassword@localhost:5432/testdb \
37+
--network host \
38+
intbot \
39+
make in-container/tests
40+
41+
- name: Run Docker container for lint
42+
run: |
43+
docker run --rm intbot make ci/lint
44+
docker run --rm intbot make ci/type-check
45+
46+
services:
47+
postgres:
48+
image: postgres:16.4
49+
env:
50+
POSTGRES_USER: intbot_user
51+
POSTGRES_PASSWORD: intbot_password
52+
POSTGRES_DB: intbot_database_test
53+
ports:
54+
- 14672:5432
55+
options: >-
56+
--health-cmd="pg_isready -U intbot_user -d intbot_database_test"
57+
--health-interval=10s
58+
--health-timeout=5s
59+
--health-retries=5
60+

.github/workflows/deploy.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Deploy latest version of the app
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
deploy:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout code
14+
uses: actions/checkout@v3
15+
16+
- name: Install uv
17+
uses: astral-sh/setup-uv@v5
18+
19+
- name: Run deployment
20+
run: make deploy/app

Makefile

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ UV_RUN_DEV=cd intbot && DJANGO_ENV="dev" uv run
77

88
# Docker
99
DOCKER_RUN_WITH_PORT=docker run -p 4672:4672 --add-host=host.internal:host-gateway -e DJANGO_ENV="local_container" -it intbot:$(V)
10+
DOCKER_RUN=docker run --add-host=host.internal:host-gateway -e DJANGO_ENV="test" -it intbot:$(V)
1011
MANAGE=cd intbot && ./manage.py
12+
# In container we run with migrations
13+
CONTAINER_TEST_CMD=DJANGO_SETTINGS_MODULE="intbot.settings" DJANGO_ENV="test" pytest --migrations
14+
CI_RUN=cd intbot && DJANGO_SETTINGS_MODULE="intbot.settings" DJANGO_ENV="ci"
1115

1216
# Deployment
1317
DEPLOY_CMD=cd deploy && uvx --from "ansible-core" ansible-playbook -i hosts.yml
@@ -108,16 +112,32 @@ in-container/migrate:
108112
in-container/manage:
109113
$(MANAGE) $(ARG)
110114

115+
in-container/tests:
116+
$(CONTAINER_TEST_CMD) -vvv
117+
118+
ci/lint:
119+
$(CI_RUN) ruff check .
120+
121+
ci/type-check:
122+
$(CI_RUN) mypy intbot
123+
111124

112125
# Docker management targets
113126
# =========================
114127

115128
docker/build:
116-
docker build . -t intbot:$(current_git_hash)
129+
docker build . -t intbot:$(current_git_hash) -t intbot:latest
117130

118131
docker/run/gunicorn:
119132
$(DOCKER_RUN_WITH_PORT) make in-container/gunicorn
120133

134+
docker/run/tests:
135+
$(DOCKER_RUN) make in-container/tests
136+
137+
docker/run/lint:
138+
$(DOCKER_RUN) make ci/lint
139+
$(DOCKER_RUN) make ci/type-check
140+
121141

122142
# Deploymenet targets
123143
# ====================

intbot/core/integrations/github.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ def fetch_github_item_details(item_id):
8484

8585

8686
class GithubProjectV2Item:
87+
# NOTE: This might be something for pydantic schemas in the future
88+
8789
def __init__(self, content: dict):
8890
self.content = content
8991

@@ -107,30 +109,30 @@ def content_type(self):
107109
return self.content["projects_v2_item"]["content_type"]
108110

109111
def node_id(self):
110-
# NOTE(artcz): This is more relevant, because of how the graphql query
111-
# above is constructed.
112+
# NOTE(artcz): This is relevant, because of how the graphql query above
113+
# is constructed.
112114
# Using node_id, which is an id of a ProjectV2Item we can get both
113115
# DraftIssue and Issue from one query.
114-
# If we use the content_node_id we need to adjust the query as that ID
115-
# points us directly either an Issue or DraftIssue
116+
# If we use the content_node_id we would probably need two separate
117+
# ways of getting that data.
116118
return self.content["projects_v2_item"]["node_id"]
117119

118-
def content_node_id(self):
119-
return self.content["projects_v2_item"]["content_node_id"]
120-
121120
def changes(self) -> dict:
122121
if "changes" in self.content:
123122
fv = self.content["changes"]["field_value"]
124123
field_name = fv["field_name"]
125124
field_type = fv["field_type"]
125+
126126
if field_type == "date":
127127
changed_from = (
128128
fv["from"].split("T")[0] if fv["from"] is not None else "None"
129129
)
130130
changed_to = fv["to"].split("T")[0] if fv["to"] is not None else "None"
131+
131132
elif field_type == "single_select":
132133
changed_from = fv["from"]["name"] if fv["from"] is not None else "None"
133134
changed_to = fv["to"]["name"] if fv["to"] is not None else "None"
135+
134136
else:
135137
changed_from = "None"
136138
changed_to = "None"
@@ -152,8 +154,9 @@ def as_discord_message(self, github_object: GithubDraftIssue | GithubIssue) -> s
152154
changes = self.changes()
153155

154156
if changes:
155-
details = "**{field}** of **{obj}** from **{from}** to **{to}**".format
156-
details = details(**{"obj": github_object.as_discord_message(), **changes})
157+
details = "**{field}** of **{obj}** from **{from}** to **{to}**".format(
158+
**{"obj": github_object.as_discord_message(), **changes}
159+
)
157160

158161
else:
159162
details = github_object.as_discord_message()

intbot/intbot/settings.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import os
1414
import warnings
15+
from typing import Any
1516
from pathlib import Path
1617

1718
# Build paths inside the project like this: BASE_DIR / 'subdir'.
@@ -112,6 +113,9 @@
112113
DJANGO_ENV = os.environ["DJANGO_ENV"]
113114
APP_VERSION = os.environ.get("APP_VERSION", "latest")[:8]
114115

116+
# Just to make mypy happy
117+
TASKS: dict[str, Any]
118+
115119
if DJANGO_ENV == "dev":
116120
DEBUG = True
117121
ALLOWED_HOSTS = ["127.0.0.1", "localhost"]
@@ -306,5 +310,8 @@ def warn_if_missing(name, default=""):
306310
# Currently used only for collecting staticfiles in docker
307311
DEBUG = False
308312

313+
elif DJANGO_ENV == "ci":
314+
DEBUG = False
315+
309316
else:
310317
raise ValueError(f"Unsupported DJANGO_ENV `{DJANGO_ENV}`")

0 commit comments

Comments
 (0)