Skip to content

Commit

Permalink
Add linter to PR and minify Docker image (#3)
Browse files Browse the repository at this point in the history
* Add linters for PR
* Update Dockerfile and Docker image
* Update building process
* Update a Python version to 3.12
  • Loading branch information
jag-k authored Nov 30, 2023
1 parent 2fc6344 commit b08d46a
Show file tree
Hide file tree
Showing 15 changed files with 345 additions and 88 deletions.
6 changes: 2 additions & 4 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
.env
NPSdir
TORRENTdir
.editorconfig
.gitignore
app/config/local.py
.dockerignore
docker-compose.yml
docker-compose.local.yml
wiki/
.*
26 changes: 26 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

assignees:
- "jag-k"

# Maintain dependencies for Poetry
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"

# Include a list of updated dependencies
# with a prefix determined by the dependency group
commit-message:
prefix: "poetry"
prefix-development: "poetry dev"
include: "scope"

assignees:
- "jag-k"
1 change: 1 addition & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ changelog:
- ignore-for-release
authors:
- octocat
- dependabot
categories:
- title: Breaking Changes 🛠
labels:
Expand Down
123 changes: 100 additions & 23 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,64 +9,141 @@ on:
branches: [ "main" ]
tags:
- "v*.*.*"
pull_request:
types: [ closed ]
branches:
- 'release/*.*.*'
workflow_dispatch:

permissions:
contents: write
packages: write
pull-requests: write

jobs:
build:
lint:
runs-on: ubuntu-latest

permissions:
contents: read
packages: write
outputs:
version: ${{ steps.get_version.outputs.version }}
is_pr: ${{ steps.release.outputs.is_pr == 'true'}}
is_tag: ${{ steps.release.outputs.is_tag == 'true'}}
is_release: ${{ steps.release.outputs.is_release == 'true'}}

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install poetry
run: pipx install poetry
- uses: actions/setup-python@v4
with:
python-version: '3.12'
cache: 'poetry'
- name: Install dependencies
run: poetry install

- name: Get version from pyproject.toml
id: get_version
run: |
echo "version=$(poetry version -s)" >> $GITHUB_OUTPUT
- name: Is it a releasable?
id: release
run: |
is_pr="${{ github.event_name == 'pull_request' && github.event.pull_request.merged == true }}"
is_tag="${{ startsWith(github.ref, 'refs/tags/') }}"
[[ "$is_pr" == "true" || "$is_tag" == "true" ]] && is_release=true || is_release=false
echo "is_pr=$is_pr" >> $GITHUB_OUTPUT
echo "is_tag=$is_tag" >> $GITHUB_OUTPUT
echo "is_release=$is_release" >> $GITHUB_OUTPUT
- name: Run Ruff
run: poetry run ruff check --output-format=github .

- name: Run pre-commit hooks
run: poetry run pre-commit run --all-files --show-diff-on-failure


build:
needs:
- lint
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3

- name: Log in to the Container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Get version from pyproject.toml
id: get_version
run: |
echo "version=$(grep -E '^\[tool\.poetry\]$' -A 4 pyproject.toml | grep -E '^version' | sed 's/version = "//;s/"$//')" >> $GITHUB_OUTPUT
- name: Get short SHA
id: slug
run: echo "sha=$(echo ${GITHUB_SHA} | cut -c1-7)" >> $GITHUB_OUTPUT
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
tags: |
type=ref,event=branch
type=sha
type=semver,pattern={{version}},value=${{ needs.lint.outputs.version }},enabled=${{ needs.lint.outputs.is_release }}
type=semver,pattern={{major}}.{{minor}},value=${{ needs.lint.outputs.version }},enabled=${{ needs.lint.outputs.is_release }}
type=semver,pattern={{major}},value=${{ needs.lint.outputs.version }},enabled=${{ needs.lint.outputs.is_release }}
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
id: docker_build
uses: docker/build-push-action@v3
with:
context: .
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.slug.outputs.sha }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.get_version.outputs.version }}
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max


release:
runs-on: ubuntu-latest
if: ${{ needs.lint.outputs.is_release }}
needs:
- build
steps:
- name: Create Tag
id: create_tag
uses: actions/github-script@v7
if: ${{ needs.lint.outputs.is_pr }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
# language=JavaScript
script: |
const version = "${{ needs.lint.outputs.version }}"
const tagMessage = `Release version ${version}`
github.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `refs/tags/v${version}`,
sha: context.sha
})
github.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: `v${version}`,
name: `v${version}`,
body: tagMessage
})
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')

with:
body: |
Docker image: `${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.get_version.outputs.version }}`
Docker image: [`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.get_version.outputs.version }}`](https://github.com/jag-k/owntinfoil/pkgs/container/owntinfoil/${{ steps.docker_build.outputs }}?tag=${{ steps.get_version.outputs.version }})
tag_name: v${{ steps.get_version.outputs.version }}
generate_release_notes: true
append_body: true
token: ${{ secrets.RELEASE_TOKEN }}
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
111 changes: 111 additions & 0 deletions .github/workflows/pr_lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: PR Validation

on:
pull_request:

jobs:
validate-pr:
runs-on: ubuntu-latest
steps:
- name: Check labels
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
# language=JavaScript
script: |
const { data: pullRequest } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
const labels = pullRequest.labels.map(label => label.name);
const invalidLabels = ['feature request', 'invalid', 'question'];
const hasInvalidLabel = labels.some(label => invalidLabels.includes(label));
if (labels.length === 0) {
core.setFailed('Pull request must have at least one label!');
}
if (hasInvalidLabel) {
core.setFailed('Pull request must have an invalid label: ' + invalidLabels.join(', '));
}
- name: Check assignees
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
# language=JavaScript
script: |
const { data: pullRequest } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
if (pullRequest.assignees.length === 0) {
core.setFailed('Pull request must have an assignee');
}
- name: Check draft status
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
# language=JavaScript
script: |
const { data: pullRequest } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
if (pullRequest.draft) {
core.setFailed('Pull request must not be a draft');
}
validate-code:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get_version.outputs.version }}
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install poetry
run: pipx install poetry
- uses: actions/setup-python@v4
with:
python-version: '3.12'
cache: 'poetry'

- name: Install dependencies
run: poetry install

- name: Run Ruff
run: poetry run ruff check --output-format=github .

- name: Run pre-commit hooks
run: poetry run pre-commit run --all-files --show-diff-on-failure

- name: Get version from pyproject.toml
id: get_version
run: |
echo "version=$(poetry version -s)" >> $GITHUB_OUTPUT
validate-branch:
runs-on: ubuntu-latest
needs:
- validate-code

if: startsWith(github.head_ref, 'release/')
steps:
- name: Check branch name with version
run: |
# Extract the branch name from the GitHub context
branch_name=${{ github.head_ref }}
# Check if the branch name starts with "release/" and does not match the version
if [[ $branch_name == release/* && $branch_name != "release/${{ needs.validate-code.outputs.version }}" ]]; then
echo "Branch name does not match the version in pyproject.toml"
exit 1
fi
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ repos:
- id: ruff-format

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand Down
42 changes: 32 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,19 +1,41 @@
FROM python:3.11-slim
FROM python:3.12-slim as base

LABEL org.opencontainers.image.source = "https://github.com/jag-k/owntinfoil"
LABEL org.opencontainers.image.source="https://github.com/jag-k/owntinfoil"
LABEL org.opencontainers.image.description="OwnTinfoil Image"
LABEL org.opencontainers.image.licenses="MIT"

WORKDIR /app

ENV NPS_DIR=/nps
ENV TORRENT_DIR=/torrents
ENV PIP_DEFAULT_TIMEOUT=100 \
# Allow statements and log messages to immediately appear
PYTHONUNBUFFERED=1 \
# disable a pip version check to reduce run-time & log-spam
PIP_DISABLE_PIP_VERSION_CHECK=1 \
# cache is useless in docker image, so disable to reduce image size
PIP_NO_CACHE_DIR=1
ENV PYTHONPATH=/app
ENV POETRY_VERSION=1.7.1
WORKDIR $PYTHONPATH

FROM base as builder

ARG POETRY_VERSION=1.7.1
RUN pip install "poetry==$POETRY_VERSION"

COPY pyproject.toml poetry.lock ./
RUN poetry config virtualenvs.create false && \
poetry install --without dev

COPY . /app
# Set poetry config to install packages in /venv/project/lib/python3.12/site-packages
RUN poetry config virtualenvs.path "/venv" && \
poetry config virtualenvs.prompt "project" && \
poetry install --no-root --only main


FROM base as final

ENV NPS_DIR=/nps
ENV TORRENT_DIR=/torrents

# Copy python side-packages from builder
COPY --from=builder "/venv/project/lib/python3.12/site-packages" "/usr/local/lib/python3.11/site-packages"

COPY . $PYTHONPATH

#ENTRYPOINT ["/bin/bash"]
CMD ["python", "app/main.py"]
Empty file added app/__init__.py
Empty file.
Loading

0 comments on commit b08d46a

Please sign in to comment.