diff --git a/.env.example b/.env.example index 568a4d2..2f2c0b4 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,9 @@ OPENAI_API_KEY=ADD-YOUR-OPENAI_API_KEY-HERE +REPO_NAME=agentic-ai-workflow +DOCKERHUB_USERNAME=lpm0073 + +# These settings are probably fine to leave as-is. ENVIRONMENT=local -DOCKERHUB_USERNAME=ADD-YOUR-DOCKERHUB_USERNAME-HERE DOCKERHUB_ACCESS_TOKEN=ADD-YOUR-DOCKERHUB_ACCESS_TOKEN-HERE LLM_TOOL_CHOICE=required LOGGING_LEVEL=20 diff --git a/.gitignore b/.gitignore index c7d04ba..1434880 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ + +.mypy_cache/ + # my own homegrown file to store coverage report output from Docker. coverage.out diff --git a/CHANGELOG.md b/CHANGELOG.md index 391fa33..78f6262 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,28 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). + + +## [0.1.7](https://github.com/FullStackWithLawrence/agentic-ai-workflow/compare/v0.1.6...v0.1.7) (2026-05-21) + + +### Bug Fixes + +* automated build and tear down ([fa572e2](https://github.com/FullStackWithLawrence/agentic-ai-workflow/commit/fa572e289f2fa737f9c30659e8f62303971aef50)) + +## [0.1.7](https://github.com/FullStackWithLawrence/agentic-ai-workflow/compare/v0.1.6...v0.1.7) (2026-05-21) + + +### Bug Fixes + +* automated build and tear down ([fa572e2](https://github.com/FullStackWithLawrence/agentic-ai-workflow/commit/fa572e289f2fa737f9c30659e8f62303971aef50)) + +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). + ## [0.1.6](https://github.com/FullStackWithLawrence/agentic-ai-workflow/compare/v0.1.5...v0.1.6) (2026-04-02) ### Bug Fixes diff --git a/Dockerfile b/Dockerfile index cfbbad0..d065dac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ LABEL maintainer="Lawrence McDaniel " \ license="GNU AGPL v3" \ vcs-url="https://github.com/FullStackWithLawrence/agentic-ai-workflow" \ org.opencontainers.image.title="StackademyAssistent" \ - org.opencontainers.image.version="0.1.6" \ + org.opencontainers.image.version="0.1.7" \ org.opencontainers.image.authors="Lawrence McDaniel " \ org.opencontainers.image.url="https://FullStackWithLawrence.github.io/agentic-ai-workflow/" \ org.opencontainers.image.source="https://github.com/FullStackWithLawrence/agentic-ai-workflow" \ diff --git a/Makefile b/Makefile index 7bebd1b..9662784 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,26 @@ -SHELL := /bin/bash -export PATH := /usr/local/bin:$(PATH) -export +# Windows‑optimized Makefile (cmd.exe as shell) +# Detect OS and set Python / venv activation / .env loading ifeq ($(OS),Windows_NT) - PYTHON := python.exe - ACTIVATE_VENV := venv\Scripts\activate + PYTHON := python.exe + ACTIVATE_VENV := call venv\Scripts\activate + LOAD_ENV := for /f "usebackq tokens=1,2 delims==" %%a in (".env") do set %%a=%%b else - PYTHON := python3.13 - ACTIVATE_VENV := source venv/bin/activate + PYTHON := python3.13 + ACTIVATE_VENV := . venv/bin/activate + LOAD_ENV := set -a && . .env && set +a endif + PIP := $(PYTHON) -m pip ifneq ("$(wildcard .env)","") - include .env + include .env else - $(shell cp .env.example .env) + $(shell cp .env.example .env) endif -.PHONY: analyze pre-commit init lint tear-down test build release +.PHONY: analyze pre-commit init init-dev lint tear-down test build release \ + docker-build docker-run docker-test docker-coverage docker-push docker-prune # Default target executed when no arguments are given to make. all: help @@ -71,21 +74,43 @@ lint: flake8 ./app/ pylint ./app/**/*.py +# --------------------------------------------------------- +# tear down venv / node_modules (Windows + *nix) +# --------------------------------------------------------- +ifeq ($(OS),Windows_NT) + RM_VENV := if exist venv rmdir /S /Q venv + RM_NODE := if exist node_modules rmdir /S /Q node_modules + RM_PYCACHE := if exist app\__pycache__ rmdir /S /Q app\__pycache__ + RM_LOCK := if exist package-lock.json del /F /Q package-lock.json +else + RM_VENV := rm -rf venv + RM_NODE := rm -rf node_modules + RM_PYCACHE := rm -rf app/__pycache__ + RM_LOCK := rm -f package-lock.json +endif + tear-down: - rm -rf venv node_modules app/__pycache__ package-lock.json + $(RM_VENV) + $(RM_NODE) + $(RM_PYCACHE) + $(RM_LOCK) docker-build: docker build -t ${DOCKERHUB_USERNAME}/${REPO_NAME} . --build-arg ENVIRONMENT=${ENVIRONMENT} +# --------------------------------------------------------- +# Docker commands using .env (Windows: LOAD_ENV) +# --------------------------------------------------------- docker-push: - source .env && \ + $(LOAD_ENV) && \ docker tag ${DOCKERHUB_USERNAME}/${REPO_NAME} ${DOCKERHUB_USERNAME}/${REPO_NAME}:latest && \ echo "${DOCKERHUB_ACCESS_TOKEN}" | docker login --username=${DOCKERHUB_USERNAME} --password-stdin && \ docker push ${DOCKERHUB_USERNAME}/${REPO_NAME}:latest docker-run: - source .env && \ - docker run -it -e OPENAI_API_KEY=${OPENAI_API_KEY} \ + $(LOAD_ENV) && \ + docker run -it \ + -e OPENAI_API_KEY=${OPENAI_API_KEY} \ -e ENVIRONMENT=prod \ -e MYSQL_HOST=${MYSQL_HOST} \ -e MYSQL_PORT=${MYSQL_PORT} \ @@ -97,7 +122,7 @@ docker-run: -e LLM_TOOL_CHOICE=${LLM_TOOL_CHOICE} ${DOCKERHUB_USERNAME}/${REPO_NAME}:latest docker-test: - source .env && \ + $(LOAD_ENV) && \ docker run --rm \ -e OPENAI_API_KEY=${OPENAI_API_KEY} \ -e ENVIRONMENT=local \ @@ -113,7 +138,7 @@ docker-test: python -m unittest discover -s app/ docker-coverage: - source .env && \ + $(LOAD_ENV) && \ docker run --rm \ -e OPENAI_API_KEY=${OPENAI_API_KEY} \ -e ENVIRONMENT=local \ @@ -129,29 +154,26 @@ docker-coverage: /bin/bash -c "python -m coverage run --source=app --omit='app/tests/*' -m unittest discover -s app/tests && python -m coverage report -m --omit='app/tests/*' && python -m coverage xml --omit='app/tests/*'" docker-prune: - @if [ "`docker ps -aq`" ]; then \ - docker stop $(docker ps -aq); \ - fi - @docker container prune -f - @docker image prune -af - @docker builder prune -af + docker container prune -f + docker image prune -af + docker builder prune -af ###################### # HELP ###################### help: @echo '====================================================================' - @echo 'analyze - generate code analysis report' - @echo 'release - force a new GitHub release' - @echo 'init - create a Python virtual environment and install prod dependencies' - @echo 'init-dev - install dev dependencies' - @echo 'test - run Python unit tests' - @echo 'lint - run Python linting' - @echo 'tear-down - destroy the Python virtual environment' - @echo 'pre-commit - install and run pre-commit hooks' - @echo 'docker-build - build the Docker image' - @echo 'docker-run - run the Docker image' - @echo 'docker-test - run the Docker image for testing' - @echo 'docker-coverage - run the Docker image for testing + coverage report' - @echo 'docker-push - push the Docker image to DockerHub' - @echo 'docker-prune - Docker tear-down containers/images/builders' + @echo 'analyze - generate code analysis report' + @echo 'release - force a new GitHub release' + @echo 'init - create a Python virtual environment and install prod dependencies' + @echo 'init-dev - install dev dependencies' + @echo 'test - run Python unit tests' + @echo 'lint - run Python linting' + @echo 'tear-down - destroy the Python virtual environment' + @echo 'pre-commit - install and run pre-commit hooks' + @echo 'docker-build - build the Docker image' + @echo 'docker-run - run the Docker image' + @echo 'docker-test - run the Docker image for testing' + @echo 'docker-coverage - run the Docker image for testing + coverage report' + @echo 'docker-push - push the Docker image to DockerHub' + @echo 'docker-prune - Docker tear-down containers/images/builders' diff --git a/Makefile_Original b/Makefile_Original new file mode 100644 index 0000000..570b1fc --- /dev/null +++ b/Makefile_Original @@ -0,0 +1,157 @@ +SHELL := /bin/bash +export PATH := /usr/local/bin:$(PATH) +export + +ifeq ($(OS),Windows_NT) + PYTHON := python.exe + ACTIVATE_VENV := venv\Scripts\activate +else + PYTHON := python3.13 + ACTIVATE_VENV := source venv/bin/activate +endif +PIP := $(PYTHON) -m pip + +ifneq ("$(wildcard .env)","") + include .env +else + $(shell cp .env.example .env) +endif + +.PHONY: analyze pre-commit init lint tear-down test build release + +# Default target executed when no arguments are given to make. +all: help + +analyze: + cloc . --exclude-ext=svg,json,zip --vcs=git + +release: + git commit -m "fix: force a new release" --allow-empty && git push + +# ------------------------------------------------------------------------- +# Install and run pre-commit hooks +# ------------------------------------------------------------------------- +pre-commit: + pre-commit install + pre-commit autoupdate + pre-commit run --all-files + +# --------------------------------------------------------- +# create python virtual environments for prod +# --------------------------------------------------------- +init: + make tear-down + $(PYTHON) -m venv venv && \ + $(ACTIVATE_VENV) && \ + $(PIP) install --upgrade pip && \ + $(PIP) install -r requirements/base.txt + +# --------------------------------------------------------- +# create python virtual environments for dev +# --------------------------------------------------------- +init-dev: + make init && \ + npm install && \ + $(ACTIVATE_VENV) && \ + $(PIP) install -r requirements/local.txt && \ + pre-commit install + +test: + python -m unittest discover -s app/ + +coverage: + python -m coverage run --source=app --omit='app/tests/*' -m unittest discover -s app/tests + python -m coverage report -m --omit='app/tests/*' + python -m coverage xml --omit='app/tests/*' + +lint: + isort . + pre-commit run --all-files + black . + flake8 ./app/ + pylint ./app/**/*.py + +tear-down: + rm -rf venv node_modules app/__pycache__ package-lock.json + +docker-build: + docker build -t ${DOCKERHUB_USERNAME}/${REPO_NAME} . --build-arg ENVIRONMENT=${ENVIRONMENT} + +docker-push: + source .env && \ + docker tag ${DOCKERHUB_USERNAME}/${REPO_NAME} ${DOCKERHUB_USERNAME}/${REPO_NAME}:latest && \ + echo "${DOCKERHUB_ACCESS_TOKEN}" | docker login --username=${DOCKERHUB_USERNAME} --password-stdin && \ + docker push ${DOCKERHUB_USERNAME}/${REPO_NAME}:latest + +docker-run: + source .env && \ + docker run -it -e OPENAI_API_KEY=${OPENAI_API_KEY} \ + -e ENVIRONMENT=prod \ + -e MYSQL_HOST=${MYSQL_HOST} \ + -e MYSQL_PORT=${MYSQL_PORT} \ + -e MYSQL_USER=${MYSQL_USER} \ + -e MYSQL_PASSWORD=${MYSQL_PASSWORD} \ + -e MYSQL_DATABASE=${MYSQL_DATABASE} \ + -e MYSQL_CHARSET=${MYSQL_CHARSET} \ + -e LOGGING_LEVEL=${LOGGING_LEVEL} \ + -e LLM_TOOL_CHOICE=${LLM_TOOL_CHOICE} ${DOCKERHUB_USERNAME}/${REPO_NAME}:latest + +docker-test: + source .env && \ + docker run --rm \ + -e OPENAI_API_KEY=${OPENAI_API_KEY} \ + -e ENVIRONMENT=local \ + -e MYSQL_HOST=${MYSQL_HOST} \ + -e MYSQL_PORT=${MYSQL_PORT} \ + -e MYSQL_USER=${MYSQL_USER} \ + -e MYSQL_PASSWORD=${MYSQL_PASSWORD} \ + -e MYSQL_DATABASE=${MYSQL_DATABASE} \ + -e MYSQL_CHARSET=${MYSQL_CHARSET} \ + -e LOGGING_LEVEL=${LOGGING_LEVEL} \ + -e LLM_TOOL_CHOICE=${LLM_TOOL_CHOICE} \ + ${DOCKERHUB_USERNAME}/${REPO_NAME}:latest \ + python -m unittest discover -s app/ + +docker-coverage: + source .env && \ + docker run --rm \ + -e OPENAI_API_KEY=${OPENAI_API_KEY} \ + -e ENVIRONMENT=local \ + -e MYSQL_HOST=${MYSQL_HOST} \ + -e MYSQL_PORT=${MYSQL_PORT} \ + -e MYSQL_USER=${MYSQL_USER} \ + -e MYSQL_PASSWORD=${MYSQL_PASSWORD} \ + -e MYSQL_DATABASE=${MYSQL_DATABASE} \ + -e MYSQL_CHARSET=${MYSQL_CHARSET} \ + -e LOGGING_LEVEL=${LOGGING_LEVEL} \ + -e LLM_TOOL_CHOICE=${LLM_TOOL_CHOICE} \ + ${DOCKERHUB_USERNAME}/${REPO_NAME}:latest \ + /bin/bash -c "python -m coverage run --source=app --omit='app/tests/*' -m unittest discover -s app/tests && python -m coverage report -m --omit='app/tests/*' && python -m coverage xml --omit='app/tests/*'" + +docker-prune: + @if [ -n "$$(docker ps -aq)" ]; then \ + docker stop $$(docker ps -aq); \ + fi + @docker container prune -f + @docker image prune -af + @docker builder prune -af + +###################### +# HELP +###################### +help: + @echo '====================================================================' + @echo 'analyze - generate code analysis report' + @echo 'release - force a new GitHub release' + @echo 'init - create a Python virtual environment and install prod dependencies' + @echo 'init-dev - install dev dependencies' + @echo 'test - run Python unit tests' + @echo 'lint - run Python linting' + @echo 'tear-down - destroy the Python virtual environment' + @echo 'pre-commit - install and run pre-commit hooks' + @echo 'docker-build - build the Docker image' + @echo 'docker-run - run the Docker image' + @echo 'docker-test - run the Docker image for testing' + @echo 'docker-coverage - run the Docker image for testing + coverage report' + @echo 'docker-push - push the Docker image to DockerHub' + @echo 'docker-prune - Docker tear-down containers/images/builders' diff --git a/app/__version__.py b/app/__version__.py index 5ecf4c7..a2d6471 100644 --- a/app/__version__.py +++ b/app/__version__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- # DO NOT EDIT. # Managed via automated CI/CD in .github/workflows/semanticVersionBump.yml. -__version__ = "0.1.6" +__version__ = "0.1.7" diff --git a/pyproject.toml b/pyproject.toml index c6fbb0a..dc72c64 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "StackademyAI" -version = "0.1.6" +version = "0.1.7" requires-python = ">=3.10" description = "StackademyAI: an AI-powered marketing agent" authors = [{ name = "Lawrence McDaniel", email = "lpm0073@gmail.com" }]