omneval-devloop 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. omneval_devloop-0.0.1/.github/workflows/build-agent-base-image.yml +53 -0
  2. omneval_devloop-0.0.1/.github/workflows/build-image.yml +111 -0
  3. omneval_devloop-0.0.1/.github/workflows/ci.yml +30 -0
  4. omneval_devloop-0.0.1/.github/workflows/publish-devloop-chart.yml +30 -0
  5. omneval_devloop-0.0.1/.github/workflows/publish-discord-bot-image.yml +58 -0
  6. omneval_devloop-0.0.1/.github/workflows/publish-poller-image.yml +59 -0
  7. omneval_devloop-0.0.1/.github/workflows/publish-temporal-worker-image.yml +41 -0
  8. omneval_devloop-0.0.1/.github/workflows/release.yml +170 -0
  9. omneval_devloop-0.0.1/.gitignore +218 -0
  10. omneval_devloop-0.0.1/CODEOWNERS +1 -0
  11. omneval_devloop-0.0.1/CONTEXT.md +82 -0
  12. omneval_devloop-0.0.1/LICENSE +201 -0
  13. omneval_devloop-0.0.1/PKG-INFO +11 -0
  14. omneval_devloop-0.0.1/README.md +2 -0
  15. omneval_devloop-0.0.1/charts/devloop/Chart.yaml +6 -0
  16. omneval_devloop-0.0.1/charts/devloop/templates/NOTES.txt +15 -0
  17. omneval_devloop-0.0.1/charts/devloop/templates/_helpers.tpl +36 -0
  18. omneval_devloop-0.0.1/charts/devloop/templates/discord-bot-deployment.yaml +44 -0
  19. omneval_devloop-0.0.1/charts/devloop/templates/poller-deployment.yaml +55 -0
  20. omneval_devloop-0.0.1/charts/devloop/templates/temporal-worker-deployment.yaml +49 -0
  21. omneval_devloop-0.0.1/charts/devloop/templates/temporal-worker-service.yaml +24 -0
  22. omneval_devloop-0.0.1/charts/devloop/test-values.yaml +11 -0
  23. omneval_devloop-0.0.1/charts/devloop/values.yaml +92 -0
  24. omneval_devloop-0.0.1/docs/getting-started.md +216 -0
  25. omneval_devloop-0.0.1/docs/temporal-prerequisites.md +106 -0
  26. omneval_devloop-0.0.1/images/agent-base/Dockerfile +72 -0
  27. omneval_devloop-0.0.1/images/agent-base/entrypoint.py +1049 -0
  28. omneval_devloop-0.0.1/images/agent-base/prompts/diagnosis.md +72 -0
  29. omneval_devloop-0.0.1/images/agent-base/prompts/implement.md +62 -0
  30. omneval_devloop-0.0.1/images/agent-base/prompts/merge.md +26 -0
  31. omneval_devloop-0.0.1/images/agent-base/prompts/plan.md +36 -0
  32. omneval_devloop-0.0.1/images/agent-base/prompts/review.md +74 -0
  33. omneval_devloop-0.0.1/images/agent-base/pytest.ini +3 -0
  34. omneval_devloop-0.0.1/images/agent-base/test_entrypoint.py +211 -0
  35. omneval_devloop-0.0.1/images/agent-base/test_human_question.py +459 -0
  36. omneval_devloop-0.0.1/images/agent-base/test_project_tests.py +523 -0
  37. omneval_devloop-0.0.1/images/agent-base/test_run_agent.py +715 -0
  38. omneval_devloop-0.0.1/images/discord-bot/Dockerfile +15 -0
  39. omneval_devloop-0.0.1/images/discord-bot/activities.py +96 -0
  40. omneval_devloop-0.0.1/images/discord-bot/discord_client.py +115 -0
  41. omneval_devloop-0.0.1/images/discord-bot/main.py +80 -0
  42. omneval_devloop-0.0.1/images/discord-bot/pyproject.toml +30 -0
  43. omneval_devloop-0.0.1/images/discord-bot/pytest.ini +4 -0
  44. omneval_devloop-0.0.1/images/discord-bot/test_text_utils.py +29 -0
  45. omneval_devloop-0.0.1/images/discord-bot/test_thread_store.py +199 -0
  46. omneval_devloop-0.0.1/images/discord-bot/text_utils.py +24 -0
  47. omneval_devloop-0.0.1/images/discord-bot/thread_store.py +77 -0
  48. omneval_devloop-0.0.1/images/discord-bot/uv.lock +1059 -0
  49. omneval_devloop-0.0.1/images/poller/Dockerfile +19 -0
  50. omneval_devloop-0.0.1/images/poller/poll.py +229 -0
  51. omneval_devloop-0.0.1/images/poller/pyproject.toml +28 -0
  52. omneval_devloop-0.0.1/images/poller/pytest.ini +4 -0
  53. omneval_devloop-0.0.1/images/poller/test_poll.py +109 -0
  54. omneval_devloop-0.0.1/images/poller/uv.lock +177 -0
  55. omneval_devloop-0.0.1/images/temporal-worker/Dockerfile +29 -0
  56. omneval_devloop-0.0.1/plan.md +313 -0
  57. omneval_devloop-0.0.1/pyproject.toml +38 -0
  58. omneval_devloop-0.0.1/src/devloop/__init__.py +27 -0
  59. omneval_devloop-0.0.1/src/devloop/cluster.py +79 -0
  60. omneval_devloop-0.0.1/src/devloop/dev_loop.py +395 -0
  61. omneval_devloop-0.0.1/src/devloop/dev_loop_logic.py +66 -0
  62. omneval_devloop-0.0.1/src/devloop/github_ops.py +167 -0
  63. omneval_devloop-0.0.1/src/devloop/k8s_jobs.py +367 -0
  64. omneval_devloop-0.0.1/src/devloop/projects.py +121 -0
  65. omneval_devloop-0.0.1/src/devloop/schedules.py +82 -0
  66. omneval_devloop-0.0.1/src/devloop/shared.py +244 -0
  67. omneval_devloop-0.0.1/src/devloop/summarization.py +69 -0
  68. omneval_devloop-0.0.1/src/devloop/summarize_activities.py +130 -0
  69. omneval_devloop-0.0.1/src/devloop/webhook.py +105 -0
  70. omneval_devloop-0.0.1/src/devloop/worker.py +124 -0
  71. omneval_devloop-0.0.1/src/devloop/workflows.py +25 -0
  72. omneval_devloop-0.0.1/tests/test_cluster.py +84 -0
  73. omneval_devloop-0.0.1/tests/test_dev_loop.py +405 -0
  74. omneval_devloop-0.0.1/tests/test_docs.py +109 -0
  75. omneval_devloop-0.0.1/tests/test_github_ops.py +131 -0
  76. omneval_devloop-0.0.1/tests/test_github_webhook.py +353 -0
  77. omneval_devloop-0.0.1/tests/test_k8s_jobs.py +374 -0
  78. omneval_devloop-0.0.1/tests/test_projects.py +97 -0
  79. omneval_devloop-0.0.1/tests/test_pure_logic.py +53 -0
  80. omneval_devloop-0.0.1/tests/test_stub_roundtrip.py +355 -0
  81. omneval_devloop-0.0.1/tests/test_summarization.py +102 -0
  82. omneval_devloop-0.0.1/tests/test_worker.py +47 -0
  83. omneval_devloop-0.0.1/uv.lock +793 -0
@@ -0,0 +1,53 @@
1
+ name: Build Agent Base Image
2
+
3
+ # Builds and publishes ghcr.io/omneval/devloop-agent-base — the shared toolchain
4
+ # base for all per-project agent images (OpenHands SDK, Temporal SDK, git, gh,
5
+ # kubectl, flux).
6
+ #
7
+ # Triggers (continuous / main only):
8
+ # - push to main → sha-<short>-<epoch> + latest tags (SDK unpinned = latest)
9
+ # - pull_request → build + test only (no push)
10
+ #
11
+ # Release (semver) builds run in release.yml, which pins omneval-devloop to the
12
+ # tag version and waits for the PyPI publish first. This workflow deliberately
13
+ # omits a tag trigger so the two never race.
14
+
15
+ on:
16
+ push:
17
+ branches: [main]
18
+ pull_request:
19
+
20
+ concurrency:
21
+ group: build-agent-base-${{ github.ref }}
22
+ cancel-in-progress: false
23
+
24
+ jobs:
25
+ test:
26
+ name: entrypoint tests
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+
31
+ - name: Install uv
32
+ uses: astral-sh/setup-uv@v5
33
+ with:
34
+ version: "0.9.11"
35
+
36
+ - name: Run entrypoint tests
37
+ working-directory: images/agent-base
38
+ run: uv run --with pytest --with pytest-asyncio pytest -q
39
+
40
+ build_and_push:
41
+ name: Build and push agent-base to GHCR
42
+ needs: test
43
+ # Grant the package-push scope the reusable workflow needs; the repo default
44
+ # token is capped at packages: read.
45
+ permissions:
46
+ packages: write
47
+ contents: read
48
+ uses: ./.github/workflows/build-image.yml
49
+ with:
50
+ image_name: devloop-agent-base
51
+ docker_context: './images/agent-base'
52
+ dockerfile: './images/agent-base/Dockerfile'
53
+ secrets: inherit
@@ -0,0 +1,111 @@
1
+ name: Build and Push Image
2
+
3
+ # Reusable workflow called by the per-image publish workflows and by the release
4
+ # orchestrator (release.yml). Handles checkout (workflow_run SHA pinning), GHCR
5
+ # auth, tag computation, metadata extraction, and the build/push step.
6
+ #
7
+ # The caller's github context flows through, so github.event_name and
8
+ # github.event.workflow_run.* are evaluated correctly here even though
9
+ # this workflow is triggered via workflow_call.
10
+ #
11
+ # SDK-embedding images pass build_args (SDK_VERSION) and wait_for_pypi so the
12
+ # pinned SDK is published before the image that bakes it is built.
13
+
14
+ on:
15
+ workflow_call:
16
+ inputs:
17
+ image_name:
18
+ description: 'Short image name (e.g. devloop-poller); appended to ghcr.io/omneval/'
19
+ required: true
20
+ type: string
21
+ docker_context:
22
+ description: 'Docker build context path (relative to repo root)'
23
+ required: true
24
+ type: string
25
+ dockerfile:
26
+ description: 'Path to the Dockerfile (relative to repo root)'
27
+ required: true
28
+ type: string
29
+ build_args:
30
+ description: 'Newline-separated KEY=value build args (e.g. SDK_VERSION=0.0.2)'
31
+ required: false
32
+ type: string
33
+ default: ''
34
+ wait_for_pypi:
35
+ description: 'If set ("pkg==version"), poll PyPI until that release is queryable before building'
36
+ required: false
37
+ type: string
38
+ default: ''
39
+
40
+ jobs:
41
+ build_and_push:
42
+ name: Build and push ${{ inputs.image_name }}
43
+ runs-on: ubuntu-latest
44
+ permissions:
45
+ packages: write
46
+ contents: read
47
+ steps:
48
+ - name: Check out the repo
49
+ uses: actions/checkout@v4
50
+ with:
51
+ # For workflow_run, build the exact commit whose CI just passed.
52
+ ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || '' }}
53
+
54
+ - name: Set up Docker Buildx
55
+ uses: docker/setup-buildx-action@v3
56
+
57
+ - name: Log in to GHCR
58
+ if: github.event_name != 'pull_request'
59
+ uses: docker/login-action@v3
60
+ with:
61
+ registry: ghcr.io
62
+ username: ${{ github.actor }}
63
+ password: ${{ secrets.GITHUB_TOKEN }}
64
+
65
+ - name: Wait for the pinned SDK to appear on PyPI
66
+ if: inputs.wait_for_pypi != ''
67
+ run: |
68
+ pkg_ver='${{ inputs.wait_for_pypi }}'
69
+ name="${pkg_ver%%==*}"
70
+ ver="${pkg_ver##*==}"
71
+ url="https://pypi.org/pypi/${name}/${ver}/json"
72
+ echo "Waiting for ${pkg_ver} at ${url}"
73
+ for i in $(seq 1 40); do
74
+ code=$(curl -s -o /dev/null -w '%{http_code}' "$url")
75
+ if [ "$code" = "200" ]; then
76
+ echo "Found ${pkg_ver} on PyPI (attempt $i)"
77
+ exit 0
78
+ fi
79
+ echo "Attempt $i/40: ${pkg_ver} not on PyPI yet (HTTP $code); retrying in 15s"
80
+ sleep 15
81
+ done
82
+ echo "ERROR: ${pkg_ver} did not appear on PyPI within ~10 minutes"
83
+ exit 1
84
+
85
+ - name: Compute sha-<short>-<epoch> tag
86
+ id: shatag
87
+ run: echo "value=sha-$(git rev-parse --short=7 HEAD)-$(date +%s)" >> "$GITHUB_OUTPUT"
88
+
89
+ - name: Extract metadata (tags, labels) for Docker
90
+ id: meta
91
+ uses: docker/metadata-action@v5
92
+ with:
93
+ images: ghcr.io/omneval/${{ inputs.image_name }}
94
+ # sha/latest track the rolling main line (workflow_run after CI, or a
95
+ # direct push to main). type=semver emits only on tag refs, which is
96
+ # the release path, so it needs no explicit enable guard.
97
+ tags: |
98
+ type=raw,value=${{ steps.shatag.outputs.value }},enable=${{ github.event_name == 'workflow_run' || github.ref == 'refs/heads/main' }}
99
+ type=raw,value=latest,enable=${{ github.event_name == 'workflow_run' || github.ref == 'refs/heads/main' }}
100
+ type=semver,pattern={{version}}
101
+ type=semver,pattern={{major}}.{{minor}}
102
+
103
+ - name: Build and push ${{ inputs.image_name }} image
104
+ uses: docker/build-push-action@v6
105
+ with:
106
+ context: ${{ inputs.docker_context }}
107
+ file: ${{ inputs.dockerfile }}
108
+ build-args: ${{ inputs.build_args }}
109
+ push: ${{ github.event_name != 'pull_request' }}
110
+ tags: ${{ steps.meta.outputs.tags }}
111
+ labels: ${{ steps.meta.outputs.labels }}
@@ -0,0 +1,30 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ with:
14
+ # Full history + tags so hatch-vcs can resolve the package version
15
+ # when uv sync builds the local project.
16
+ fetch-depth: 0
17
+
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v5
20
+ with:
21
+ version: "0.9.11"
22
+
23
+ - name: Install dependencies
24
+ run: uv sync --all-groups
25
+
26
+ - name: Lint
27
+ run: uv run ruff check src/ tests/
28
+
29
+ - name: Test
30
+ run: uv run pytest
@@ -0,0 +1,30 @@
1
+ name: Lint Devloop Helm Chart
2
+
3
+ # Validates the devloop Helm chart on pull requests. Packaging and publishing the
4
+ # chart as an OCI artifact to ghcr.io/omneval/charts/devloop happens in
5
+ # release.yml on a v* tag.
6
+
7
+ on:
8
+ pull_request:
9
+
10
+ jobs:
11
+ lint:
12
+ name: Package and lint chart
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Check out the repo
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Set up Helm
19
+ uses: azure/setup-helm@v4
20
+ with:
21
+ version: v3.14.0
22
+
23
+ - name: Package chart
24
+ id: package
25
+ run: |
26
+ helm package charts/devloop/ -u -d .cr-release-packages
27
+ echo "chart=$(ls .cr-release-packages/devloop-*.tgz)" >> "$GITHUB_OUTPUT"
28
+
29
+ - name: Lint chart
30
+ run: helm lint ${{ steps.package.outputs.chart }}
@@ -0,0 +1,58 @@
1
+ name: Publish Discord Bot Image
2
+
3
+ # Builds and publishes ghcr.io/omneval/devloop-discord-bot — the Discord <-> Temporal
4
+ # bridge for Phase Gates and changelog posts.
5
+ #
6
+ # Triggers (continuous / main only):
7
+ # - workflow_run after "CI" succeeds on main → sha-<short>-<epoch> + latest tags
8
+ # - pull_request → build + test only (no push)
9
+ #
10
+ # Depending on CI (rather than push to main directly) ensures the image is never
11
+ # pushed against a broken devloop package. Release (semver) builds run in
12
+ # release.yml; this workflow has no tag trigger so the two never race.
13
+
14
+ on:
15
+ workflow_run:
16
+ workflows: ["CI"]
17
+ types: [completed]
18
+ pull_request:
19
+
20
+ concurrency:
21
+ group: publish-discord-bot-${{ github.ref }}
22
+ cancel-in-progress: false
23
+
24
+ jobs:
25
+ test:
26
+ name: discord-bot tests
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ with:
31
+ ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || '' }}
32
+
33
+ - name: Install uv
34
+ uses: astral-sh/setup-uv@v5
35
+ with:
36
+ version: "0.9.11"
37
+
38
+ - name: Run tests
39
+ working-directory: images/discord-bot
40
+ run: uv run pytest -q
41
+
42
+ build_and_push:
43
+ name: Build and push discord-bot to GHCR
44
+ needs: test
45
+ if: >-
46
+ github.event_name == 'pull_request' ||
47
+ (github.event_name == 'workflow_run' &&
48
+ github.event.workflow_run.conclusion == 'success' &&
49
+ github.event.workflow_run.head_branch == 'main')
50
+ permissions:
51
+ packages: write
52
+ contents: read
53
+ uses: ./.github/workflows/build-image.yml
54
+ with:
55
+ image_name: devloop-discord-bot
56
+ docker_context: './images/discord-bot'
57
+ dockerfile: './images/discord-bot/Dockerfile'
58
+ secrets: inherit
@@ -0,0 +1,59 @@
1
+ name: Publish Poller Image
2
+
3
+ # Builds and publishes ghcr.io/omneval/devloop-poller — the GitHub issue poller
4
+ # that detects `agent-ready`-labeled issues and forwards them to the Temporal
5
+ # Orchestration Worker webhook to start a Dev Loop.
6
+ #
7
+ # Triggers (continuous / main only):
8
+ # - workflow_run after "CI" succeeds on main → sha-<short>-<epoch> + latest tags
9
+ # - pull_request → build + test only (no push)
10
+ #
11
+ # Depending on CI (rather than push to main directly) ensures the image is never
12
+ # pushed against a broken devloop package. Release (semver) builds run in
13
+ # release.yml; this workflow has no tag trigger so the two never race.
14
+
15
+ on:
16
+ workflow_run:
17
+ workflows: ["CI"]
18
+ types: [completed]
19
+ pull_request:
20
+
21
+ concurrency:
22
+ group: publish-poller-${{ github.ref }}
23
+ cancel-in-progress: false
24
+
25
+ jobs:
26
+ test:
27
+ name: poller tests
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ with:
32
+ ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || '' }}
33
+
34
+ - name: Install uv
35
+ uses: astral-sh/setup-uv@v5
36
+ with:
37
+ version: "0.9.11"
38
+
39
+ - name: Run tests
40
+ working-directory: images/poller
41
+ run: uv run pytest -q
42
+
43
+ build_and_push:
44
+ name: Build and push poller to GHCR
45
+ needs: test
46
+ if: >-
47
+ github.event_name == 'pull_request' ||
48
+ (github.event_name == 'workflow_run' &&
49
+ github.event.workflow_run.conclusion == 'success' &&
50
+ github.event.workflow_run.head_branch == 'main')
51
+ permissions:
52
+ packages: write
53
+ contents: read
54
+ uses: ./.github/workflows/build-image.yml
55
+ with:
56
+ image_name: devloop-poller
57
+ docker_context: '.'
58
+ dockerfile: './images/poller/Dockerfile'
59
+ secrets: inherit
@@ -0,0 +1,41 @@
1
+ name: Publish Temporal Worker Image
2
+
3
+ # Builds and publishes ghcr.io/omneval/devloop-temporal-worker — the reference
4
+ # Temporal Orchestration Worker that installs omneval-devloop and registers the
5
+ # Dev Loop + Summarization workflows.
6
+ #
7
+ # Triggers (continuous / main only):
8
+ # - workflow_run after "CI" succeeds on main → sha-<short>-<epoch> + latest tags
9
+ # - pull_request → build only (no push)
10
+ #
11
+ # Release (semver) builds run in release.yml, which pins the SDK to the tag and
12
+ # waits for the PyPI publish first; this workflow has no tag trigger so the two
13
+ # never race. On main the SDK is installed unpinned (latest release).
14
+
15
+ on:
16
+ workflow_run:
17
+ workflows: ["CI"]
18
+ types: [completed]
19
+ pull_request:
20
+
21
+ concurrency:
22
+ group: publish-temporal-worker-${{ github.ref }}
23
+ cancel-in-progress: false
24
+
25
+ jobs:
26
+ build_and_push:
27
+ name: Build and push temporal-worker to GHCR
28
+ if: >-
29
+ github.event_name == 'pull_request' ||
30
+ (github.event_name == 'workflow_run' &&
31
+ github.event.workflow_run.conclusion == 'success' &&
32
+ github.event.workflow_run.head_branch == 'main')
33
+ permissions:
34
+ packages: write
35
+ contents: read
36
+ uses: ./.github/workflows/build-image.yml
37
+ with:
38
+ image_name: devloop-temporal-worker
39
+ docker_context: './images/temporal-worker'
40
+ dockerfile: './images/temporal-worker/Dockerfile'
41
+ secrets: inherit
@@ -0,0 +1,170 @@
1
+ name: Release
2
+
3
+ # Single orchestrator for a tagged release. Pushing a v* tag drives the whole
4
+ # release as one job DAG, so ordering is structural (needs:) instead of a race
5
+ # between independent workflows:
6
+ #
7
+ # test ─┬─> pypi ─> sdk-images (agent-base, temporal-worker) [pinned SDK]
8
+ # ├─> chart [parallel]
9
+ # └─> images (discord-bot, poller) [parallel, no SDK]
10
+ #
11
+ # The git tag is the single source of truth: hatch-vcs derives the SDK version
12
+ # from it (e.g. v0.0.2 -> 0.0.2), the PyPI release carries that version, the
13
+ # Docker images are tagged with the same semver, and the SDK pinned into the
14
+ # SDK-embedding images is exactly that release — so an image tagged 0.0.2 can
15
+ # never contain SDK 0.0.1. sdk-images both `needs: pypi` and wait for the release
16
+ # to be queryable on PyPI before building.
17
+ #
18
+ # The continuous (main) path is unchanged and lives elsewhere: ci.yml runs the
19
+ # SDK suite, and the per-image publish-*-image.yml workflows publish sha/latest
20
+ # after CI succeeds.
21
+
22
+ on:
23
+ push:
24
+ tags: ['v*']
25
+
26
+ concurrency:
27
+ group: release-${{ github.ref }}
28
+ cancel-in-progress: false
29
+
30
+ jobs:
31
+ meta:
32
+ name: Resolve release version
33
+ runs-on: ubuntu-latest
34
+ outputs:
35
+ version: ${{ steps.v.outputs.version }}
36
+ steps:
37
+ # v0.0.2 -> 0.0.2; used to pin the SDK and to poll PyPI.
38
+ - id: v
39
+ run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
40
+
41
+ test:
42
+ name: SDK test suite
43
+ runs-on: ubuntu-latest
44
+ steps:
45
+ - uses: actions/checkout@v4
46
+ with:
47
+ # Full history + tags so hatch-vcs can resolve the version.
48
+ fetch-depth: 0
49
+
50
+ - name: Install uv
51
+ uses: astral-sh/setup-uv@v5
52
+ with:
53
+ version: "0.9.11"
54
+
55
+ - name: Install dependencies
56
+ run: uv sync --all-groups
57
+
58
+ - name: Lint
59
+ run: uv run ruff check src/ tests/
60
+
61
+ - name: Test
62
+ run: uv run pytest
63
+
64
+ pypi:
65
+ name: Build and publish to PyPI
66
+ needs: test
67
+ runs-on: ubuntu-latest
68
+ environment: pypi
69
+ permissions:
70
+ id-token: write
71
+ steps:
72
+ - uses: actions/checkout@v4
73
+ with:
74
+ # hatch-vcs reads the tag from git history to version the build.
75
+ fetch-depth: 0
76
+
77
+ - name: Install uv
78
+ uses: astral-sh/setup-uv@v5
79
+ with:
80
+ version: "0.11.18"
81
+
82
+ - name: Build package
83
+ run: uv build
84
+
85
+ - name: Publish to PyPI
86
+ uses: pypa/gh-action-pypi-publish@release/v1
87
+
88
+ chart:
89
+ name: Package and push Helm chart
90
+ needs: test
91
+ runs-on: ubuntu-latest
92
+ permissions:
93
+ packages: write
94
+ contents: read
95
+ steps:
96
+ - uses: actions/checkout@v4
97
+
98
+ - name: Set up Helm
99
+ uses: azure/setup-helm@v4
100
+ with:
101
+ version: v3.14.0
102
+
103
+ - name: Log in to GHCR
104
+ uses: docker/login-action@v3
105
+ with:
106
+ registry: ghcr.io
107
+ username: ${{ github.actor }}
108
+ password: ${{ secrets.GITHUB_TOKEN }}
109
+
110
+ - name: Package chart
111
+ id: package
112
+ run: |
113
+ helm package charts/devloop/ -u -d .cr-release-packages
114
+ echo "chart=$(ls .cr-release-packages/devloop-*.tgz)" >> "$GITHUB_OUTPUT"
115
+
116
+ - name: Lint chart
117
+ run: helm lint ${{ steps.package.outputs.chart }}
118
+
119
+ - name: Push chart to GHCR
120
+ run: helm push ${{ steps.package.outputs.chart }} oci://ghcr.io/omneval/charts
121
+
122
+ images:
123
+ name: Build ${{ matrix.image_name }}
124
+ needs: test
125
+ # A job calling a reusable workflow must grant the permissions that workflow
126
+ # needs; otherwise the token is capped at the repo default (packages: read).
127
+ permissions:
128
+ packages: write
129
+ contents: read
130
+ strategy:
131
+ matrix:
132
+ include:
133
+ - image_name: devloop-discord-bot
134
+ docker_context: './images/discord-bot'
135
+ dockerfile: './images/discord-bot/Dockerfile'
136
+ - image_name: devloop-poller
137
+ docker_context: '.'
138
+ dockerfile: './images/poller/Dockerfile'
139
+ uses: ./.github/workflows/build-image.yml
140
+ with:
141
+ image_name: ${{ matrix.image_name }}
142
+ docker_context: ${{ matrix.docker_context }}
143
+ dockerfile: ${{ matrix.dockerfile }}
144
+ secrets: inherit
145
+
146
+ sdk-images:
147
+ name: Build ${{ matrix.image_name }}
148
+ # Only build after the pinned SDK is published; the reusable workflow also
149
+ # waits for it to be queryable on PyPI before building.
150
+ needs: [test, meta, pypi]
151
+ permissions:
152
+ packages: write
153
+ contents: read
154
+ strategy:
155
+ matrix:
156
+ include:
157
+ - image_name: devloop-agent-base
158
+ docker_context: './images/agent-base'
159
+ dockerfile: './images/agent-base/Dockerfile'
160
+ - image_name: devloop-temporal-worker
161
+ docker_context: './images/temporal-worker'
162
+ dockerfile: './images/temporal-worker/Dockerfile'
163
+ uses: ./.github/workflows/build-image.yml
164
+ with:
165
+ image_name: ${{ matrix.image_name }}
166
+ docker_context: ${{ matrix.docker_context }}
167
+ dockerfile: ${{ matrix.dockerfile }}
168
+ build_args: SDK_VERSION=${{ needs.meta.outputs.version }}
169
+ wait_for_pypi: omneval-devloop==${{ needs.meta.outputs.version }}
170
+ secrets: inherit