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.
- omneval_devloop-0.0.1/.github/workflows/build-agent-base-image.yml +53 -0
- omneval_devloop-0.0.1/.github/workflows/build-image.yml +111 -0
- omneval_devloop-0.0.1/.github/workflows/ci.yml +30 -0
- omneval_devloop-0.0.1/.github/workflows/publish-devloop-chart.yml +30 -0
- omneval_devloop-0.0.1/.github/workflows/publish-discord-bot-image.yml +58 -0
- omneval_devloop-0.0.1/.github/workflows/publish-poller-image.yml +59 -0
- omneval_devloop-0.0.1/.github/workflows/publish-temporal-worker-image.yml +41 -0
- omneval_devloop-0.0.1/.github/workflows/release.yml +170 -0
- omneval_devloop-0.0.1/.gitignore +218 -0
- omneval_devloop-0.0.1/CODEOWNERS +1 -0
- omneval_devloop-0.0.1/CONTEXT.md +82 -0
- omneval_devloop-0.0.1/LICENSE +201 -0
- omneval_devloop-0.0.1/PKG-INFO +11 -0
- omneval_devloop-0.0.1/README.md +2 -0
- omneval_devloop-0.0.1/charts/devloop/Chart.yaml +6 -0
- omneval_devloop-0.0.1/charts/devloop/templates/NOTES.txt +15 -0
- omneval_devloop-0.0.1/charts/devloop/templates/_helpers.tpl +36 -0
- omneval_devloop-0.0.1/charts/devloop/templates/discord-bot-deployment.yaml +44 -0
- omneval_devloop-0.0.1/charts/devloop/templates/poller-deployment.yaml +55 -0
- omneval_devloop-0.0.1/charts/devloop/templates/temporal-worker-deployment.yaml +49 -0
- omneval_devloop-0.0.1/charts/devloop/templates/temporal-worker-service.yaml +24 -0
- omneval_devloop-0.0.1/charts/devloop/test-values.yaml +11 -0
- omneval_devloop-0.0.1/charts/devloop/values.yaml +92 -0
- omneval_devloop-0.0.1/docs/getting-started.md +216 -0
- omneval_devloop-0.0.1/docs/temporal-prerequisites.md +106 -0
- omneval_devloop-0.0.1/images/agent-base/Dockerfile +72 -0
- omneval_devloop-0.0.1/images/agent-base/entrypoint.py +1049 -0
- omneval_devloop-0.0.1/images/agent-base/prompts/diagnosis.md +72 -0
- omneval_devloop-0.0.1/images/agent-base/prompts/implement.md +62 -0
- omneval_devloop-0.0.1/images/agent-base/prompts/merge.md +26 -0
- omneval_devloop-0.0.1/images/agent-base/prompts/plan.md +36 -0
- omneval_devloop-0.0.1/images/agent-base/prompts/review.md +74 -0
- omneval_devloop-0.0.1/images/agent-base/pytest.ini +3 -0
- omneval_devloop-0.0.1/images/agent-base/test_entrypoint.py +211 -0
- omneval_devloop-0.0.1/images/agent-base/test_human_question.py +459 -0
- omneval_devloop-0.0.1/images/agent-base/test_project_tests.py +523 -0
- omneval_devloop-0.0.1/images/agent-base/test_run_agent.py +715 -0
- omneval_devloop-0.0.1/images/discord-bot/Dockerfile +15 -0
- omneval_devloop-0.0.1/images/discord-bot/activities.py +96 -0
- omneval_devloop-0.0.1/images/discord-bot/discord_client.py +115 -0
- omneval_devloop-0.0.1/images/discord-bot/main.py +80 -0
- omneval_devloop-0.0.1/images/discord-bot/pyproject.toml +30 -0
- omneval_devloop-0.0.1/images/discord-bot/pytest.ini +4 -0
- omneval_devloop-0.0.1/images/discord-bot/test_text_utils.py +29 -0
- omneval_devloop-0.0.1/images/discord-bot/test_thread_store.py +199 -0
- omneval_devloop-0.0.1/images/discord-bot/text_utils.py +24 -0
- omneval_devloop-0.0.1/images/discord-bot/thread_store.py +77 -0
- omneval_devloop-0.0.1/images/discord-bot/uv.lock +1059 -0
- omneval_devloop-0.0.1/images/poller/Dockerfile +19 -0
- omneval_devloop-0.0.1/images/poller/poll.py +229 -0
- omneval_devloop-0.0.1/images/poller/pyproject.toml +28 -0
- omneval_devloop-0.0.1/images/poller/pytest.ini +4 -0
- omneval_devloop-0.0.1/images/poller/test_poll.py +109 -0
- omneval_devloop-0.0.1/images/poller/uv.lock +177 -0
- omneval_devloop-0.0.1/images/temporal-worker/Dockerfile +29 -0
- omneval_devloop-0.0.1/plan.md +313 -0
- omneval_devloop-0.0.1/pyproject.toml +38 -0
- omneval_devloop-0.0.1/src/devloop/__init__.py +27 -0
- omneval_devloop-0.0.1/src/devloop/cluster.py +79 -0
- omneval_devloop-0.0.1/src/devloop/dev_loop.py +395 -0
- omneval_devloop-0.0.1/src/devloop/dev_loop_logic.py +66 -0
- omneval_devloop-0.0.1/src/devloop/github_ops.py +167 -0
- omneval_devloop-0.0.1/src/devloop/k8s_jobs.py +367 -0
- omneval_devloop-0.0.1/src/devloop/projects.py +121 -0
- omneval_devloop-0.0.1/src/devloop/schedules.py +82 -0
- omneval_devloop-0.0.1/src/devloop/shared.py +244 -0
- omneval_devloop-0.0.1/src/devloop/summarization.py +69 -0
- omneval_devloop-0.0.1/src/devloop/summarize_activities.py +130 -0
- omneval_devloop-0.0.1/src/devloop/webhook.py +105 -0
- omneval_devloop-0.0.1/src/devloop/worker.py +124 -0
- omneval_devloop-0.0.1/src/devloop/workflows.py +25 -0
- omneval_devloop-0.0.1/tests/test_cluster.py +84 -0
- omneval_devloop-0.0.1/tests/test_dev_loop.py +405 -0
- omneval_devloop-0.0.1/tests/test_docs.py +109 -0
- omneval_devloop-0.0.1/tests/test_github_ops.py +131 -0
- omneval_devloop-0.0.1/tests/test_github_webhook.py +353 -0
- omneval_devloop-0.0.1/tests/test_k8s_jobs.py +374 -0
- omneval_devloop-0.0.1/tests/test_projects.py +97 -0
- omneval_devloop-0.0.1/tests/test_pure_logic.py +53 -0
- omneval_devloop-0.0.1/tests/test_stub_roundtrip.py +355 -0
- omneval_devloop-0.0.1/tests/test_summarization.py +102 -0
- omneval_devloop-0.0.1/tests/test_worker.py +47 -0
- 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
|