Fix black lint, fix /processing-runs 404s, add semantic release and GitOps deploy
Agent-Logs-Url: https://github.com/christianlouis/InboxConverge/sessions/3fdf6219-3e1f-4867-b74d-efb6e4fe7e72 Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
@@ -224,3 +224,59 @@ jobs:
|
|||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
|
|
||||||
|
# ── Phase 5: GitOps – update preprod k8s manifest ─────────────────────────
|
||||||
|
update-k8s-manifest:
|
||||||
|
name: Update Preprod K8s Manifest
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [build]
|
||||||
|
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Compute image tags
|
||||||
|
id: tag
|
||||||
|
run: |
|
||||||
|
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
|
||||||
|
echo "backend_image=ghcr.io/${{ github.repository_owner }}/inboxconverge/backend:main-${SHORT_SHA}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "frontend_image=ghcr.io/${{ github.repository_owner }}/inboxconverge/frontend:main-${SHORT_SHA}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Checkout k8s-cluster-state
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: christianlouis/k8s-cluster-state
|
||||||
|
token: ${{ secrets.GH_PAT }}
|
||||||
|
path: k8s-cluster-state
|
||||||
|
|
||||||
|
- name: Update backend image tag in preprod manifest
|
||||||
|
uses: mikefarah/yq@v4.44.6
|
||||||
|
env:
|
||||||
|
IMAGE: ${{ steps.tag.outputs.backend_image }}
|
||||||
|
with:
|
||||||
|
cmd: |
|
||||||
|
yq -i '(.. | select(tag == "!!str") | select(test("^ghcr\\.io/christianlouis/inboxconverge/backend:"))) = strenv(IMAGE)' \
|
||||||
|
k8s-cluster-state/apps/gmail-puller/preprod/gmail-puller-stack.yaml
|
||||||
|
|
||||||
|
- name: Update frontend image tag in preprod manifest
|
||||||
|
uses: mikefarah/yq@v4.44.6
|
||||||
|
env:
|
||||||
|
IMAGE: ${{ steps.tag.outputs.frontend_image }}
|
||||||
|
with:
|
||||||
|
cmd: |
|
||||||
|
yq -i '(.. | select(tag == "!!str") | select(test("^ghcr\\.io/christianlouis/inboxconverge/frontend:"))) = strenv(IMAGE)' \
|
||||||
|
k8s-cluster-state/apps/gmail-puller/preprod/gmail-puller-stack.yaml
|
||||||
|
|
||||||
|
- name: Commit and push manifest update
|
||||||
|
run: |
|
||||||
|
cd k8s-cluster-state
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add apps/gmail-puller/preprod/gmail-puller-stack.yaml
|
||||||
|
if git diff --staged --quiet; then
|
||||||
|
echo "No changes to commit"
|
||||||
|
else
|
||||||
|
git commit -m "chore(preprod): update inboxconverge images to ${{ steps.tag.outputs.short_sha }}"
|
||||||
|
git push
|
||||||
|
fi
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
name: Semantic Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Semantic Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository == 'christianlouis/InboxConverge'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
python-version: '3.12'
|
||||||
|
cache: 'pip'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install python-semantic-release
|
||||||
|
|
||||||
|
- name: Configure Git
|
||||||
|
run: |
|
||||||
|
git config --global user.name "github-actions[bot]"
|
||||||
|
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
- name: Run Semantic Release
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
semantic-release version --print
|
||||||
|
semantic-release version
|
||||||
|
semantic-release publish
|
||||||
|
|
||||||
|
- name: Update changelog if no new version was released
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
if git diff --name-only HEAD~1 2>/dev/null | grep -q CHANGELOG.md; then
|
||||||
|
echo "CHANGELOG.md was already updated by semantic-release version"
|
||||||
|
else
|
||||||
|
semantic-release changelog
|
||||||
|
if ! git diff --quiet CHANGELOG.md; then
|
||||||
|
git add CHANGELOG.md
|
||||||
|
git commit -m "docs(changelog): update changelog [skip ci]"
|
||||||
|
git push
|
||||||
|
fi
|
||||||
|
fi
|
||||||
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **Black formatting**: `backend/app/api/v1/endpoints/admin.py` was not formatted correctly; reformatted to pass `black --check`.
|
||||||
|
- **`/processing-runs` endpoint 404s**: Routes in `logs.py` had a redundant `/processing-runs` path segment (the router was already mounted at `/processing-runs` in `api.py`). All three user-facing log endpoints now return correct results:
|
||||||
|
- `GET /processing-runs` (was: `GET /processing-runs/processing-runs`)
|
||||||
|
- `GET /processing-runs/{id}` (was: `GET /processing-runs/processing-runs/{id}`)
|
||||||
|
- `GET /processing-runs/{id}/logs` (was: `GET /processing-runs/processing-runs/{id}/logs`)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- **Semantic Release** (`release.yml`): Automated versioning and GitHub Release creation on every push to `main` using `python-semantic-release`. Reads conventional-commit prefixes (`feat:`, `fix:`, etc.) to determine the next version and updates `CHANGELOG.md`.
|
||||||
|
- **`pyproject.toml`**: Project metadata and `[tool.semantic_release]` configuration for `python-semantic-release`.
|
||||||
|
- **GitOps auto-deployment** (step in `ci.yml`): After a successful Docker build on `main`, a new `update-k8s-manifest` job checks out `christianlouis/k8s-cluster-state` (using the `GH_PAT` secret) and updates the backend and frontend image tags in `apps/gmail-puller/preprod/gmail-puller-stack.yaml` to the new `main-<sha>` image, then commits and pushes.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- **Project renamed to InboxConverge**: All user-visible strings, Docker container names, database defaults, Docker image paths, monitoring job names, Grafana dashboard titles, and documentation updated from the legacy names (`POP3 to Gmail Forwarder`, `InboxRescue`, `gmail-puller`, `pop3_forwarder`, etc.) to **InboxConverge** / `inboxconverge`.
|
- **Project renamed to InboxConverge**: All user-visible strings, Docker container names, database defaults, Docker image paths, monitoring job names, Grafana dashboard titles, and documentation updated from the legacy names (`POP3 to Gmail Forwarder`, `InboxRescue`, `gmail-puller`, `pop3_forwarder`, etc.) to **InboxConverge** / `inboxconverge`.
|
||||||
- **Domain updated to `inboxconverge.com`**: All contact and administrative email addresses now default to `@inboxconverge.com` (e.g. `christian@inboxconverge.com`).
|
- **Domain updated to `inboxconverge.com`**: All contact and administrative email addresses now default to `@inboxconverge.com` (e.g. `christian@inboxconverge.com`).
|
||||||
|
|||||||
@@ -407,6 +407,8 @@ async def test_admin_notification_config(
|
|||||||
"""Test an admin notification channel by sending a test message (admin only)"""
|
"""Test an admin notification channel by sending a test message (admin only)"""
|
||||||
success, message = await test_notification(request.apprise_url)
|
success, message = await test_notification(request.apprise_url)
|
||||||
return NotificationTestResponse(success=success, message=message)
|
return NotificationTestResponse(success=success, message=message)
|
||||||
|
|
||||||
|
|
||||||
# ── Admin Logs ─────────────────────────────────────────────────────────────────
|
# ── Admin Logs ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ def _paginate(total: int, page: int, page_size: int) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/processing-runs",
|
"",
|
||||||
response_model=PaginatedProcessingRunsResponse,
|
response_model=PaginatedProcessingRunsResponse,
|
||||||
summary="List processing runs for the current user",
|
summary="List processing runs for the current user",
|
||||||
)
|
)
|
||||||
@@ -117,7 +117,7 @@ async def list_processing_runs(
|
|||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/processing-runs/{run_id}",
|
"/{run_id}",
|
||||||
response_model=ProcessingRunDetailResponse,
|
response_model=ProcessingRunDetailResponse,
|
||||||
summary="Get a single processing run",
|
summary="Get a single processing run",
|
||||||
)
|
)
|
||||||
@@ -160,7 +160,7 @@ async def get_processing_run(
|
|||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/processing-runs/{run_id}/logs",
|
"/{run_id}/logs",
|
||||||
response_model=PaginatedProcessingLogsResponse,
|
response_model=PaginatedProcessingLogsResponse,
|
||||||
summary="Get per-email logs for a processing run",
|
summary="Get per-email logs for a processing run",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ Comprehensive task breakdown for repository improvements and production readines
|
|||||||
- [x] Rename entire project to **InboxConverge**: all user-visible strings, Docker container/image names, DB defaults, monitoring, and docs updated.
|
- [x] Rename entire project to **InboxConverge**: all user-visible strings, Docker container/image names, DB defaults, monitoring, and docs updated.
|
||||||
- [x] Domain updated to `inboxconverge.com`; contact email defaults to `christian@inboxconverge.com`.
|
- [x] Domain updated to `inboxconverge.com`; contact email defaults to `christian@inboxconverge.com`.
|
||||||
- [x] New configurable env vars: `CONTACT_EMAIL`, `APP_URL`, `NEXT_PUBLIC_APP_NAME`.
|
- [x] New configurable env vars: `CONTACT_EMAIL`, `APP_URL`, `NEXT_PUBLIC_APP_NAME`.
|
||||||
|
- [x] Fixed Black formatting failure in CI (`admin.py` reformatted).
|
||||||
|
- [x] Fixed `/processing-runs` endpoint 404s caused by duplicate path prefix in `logs.py`.
|
||||||
|
- [x] Added Semantic Release workflow (`release.yml`) for automatic versioning and GitHub Releases.
|
||||||
|
- [x] Added `pyproject.toml` with `[tool.semantic_release]` configuration.
|
||||||
|
- [x] Added GitOps auto-deployment step in `ci.yml` to update preprod k8s manifest in `k8s-cluster-state` repo.
|
||||||
|
|
||||||
## 🔴 Critical - Security (In Progress)
|
## 🔴 Critical - Security (In Progress)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=45", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "inboxconverge"
|
||||||
|
dynamic = ["version"]
|
||||||
|
description = "Multi-account email forwarding and processing service"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
license = {text = "MIT"}
|
||||||
|
authors = [
|
||||||
|
{name = "Christian Louis", email = "christianlouis@users.noreply.github.com"}
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://github.com/christianlouis/InboxConverge"
|
||||||
|
Repository = "https://github.com/christianlouis/InboxConverge"
|
||||||
|
Issues = "https://github.com/christianlouis/InboxConverge/issues"
|
||||||
|
Changelog = "https://github.com/christianlouis/InboxConverge/blob/main/CHANGELOG.md"
|
||||||
|
|
||||||
|
[tool.semantic_release]
|
||||||
|
version_source = "tag"
|
||||||
|
commit_version_number = true
|
||||||
|
tag_format = "v{version}"
|
||||||
|
major_on_zero = false
|
||||||
|
allow_zero_version = true
|
||||||
|
|
||||||
|
[tool.semantic_release.branches.main]
|
||||||
|
match = "main"
|
||||||
|
prerelease = false
|
||||||
|
|
||||||
|
[tool.semantic_release.changelog]
|
||||||
|
mode = "update"
|
||||||
|
exclude_commit_patterns = [
|
||||||
|
"^chore\\(release\\):",
|
||||||
|
"^Merge",
|
||||||
|
"^Bump version",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.semantic_release.changelog.default_templates]
|
||||||
|
changelog_file = "CHANGELOG.md"
|
||||||
|
output_format = "md"
|
||||||
|
|
||||||
|
[tool.semantic_release.commit_parser_options]
|
||||||
|
allowed_tags = [
|
||||||
|
"feat",
|
||||||
|
"fix",
|
||||||
|
"docs",
|
||||||
|
"style",
|
||||||
|
"refactor",
|
||||||
|
"perf",
|
||||||
|
"test",
|
||||||
|
"build",
|
||||||
|
"ci",
|
||||||
|
"chore",
|
||||||
|
]
|
||||||
|
minor_tags = ["feat"]
|
||||||
|
patch_tags = ["fix", "perf"]
|
||||||
|
default_bump_level = 0
|
||||||
|
|
||||||
|
[tool.semantic_release.remote]
|
||||||
|
name = "origin"
|
||||||
|
type = "github"
|
||||||
|
ignore_token_for_push = false
|
||||||
|
|
||||||
|
[tool.semantic_release.remote.token]
|
||||||
|
env = "GH_TOKEN"
|
||||||
|
|
||||||
|
[tool.semantic_release.publish]
|
||||||
|
dist_glob_patterns = []
|
||||||
|
upload_to_vcs_release = true
|
||||||
|
upload_to_pypi = false
|
||||||
|
upload_to_repository = false
|
||||||
Reference in New Issue
Block a user