Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ integration PRs, follows `main` through production, and pauses after failures.

## Install

Install the reviewed `v0.2.5` source commit directly from GitHub:
Install the reviewed `v0.2.6` source commit directly from GitHub:

```bash
python3 -m pip install \
'deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@94fe042a58c731343c8bbd73d0bdfcb38a55866f'
'deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@a0e2c833282e63bf5db4339f99773aa9ba2f0c82'
deploybot init
```

Expand Down Expand Up @@ -86,7 +86,7 @@ aligned with `pipeline.ci_workflows`. The privileged worker never checks out or
executes pull-request code. Pin the Action to the full reviewed release commit:

```yaml
- uses: Forward-Future/DeployBot@94fe042a58c731343c8bbd73d0bdfcb38a55866f
- uses: Forward-Future/DeployBot@a0e2c833282e63bf5db4339f99773aa9ba2f0c82
```

The Action uses GitHub's built-in workflow token. GitHub intentionally does not
Expand Down
2 changes: 1 addition & 1 deletion adapters/claude-code/.mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"command": "uvx",
"args": [
"--from",
"deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@94fe042a58c731343c8bbd73d0bdfcb38a55866f",
"deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@a0e2c833282e63bf5db4339f99773aa9ba2f0c82",
"deploybot-mcp"
]
}
Expand Down
2 changes: 1 addition & 1 deletion adapters/codex/agent-merge-queue/.mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"command": "uvx",
"args": [
"--from",
"deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@94fe042a58c731343c8bbd73d0bdfcb38a55866f",
"deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@a0e2c833282e63bf5db4339f99773aa9ba2f0c82",
"deploybot-mcp"
]
}
Expand Down
2 changes: 1 addition & 1 deletion adapters/cursor/.cursor/mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"command": "uvx",
"args": [
"--from",
"deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@94fe042a58c731343c8bbd73d0bdfcb38a55866f",
"deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@a0e2c833282e63bf5db4339f99773aa9ba2f0c82",
"deploybot-mcp"
]
}
Expand Down
4 changes: 2 additions & 2 deletions examples/github-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ jobs:
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
# v0.2.5 implementation; keep the full commit for privileged workflows.
- uses: Forward-Future/DeployBot@94fe042a58c731343c8bbd73d0bdfcb38a55866f
# v0.2.6 implementation; keep the full commit for privileged workflows.
- uses: Forward-Future/DeployBot@a0e2c833282e63bf5db4339f99773aa9ba2f0c82
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "deploybot-merge-queue"
version = "0.2.5"
version = "0.2.6"
description = "DeployBot: a provider-neutral GitHub merge queue for coding agents"
readme = "README.md"
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion src/agent_merge_queue/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""DeployBot: a provider-neutral GitHub merge queue for coding agents."""

__version__ = "0.2.5"
__version__ = "0.2.6"
13 changes: 11 additions & 2 deletions src/agent_merge_queue/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ def release_state(
# the downstream run against the default-branch SHA, so it can otherwise
# hide a real deployment (or look like a deployment failure) for that same
# revision. A skipped run did not attempt a release and is not evidence.
ci_fence = str((ci or {}).get("updated_at") or (ci or {}).get("created_at") or "")
ci_fence = parse_time(
str((ci or {}).get("updated_at") or (ci or {}).get("created_at") or "")
)
deploy = latest_run(
[
run
Expand All @@ -63,7 +65,14 @@ def release_state(
str(run.get("status") or "") == "completed"
and str(run.get("conclusion") or "") == "skipped"
)
and (not ci_fence or str(run.get("created_at") or "") >= ci_fence)
and (
ci_fence is None
or (
(created_at := parse_time(str(run.get("created_at") or "")))
is not None
and created_at >= ci_fence
)
)
],
config.deploy_workflows,
main_sha,
Expand Down
27 changes: 27 additions & 0 deletions tests/test_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,33 @@ def test_new_successful_ci_supersedes_an_older_failed_deploy(self) -> None:
self.assertEqual(value["state"], "awaiting-deploy")
self.assertIsNone(value["latest_deploy"])

def test_release_fence_compares_normalized_timestamps(self) -> None:
sha = "a" * 40
runs = [
{
"id": 1,
"name": "CI",
"head_sha": sha,
"status": "completed",
"conclusion": "success",
"created_at": "2026-06-20T00:00:00Z",
"updated_at": "2026-06-20T01:00:00+01:00",
},
{
"id": 2,
"name": "Deploy",
"head_sha": sha,
"status": "completed",
"conclusion": "success",
"created_at": "2026-06-20T00:30:00.000Z",
},
]

value = release_state(main_sha=sha, runs=runs, config=CONFIG.pipeline)

self.assertEqual(value["state"], "verified")
self.assertEqual(value["latest_deploy"]["id"], 2)

def test_follow_dispatches_deploy_after_token_dispatched_ci(self) -> None:
sha = "a" * 40
ci = {
Expand Down
2 changes: 1 addition & 1 deletion tests/test_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

ROOT = Path(__file__).resolve().parents[1]
CANONICAL = ROOT / "skills" / "deploybot" / "SKILL.md"
RELEASE_COMMIT = "94fe042a58c731343c8bbd73d0bdfcb38a55866f"
RELEASE_COMMIT = "a0e2c833282e63bf5db4339f99773aa9ba2f0c82"
CHECKOUT_COMMIT = "9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"


Expand Down