Compare commits
	
		
			No commits in common. 'master' and 'drew/add-ci-setup' have entirely different histories. 
		
	
	
		
			master
			...
			drew/add-c
		
	
		
	| @ -1,30 +1,3 @@ | ||||
| # cookiecutter-basic | ||||
| 
 | ||||
| A basic [Cookiecutter](https://cookiecutter.readthedocs.io/en/stable) template for most Androiddrew style repos. | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| With [Cookiecutter installed](https://cookiecutter.readthedocs.io/en/stable/installation.html), execute the following command and provide your template parameters.  | ||||
| 
 | ||||
| ``` | ||||
| cookiecutter https://git.runcible.io/androiddrew/cookiecutter-basic | ||||
| ``` | ||||
| 
 | ||||
| Once templated, you can change into the new project directory and execute the `scripts/bootstrap.sh` script.  | ||||
| 
 | ||||
| ``` | ||||
| cd <cookiecutter.project_slug> | ||||
| ./scripts/bootstrap.sh | ||||
| ``` | ||||
| 
 | ||||
| This will create a Python virtual environment if one is not already enabled, install [pip-tools](https://github.com/jazzband/pip-tools/), compile the requirements.in and dev-requirements.in files, install the initial dependencies, initialize the project as a git repository, and install the [pre-commit hooks](https://pre-commit.com/).  | ||||
| 
 | ||||
| ## Licenses | ||||
| 
 | ||||
| Within a `pyproject.toml` file the license section expects the string identifier as determined by https://spdx.org/licenses/. This project supports a small subset of these licenses.  | ||||
| 
 | ||||
| Example: | ||||
| ``` | ||||
| [project] | ||||
| license = {text = "MIT"} | ||||
| ``` | ||||
| A basic cookiecutter template for most Androiddrew style repos. | ||||
| @ -1,18 +1,17 @@ | ||||
| { | ||||
|   "full_name": "Drew Bednar", | ||||
|   "email": "drew@runcible.io", | ||||
|   "email": "drew@androiddrew.com", | ||||
|   "github_username": "androiddrew", | ||||
|   "project_name": "python_app", | ||||
|   "project_slug": "{{ cookiecutter.project_name.lower().strip().replace(' ', '_').replace('-','_')}}", | ||||
|   "initial_dependencies": "", | ||||
|   "description": "A templated Python project", | ||||
|   "image_registry": "registry.runcible.io", | ||||
|   "description": "An templated Python project", | ||||
|   "open_source_license": [ | ||||
|     "MIT", | ||||
|     "BSD-3-Clause", | ||||
|     "ISC", | ||||
|     "Apache-2.0", | ||||
|     "GPL-3.0-or-later", | ||||
|     "MIT license", | ||||
|     "BSD license", | ||||
|     "ISC license", | ||||
|     "Apache Software License 2.0", | ||||
|     "GNU General Public License v3", | ||||
|     "Not open source" | ||||
|   ] | ||||
| } | ||||
| @ -1,14 +0,0 @@ | ||||
| ./tests | ||||
| ./scripts | ||||
| .ruff_cache | ||||
| .coveragerc | ||||
| .dockerignore | ||||
| .git | ||||
| .gitignore | ||||
| .pre-commit-config.yaml | ||||
| dev-requirements.in | ||||
| dev-requirements.txt | ||||
| .profile | ||||
| Dockerfile | ||||
| requirements.in | ||||
| tasks.py | ||||
| @ -0,0 +1,23 @@ | ||||
| kind: pipeline | ||||
| type: docker | ||||
| name: CI Test Pipeline | ||||
| 
 | ||||
| steps: | ||||
| - name: greeting | ||||
|   image: alpine | ||||
|   commands: | ||||
|   - echo "Welcome to drone\n" | ||||
| 
 | ||||
| - name: Unit Tests | ||||
|   image: python:3.11-bullseye | ||||
|   commands: | ||||
|     - bash -c './ci_scripts/run_unit_tests.sh' | ||||
| 
 | ||||
| trigger: | ||||
|   event: | ||||
|     - pull_request | ||||
|     - push | ||||
| 
 | ||||
| # Secrets used to pull private images | ||||
| image_pull_secrets: | ||||
|   - dockerconfigjson | ||||
| @ -1,44 +0,0 @@ | ||||
| kind: pipeline | ||||
| type: docker | ||||
| name: CI Test/Lint Pipeline | ||||
| 
 | ||||
| steps: | ||||
| - name: Unit Tests and Linters | ||||
|   # Bullseye because drone runner host OS is using older libseccomp2 causing issues | ||||
|   # with thread allocation. See: https://github.com/docker-library/python/issues/835 | ||||
|   image: python:3.11-bullseye | ||||
|   commands: | ||||
|    - bash -xc './scripts/run_linters.sh' | ||||
|    - bash -xc './scripts/run_unit_tests.sh' | ||||
|   group: test-lint | ||||
| 
 | ||||
| trigger: | ||||
|   event: | ||||
|     - pull_request | ||||
|     - push | ||||
| 
 | ||||
| # Secrets used to pull private images | ||||
| image_pull_secrets: | ||||
|   - dockerconfigjson | ||||
| 
 | ||||
| --- | ||||
| kind: pipeline | ||||
| type: docker | ||||
| name: Build Production Image | ||||
| steps: | ||||
| - name: Build {{ cookiecutter.project_slug }} Container Image | ||||
|   image: plugins/docker | ||||
|   settings: | ||||
|     username: automate | ||||
|     password: | ||||
|       from_secret: automate_password | ||||
|     dockerfile: Dockerfile | ||||
|     registry: {{ cookiecutter.image_registry }} | ||||
|     repo: {{ cookiecutter.image_registry }}/{{ cookiecutter.project_slug }} | ||||
|     tags: | ||||
|       - ${DRONE_COMMIT_SHA} | ||||
|   when: | ||||
|     branch: | ||||
|       - master | ||||
|     event: | ||||
|       - push | ||||
| @ -1,55 +0,0 @@ | ||||
| # syntax = docker/dockerfile:1.4 | ||||
| 
 | ||||
| # Best practice: Choose a stable base image and tag. | ||||
| FROM python:3.11-slim-bookworm | ||||
| 
 | ||||
| # Install security updates, and some useful packages. | ||||
| # | ||||
| # Best practices: | ||||
| # * Make sure apt-get doesn't run in interactive mode. | ||||
| # * Update system packages. | ||||
| # * Pre-install some useful tools. | ||||
| # * Minimize system package installation. | ||||
| RUN export DEBIAN_FRONTEND=noninteractive && \ | ||||
|     apt-get update && \ | ||||
|     apt-get -y upgrade && \ | ||||
|     apt-get install -y --no-install-recommends tini procps net-tools && \ | ||||
|     apt-get -y clean && \ | ||||
|     rm -rf /var/lib/apt/lists/* | ||||
| 
 | ||||
| # Install dependencies. | ||||
| # | ||||
| # Best practices: | ||||
| # * `COPY` in files only when needed. | ||||
| # * Reduce disk usage from `pip` installs. | ||||
| COPY requirements.txt . | ||||
| RUN pip install --no-cache-dir -r requirements.txt | ||||
| 
 | ||||
| # Create a new user to run as. | ||||
| # | ||||
| # Best practices: Don't run as root. | ||||
| RUN useradd --create-home appuser | ||||
| USER appuser | ||||
| WORKDIR /home/appuser | ||||
| 
 | ||||
| # Copy in the code. | ||||
| # | ||||
| # Best practices: Avoid extra chowns. | ||||
| COPY --chown=appuser . . | ||||
| 
 | ||||
| # Best practices: Prepare for C crashes. | ||||
| ENV PYTHONFAULTHANDLER=1 | ||||
| ENV PYTHONUNBUFFERED=0 | ||||
| 
 | ||||
| ARG COMMIT_SHA | ||||
| 
 | ||||
| LABEL io.runcible.repo-sha="${COMMIT_SHA}" | ||||
| 
 | ||||
| # Run the code when the image is run: | ||||
| # | ||||
| # Best practices: | ||||
| # * Add an `init` process. | ||||
| # * Make sure images shut down correctly (via ENTRYPOINT [] syntax). | ||||
| # * '-g' option means killing the container kills all processes, not just the | ||||
| #   entrypoint shell. | ||||
| ENTRYPOINT ["tini", "-g", "--", "./entrypoint.sh"] | ||||
| @ -1,8 +0,0 @@ | ||||
| #!/bin/bash | ||||
| 
 | ||||
| # Best practice: Bash strict mode. | ||||
| set -euo pipefail | ||||
| 
 | ||||
| # Best practice: Make sure the image shuts down correctly by using `exec` in | ||||
| # entry point shell scripts. | ||||
| exec "$@" | ||||
| @ -1,28 +0,0 @@ | ||||
| #! /usr/bin/env bash | ||||
| 
 | ||||
| # shellcheck source=/dev/null | ||||
| source "$(dirname "$0")/_common.sh" | ||||
| 
 | ||||
| if [ "${DRONE}" == "true" ]; then | ||||
|     _setup_env | ||||
|     pip install -r requirements.txt -r dev-requirements.txt | ||||
| fi | ||||
| 
 | ||||
| # Run linting commands and capture their return codes | ||||
| "${VIRTUAL_ENV}/bin/python3" -m isort --check ./speech_collect ./tests ./tasks.py | ||||
| ISORT_EXIT_CODE=$? | ||||
| 
 | ||||
| "${VIRTUAL_ENV}/bin/python3" -m black --check ./speech_collect ./tests ./tasks.py | ||||
| BLACK_EXIT_CODE=$? | ||||
| 
 | ||||
| "${VIRTUAL_ENV}/bin/python3" -m ruff ./speech_collect ./tests ./tasks.py | ||||
| RUFF_EXIT_CODE=$? | ||||
| 
 | ||||
| # Check if any linting command failed | ||||
| if [ $ISORT_EXIT_CODE -ne 0 ] || [ $BLACK_EXIT_CODE -ne 0 ] || [ $RUFF_EXIT_CODE -ne 0 ]; then | ||||
|     echo "Some linting checks failed" | ||||
|     # Exit with a non-zero status, you can choose which error code to return | ||||
|     exit 1 | ||||
| fi | ||||
| 
 | ||||
| echo "All linting checks passed" | ||||
| @ -1,52 +0,0 @@ | ||||
| import os | ||||
| 
 | ||||
| from invoke import task | ||||
| 
 | ||||
| IMAGE_RESPOSITORY = os.environ.get("IMAGE_RESPOSITORY", "{{ cookiecutter.image_registry }}/{{ cookiecutter.project_slug }}") | ||||
| 
 | ||||
| 
 | ||||
| @task | ||||
| def update_deps(c): | ||||
|     """Updates depenencies""" | ||||
|     c.run("pip-compile requirements.in", pty=True) | ||||
|     c.run("pip-compile dev-requirements.in", pty=True) | ||||
| 
 | ||||
| 
 | ||||
| @task | ||||
| def sync_deps(c): | ||||
|     """Syncs local dependencies""" | ||||
|     c.run("pip-sync requirements.txt dev-requirements.txt") | ||||
| 
 | ||||
| 
 | ||||
| @task | ||||
| def lint(c): | ||||
|     """Runs all linters against the project.""" | ||||
|     c.run("./scripts/run_linters.sh", pty=True) | ||||
| 
 | ||||
| 
 | ||||
| @task | ||||
| def delint(c): | ||||
|     """Applies automated linters to project""" | ||||
|     c.run("isort ./{{ cookiecutter.project_slug }} ./tests ./tasks.py", pty=True) | ||||
|     c.run("black ./{{ cookiecutter.project_slug }} ./tests ./tasks.py", pty=True) | ||||
| 
 | ||||
| 
 | ||||
| @task | ||||
| def build(c): | ||||
|     """Builds the project as a Python package.""" | ||||
|     c.run("python3 -m build") | ||||
| 
 | ||||
| 
 | ||||
| @task | ||||
| def build_image(c, dev=True, registry_user=None, registry_token=None, push=False, login=False): | ||||
|     """Builds the {{ cookiecutter.project_slug }} container image.""" | ||||
|     context_dir = c.run("pwd", hide=True).stdout.strip() | ||||
|     commit_sha = c.run("git rev-parse --short HEAD", hide=True).stdout.strip() | ||||
|     image_name = f"{IMAGE_RESPOSITORY}:{commit_sha}{'-dev' if dev else ''}" | ||||
|     c.run(f"docker build --build-arg='COMMIT_SHA={commit_sha}' -t {image_name} {context_dir}") | ||||
|     if login: | ||||
|         if registry_user is None or registry_token is None: | ||||
|             raise ValueError("--registry_user and --registry_token must be provided if using --login parameter") | ||||
|         c.run(f"docker login -u {registry_user} -p {registry_token}") | ||||
|     if push: | ||||
|         c.run(f"docker push {image_name}") | ||||
					Loading…
					
					
				
		Reference in New Issue