From 7a120bb0686887820f2b69773086995aff9e67ec Mon Sep 17 00:00:00 2001 From: Justin Ko Date: Wed, 30 Sep 2026 16:03:30 +0900 Subject: [PATCH] chore(release): prepare v0.1.1 --- .gitea/release.yaml | 103 +++++++++++++++++++++ .github/workflows/publish-image.yml | 134 ---------------------------- README.md | 4 +- jarca_ledger_mcp/__init__.py | 2 +- pyproject.toml | 2 +- uv.lock | 2 +- 6 files changed, 108 insertions(+), 139 deletions(-) create mode 100644 .gitea/release.yaml delete mode 100644 .github/workflows/publish-image.yml diff --git a/.gitea/release.yaml b/.gitea/release.yaml new file mode 100644 index 0000000..a280d73 --- /dev/null +++ b/.gitea/release.yaml @@ -0,0 +1,103 @@ +schema: gitea-agent/release/v1 + +version: + sources: + - path: pyproject.toml + format: toml + selector: project.version + - path: jarca_ledger_mcp/__init__.py + format: python-assignment + selector: __version__ + lockfiles: + - path: uv.lock + package: jarca-ledger-mcp + tag_template: "v{version}" + +prepare: + runtime: + python: "3.12" + commands: + - name: sync + argv: [uv, sync, --python, "3.12", --frozen, --extra, dev, --extra, dashboard] + - name: lint + argv: [uv, run, ruff, check, .] + - name: test + argv: [uv, run, pytest] + - name: dashboard-http-smoke + argv: [uv, run, python, scripts/ci_dashboard_http_smoke.py, --host, 127.0.0.1, --port, "18501", --timeout, "45"] + - name: db-safety-smoke + argv: [uv, run, python, scripts/ci_db_safety_smoke.py, --timeout, "45"] + +artifacts: + - type: container + name: jarca-ledger-mcp + platform: linux/arm64 + + build: + adapter: docker-buildx + context: . + dockerfile: Dockerfile + pull: true + local_tag_template: "jarca-ledger-mcp:release-{commit}" + labels: + org.opencontainers.image.source: "https://gitea.jsfamily.quest/jsfamily/jarca-ledger-mcp" + org.opencontainers.image.revision: "{commit}" + org.opencontainers.image.version: "{version}" + + smoke: + - type: image-platform + expected_os: linux + expected_architecture: arm64 + - type: container-command + environment: + JARCA_LEDGER_DB_PATH: /tmp/ledger.sqlite3 + argv: + - python + - -c + - >- + import platform; from jarca_ledger_mcp import service; + result = service.health_check(); + assert platform.machine() == "aarch64"; + assert result["success"], result + - type: container-health + name_template: "jarca-mcp-{run_id}" + command: default + expected: healthy + timeout_seconds: 90 + - type: container-http + name_template: "jarca-dashboard-{run_id}" + command: + - python + - -m + - streamlit + - run + - dashboard/app.py + - --server.address + - 0.0.0.0 + - --server.port + - "8501" + - --server.headless + - "true" + - --browser.gatherUsageStats + - "false" + container_port: 8501 + path: /_stcore/health + expected_status: 200 + expected_body: ok + timeout_seconds: 90 + + publish: + adapter: gitea-container-registry + registry: gitea.jsfamily.quest + repository: jsfamily/jarca-ledger-mcp + credentials: + username: authenticated-gitea-login + token_env: GITEA_TOKEN + tags: + - "{tag}" + - "sha-{commit}" + overwrite: false + verify: + - digest + - platform + - org.opencontainers.image.revision diff --git a/.github/workflows/publish-image.yml b/.github/workflows/publish-image.yml deleted file mode 100644 index 0e14d70..0000000 --- a/.github/workflows/publish-image.yml +++ /dev/null @@ -1,134 +0,0 @@ -name: Verify and publish ARM64 image - -on: - pull_request: - paths: - - Dockerfile - - .dockerignore - - pyproject.toml - - uv.lock - - jarca_ledger_mcp/** - - dashboard/** - - .github/workflows/publish-image.yml - push: - tags: - - "v*" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: image-${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - verify-arm64: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: docker/setup-qemu-action@v3 - with: - platforms: arm64 - - - uses: docker/setup-buildx-action@v3 - - - name: Build ARM64 verification image - uses: docker/build-push-action@v6 - with: - context: . - platforms: linux/arm64 - load: true - push: false - tags: jarca-ledger-mcp:arm64-verify - cache-from: type=gha,scope=jarca-ledger-arm64 - cache-to: type=gha,mode=max,scope=jarca-ledger-arm64 - - - name: Verify image platform, imports, and SQLite - run: | - set -euo pipefail - test "$(docker image inspect jarca-ledger-mcp:arm64-verify --format '{{.Architecture}}')" = arm64 - docker run --rm --platform linux/arm64 \ - -e JARCA_LEDGER_DB_PATH=/tmp/ledger.sqlite3 \ - jarca-ledger-mcp:arm64-verify \ - python -c 'import platform, cryptography, numpy, pandas, pyarrow, pymupdf; from jarca_ledger_mcp import service; result=service.health_check(); assert platform.machine() == "aarch64"; assert result["success"], result; print(result["schema_version"])' - - - name: Verify MCP and Dashboard startup - run: | - set -euo pipefail - trap 'docker rm -f jarca-mcp-smoke jarca-dashboard-smoke >/dev/null 2>&1 || true' EXIT - - docker run -d --name jarca-mcp-smoke --platform linux/arm64 \ - jarca-ledger-mcp:arm64-verify - for _ in $(seq 1 60); do - status=$(docker inspect --format '{{.State.Health.Status}}' jarca-mcp-smoke) - test "$status" = healthy && break - test "$status" = unhealthy && { docker logs jarca-mcp-smoke; exit 1; } - sleep 1 - done - test "$(docker inspect --format '{{.State.Health.Status}}' jarca-mcp-smoke)" = healthy - - docker run -d --name jarca-dashboard-smoke --platform linux/arm64 \ - -p 127.0.0.1::8501 jarca-ledger-mcp:arm64-verify \ - python -m streamlit run dashboard/app.py \ - --server.address 0.0.0.0 --server.port 8501 \ - --server.headless true --browser.gatherUsageStats false - port=$(docker port jarca-dashboard-smoke 8501/tcp | sed 's/.*://') - code=000 - for _ in $(seq 1 90); do - code=$(curl -sS -o /tmp/dashboard-health -w '%{http_code}' \ - "http://127.0.0.1:${port}/_stcore/health" || true) - test "$code" = 200 && break - sleep 1 - done - test "$code" = 200 - test "$(tr -d '\n' < /tmp/dashboard-health)" = ok - - publish: - if: startsWith(github.ref, 'refs/tags/v') - needs: verify-arm64 - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - outputs: - digest: ${{ steps.build.outputs.digest }} - steps: - - uses: actions/checkout@v4 - - - uses: docker/setup-qemu-action@v3 - with: - platforms: arm64 - - - uses: docker/setup-buildx-action@v3 - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and publish immutable ARM64 image - id: build - uses: docker/build-push-action@v6 - with: - context: . - platforms: linux/arm64 - push: true - tags: | - ghcr.io/genichin/jarca-ledger-mcp:${{ github.ref_name }} - ghcr.io/genichin/jarca-ledger-mcp:sha-${{ github.sha }} - labels: | - org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} - org.opencontainers.image.revision=${{ github.sha }} - org.opencontainers.image.version=${{ github.ref_name }} - cache-from: type=gha,scope=jarca-ledger-arm64 - cache-to: type=gha,mode=max,scope=jarca-ledger-arm64 - provenance: mode=max - sbom: true - - - name: Report published digest - run: | - echo "ghcr.io/genichin/jarca-ledger-mcp:${GITHUB_REF_NAME}@${{ steps.build.outputs.digest }}" diff --git a/README.md b/README.md index fa8efc2..33c1fc0 100644 --- a/README.md +++ b/README.md @@ -90,11 +90,11 @@ Deployment: jarca-ledger (replicas: 1) - MCP와 frontend는 목적별 Kubernetes Service로 분리합니다. MCP는 `8000`, frontend는 `8501`을 대상으로 합니다. - 외부 공개가 필요하면 일반적으로 frontend Service만 Ingress 또는 NodePort에 연결하고, MCP Service는 필요한 범위에서만 노출합니다. - ARM64 worker에서만 실행하도록 Pod의 `nodeSelector` 또는 node affinity를 설정합니다. -- 배포 이미지는 가변 태그 대신 검증된 GHCR digest로 고정합니다. +- 배포 이미지는 가변 태그 대신 검증된 `gitea.jsfamily.quest/jsfamily/jarca-ledger-mcp` Gitea Container Registry digest로 고정합니다. Streamlit이 SQLite에 직접 접근하지 않고 MCP/API만 호출하도록 변경하거나 네트워크 DB로 전환한 뒤에는 MCP와 frontend를 각각 독립 Deployment로 분리할 수 있습니다. -로컬 `docker-compose.yml`도 동일한 애플리케이션 이미지를 두 컨테이너로 실행하는 구조입니다. 현재 Compose 설정은 로컬에서 빌드한 `jarca-ledger:latest`를 사용하며, MCP는 호스트 `8000` 포트로, Streamlit은 호스트 `40059`에서 컨테이너 `8501` 포트로 연결됩니다. Compose 실행 전 host environment 또는 안전한 `.env` 전달 경계에 두 Dashboard credential 변수를 설정해야 하며 누락 시 Compose가 시작을 거부합니다. GHCR 릴리즈를 배포할 때는 두 서비스의 `image`를 검증된 동일 digest로 지정해야 합니다. +로컬 `docker-compose.yml`도 동일한 애플리케이션 이미지를 두 컨테이너로 실행하는 구조입니다. 현재 Compose 설정은 로컬에서 빌드한 `jarca-ledger:latest`를 사용하며, MCP는 호스트 `8000` 포트로, Streamlit은 호스트 `40059`에서 컨테이너 `8501` 포트로 연결됩니다. Compose 실행 전 host environment 또는 안전한 `.env` 전달 경계에 두 Dashboard credential 변수를 설정해야 하며 누락 시 Compose가 시작을 거부합니다. Gitea Container Registry 릴리즈를 배포할 때는 두 서비스의 `image`를 검증된 동일 `gitea.jsfamily.quest/jsfamily/jarca-ledger-mcp` digest로 지정해야 합니다. ## 주요 도구 diff --git a/jarca_ledger_mcp/__init__.py b/jarca_ledger_mcp/__init__.py index 1b71774..7d9c041 100644 --- a/jarca_ledger_mcp/__init__.py +++ b/jarca_ledger_mcp/__init__.py @@ -1,3 +1,3 @@ """Jarca Ledger MCP server.""" -__version__ = "0.1.0" +__version__ = "0.1.1" diff --git a/pyproject.toml b/pyproject.toml index 8598596..921be8b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "jarca-ledger-mcp" -version = "0.1.0" +version = "0.1.1" description = "Jarca household ledger MCP server for transactions, accounts, budgets, cashflow, and investable cashflow analysis" readme = "README.md" requires-python = ">=3.11" diff --git a/uv.lock b/uv.lock index 48d7de7..25edd7e 100644 --- a/uv.lock +++ b/uv.lock @@ -469,7 +469,7 @@ wheels = [ [[package]] name = "jarca-ledger-mcp" -version = "0.1.0" +version = "0.1.1" source = { editable = "." } dependencies = [ { name = "mcp" }, -- 2.54.0