Skip to content

Commit 70ba4c9

Browse files
authored
Merge pull request #230 from Harvard-University-iCommons/task/haydn9000/TLT-5203/uv-ruff-codeartifact-update
Migration to use uv + ruff
2 parents cd1d970 + 4d8db7d commit 70ba4c9

73 files changed

Lines changed: 4090 additions & 2234 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
name: Build Container
2+
on:
3+
push:
4+
branches:
5+
- 'develop'
6+
tags:
7+
- 'v*'
8+
pull_request:
9+
branches:
10+
- 'develop'
11+
12+
# Allows you to run this workflow manually from the Actions tab
13+
workflow_dispatch:
14+
15+
16+
env:
17+
ENV: build
18+
DJANGO_SETTINGS_MODULE: lti_emailer.settings.local
19+
AWS_REGION: 'us-east-1'
20+
AWS_ROLE: arn:aws:iam::482956169056:role/uw-lti-emailer-github-actions-role
21+
REPOSITORY: 'uw/lti-emailer'
22+
ECR_HOST: '482956169056.dkr.ecr.us-east-1.amazonaws.com'
23+
ECS_CLUSTER: 'default'
24+
ECS_SERVICE: 'uw-lti-emailer-service-dev-1-4-0'
25+
ECS_TASK_DEFINITION: 'uw-lti-emailer-task-dev'
26+
CONTAINER_NAME: 'uw-lti-emailer-container-dev'
27+
UV_INDEX_PRIVATE_REGISTRY_USERNAME: aws
28+
29+
30+
jobs:
31+
quality-checks:
32+
runs-on: ubuntu-latest
33+
34+
steps:
35+
- name: Checkout repository
36+
uses: actions/checkout@v4
37+
38+
- name: Lint with ruff
39+
uses: astral-sh/ruff-action@v3
40+
41+
- name: Check formatting with ruff
42+
run: ruff format --check
43+
44+
# could run tests here, but we don't have any tests yet
45+
46+
build-and-push-image:
47+
runs-on: ubuntu-latest
48+
needs: quality-checks
49+
50+
permissions:
51+
contents: read
52+
packages: write
53+
id-token: write # This is required for requesting the JWT
54+
55+
steps:
56+
- name: Checkout repository
57+
uses: actions/checkout@v4
58+
59+
- name: Configure AWS Credentials
60+
uses: aws-actions/configure-aws-credentials@v4
61+
with:
62+
role-to-assume: ${{ env.AWS_ROLE }}
63+
role-session-name: GitHub_to_AWS_via_FederatedOIDC
64+
aws-region: ${{ env.AWS_REGION }}
65+
mask-aws-account-id: 'no'
66+
67+
- name: Get CodeArtifact authorization token
68+
id: codeartifact-auth
69+
run: |
70+
echo "UV_INDEX_PRIVATE_REGISTRY_PASSWORD=$(aws codeartifact get-authorization-token --domain huit-academic-technology --query authorizationToken --output text)" >> $GITHUB_ENV
71+
echo "Successfully retrieved CodeArtifact authorization token"
72+
73+
- name: Login to Amazon ECR
74+
id: login-ecr
75+
uses: aws-actions/amazon-ecr-login@v2
76+
with:
77+
mask-password: 'true'
78+
79+
# SSH agent will no longer be required once we switch to
80+
# using CodeArtifact for all private package dependencies
81+
- name: Setup ssh agent
82+
uses: webfactory/ssh-agent@v0.9.1
83+
with:
84+
ssh-private-key: ${{ secrets.DEPLOY_SSH_KEY }}
85+
86+
- name: Configure docker image metadata
87+
id: docker_meta
88+
uses: docker/metadata-action@v5
89+
with:
90+
images: ${{ steps.login-ecr.outputs.registry }}/${{ env.REPOSITORY }}
91+
flavor: |
92+
latest=false
93+
tags: |
94+
type=semver,pattern={{version}}
95+
type=sha,format=long,prefix=sha-,suffix=${{ startsWith(github.ref, 'refs/tags/v') && format('-{0}', github.ref_name) || '' }}
96+
type=sha,format=short,prefix=sha-,suffix=${{ startsWith(github.ref, 'refs/tags/v') && format('-{0}', github.ref_name) || '' }}
97+
type=ref,event=branch
98+
type=ref,event=tag
99+
type=raw,value=${{ github.event.after }}
100+
101+
- name: Generate build_info.py
102+
run: |
103+
# Get the short version of the SHA (Note: this commit SHA is the last commit in the push event that triggered the workflow).
104+
SHORT_SHA=$(echo ${{ github.event.after }} | cut -c1-7)
105+
106+
echo "BUILD_INFO = {" > build_info.py
107+
echo " 'resolved_source_version': '${{ github.sha }}'," >> build_info.py
108+
echo " 'source_version': '${{ github.ref_name }}'," >> build_info.py
109+
echo " 'build_timestamp': '$(date "+%Y-%m-%dT%H:%M:%S%z")'," >> build_info.py
110+
echo " 'image_tag': '${{ github.ref_name }}'," >> build_info.py
111+
echo " 'image_hash_tag': '$SHORT_SHA'," >> build_info.py
112+
echo "}" >> build_info.py
113+
114+
- name: Build and push
115+
id: build_and_push
116+
uses: docker/build-push-action@v5
117+
with:
118+
context: .
119+
ssh: default=${{ env.SSH_AUTH_SOCK }}
120+
secrets: UV_INDEX_PRIVATE_REGISTRY_PASSWORD=${{ env.UV_INDEX_PRIVATE_REGISTRY_PASSWORD }}
121+
push: true
122+
tags: ${{ steps.docker_meta.outputs.tags }}
123+
labels: ${{ steps.docker_meta.outputs.labels }}
124+
build-args: |
125+
BUILD_VERSION=${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.version'] }}
126+
BUILD_REVISION=${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.revision'] }}
127+
128+
- name: Download task definition
129+
run: |
130+
aws ecs describe-task-definition --task-definition ${{ env.ECS_TASK_DEFINITION }} --query taskDefinition > task-definition.json
131+
132+
- name: Fill in the new image ID in the Amazon ECS task definition
133+
id: task-def
134+
uses: aws-actions/amazon-ecs-render-task-definition@v1
135+
with:
136+
task-definition: task-definition.json
137+
container-name: ${{ env.CONTAINER_NAME }}
138+
image: ${{ env.ECR_HOST }}/${{ env.REPOSITORY }}:${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.version'] }}
139+
environment-variables: |
140+
BUILD_VERSION=${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.version'] }}
141+
BUILD_REVISION=${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.revision'] }}
142+
BUILD_TIMESTAMP=${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.created'] }}
143+
BUILD_REF=${{ github.ref }}
144+
BUILD_REF_NAME=${{ github.ref_name }}
145+
BUILD_REF_TYPE=${{ github.ref_type }}
146+
147+
- name: Deploy Amazon ECS task definition
148+
uses: aws-actions/amazon-ecs-deploy-task-definition@v2
149+
with:
150+
task-definition: ${{ steps.task-def.outputs.task-definition }}
151+
service: ${{ env.ECS_SERVICE }}
152+
cluster: ${{ env.ECS_CLUSTER }}
153+
wait-for-service-stability: false

Dockerfile

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
1-
# syntax=docker/dockerfile:experimental
1+
# syntax=docker/dockerfile:1
22

3-
FROM 482956169056.dkr.ecr.us-east-1.amazonaws.com/uw/python-postgres-build:v3.10 as build
4-
COPY lti_emailer/requirements/*.txt /code/
5-
RUN --mount=type=ssh,id=build_ssh_key ./python_venv/bin/pip install gunicorn && ./python_venv/bin/pip install -r aws.txt
6-
COPY . /code/
3+
FROM python:3.10-slim-bookworm as build
4+
COPY --from=ghcr.io/astral-sh/uv:0.7.22 /uv /uvx /bin/
5+
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=0 UV_INDEX_PRIVATE_REGISTRY_USERNAME=aws
6+
7+
RUN apt-get update; apt-get install -y --no-install-recommends git libpq-dev build-essential openssh-client
8+
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
9+
WORKDIR /code
10+
RUN --mount=type=cache,target=/root/.cache/uv \
11+
--mount=type=bind,source=uv.lock,target=uv.lock \
12+
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
13+
--mount=type=ssh \
14+
--mount=type=secret,id=UV_INDEX_PRIVATE_REGISTRY_PASSWORD,env=UV_INDEX_PRIVATE_REGISTRY_PASSWORD \
15+
uv sync --locked --no-install-project --no-dev --keyring-provider disabled -v
16+
COPY . /code
17+
RUN --mount=type=cache,target=/root/.cache/uv \
18+
--mount=type=ssh \
19+
--mount=type=secret,id=UV_INDEX_PRIVATE_REGISTRY_PASSWORD,env=UV_INDEX_PRIVATE_REGISTRY_PASSWORD \
20+
uv sync --locked --no-dev --extra aws --keyring-provider disabled -v
721
RUN chmod a+x /code/docker-entrypoint.sh
822

9-
FROM 482956169056.dkr.ecr.us-east-1.amazonaws.com/uw/python-postgres-base:v3.10
10-
COPY --from=build /code /code/
23+
FROM python:3.10-slim-bookworm
24+
RUN apt-get update; apt-get install -y --no-install-recommends git libpq5
25+
COPY --from=build /code /code
26+
ENV PATH="/code/.venv/bin:$PATH"
1127
ENV PYTHONUNBUFFERED 1
1228
WORKDIR /code
1329
ENTRYPOINT ["/code/docker-entrypoint.sh"]
14-
EXPOSE 8000
30+
EXPOSE 8000

batv_test.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,22 @@
44
# Import the email modules we'll need
55
from email.mime.text import MIMEText
66

7-
from_addr = 'colin_murtaugh@harvard.edu'
8-
to_addr = 'canvas-4998@mg.dev.tlt.harvard.edu'
7+
from_addr = "colin_murtaugh@harvard.edu"
8+
to_addr = "canvas-4998@mg.dev.tlt.harvard.edu"
99

1010
# envelope_addr = from_addr
11-
envelope_addr = 'prvs=764a7a4cd={}'.format(from_addr)
11+
envelope_addr = "prvs=764a7a4cd={}".format(from_addr)
1212

13-
body = 'This is a message for testing the LTI emailer. Envelope address: {}'.format(envelope_addr)
13+
body = "This is a message for testing the LTI emailer. Envelope address: {}".format(
14+
envelope_addr
15+
)
1416

1517
msg = MIMEText(body)
16-
msg['From'] = from_addr
17-
msg['To'] = to_addr
18-
msg['Subject'] = 'Test message'
18+
msg["From"] = from_addr
19+
msg["To"] = to_addr
20+
msg["Subject"] = "Test message"
1921

2022

21-
s = smtplib.SMTP('mailhub.harvard.edu')
23+
s = smtplib.SMTP("mailhub.harvard.edu")
2224
s.sendmail(envelope_addr, [to_addr], msg.as_string())
2325
s.quit()

docker-entrypoint.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#!/bin/sh
22

3-
./python_venv/bin/python manage.py migrate # Apply database migrations
4-
./python_venv/bin/python manage.py collectstatic --noinput # Collect static files
3+
python manage.py migrate # Apply database migrations
4+
python manage.py collectstatic --noinput # Collect static files
55

66
# Start Gunicorn processes
77
echo Starting Gunicorn.
8-
exec ./python_venv/bin/gunicorn -c lti_emailer/settings/gunicorn.conf.py lti_emailer.wsgi:application
8+
exec gunicorn -c lti_emailer/settings/gunicorn.conf.py lti_emailer.wsgi:application

0 commit comments

Comments
 (0)