Compare commits

..
6 Commits
Author SHA1 Message Date
Emil Simeonov 065a38b357 feat(ci): manifest-aware dependency PRs and cleanup protection
CI / validate (pull_request) Successful in 51s
CI / auto-merge (pull_request) Successful in 19s
2026-09-19 04:45:27 +02:00
kireto f15a8beb66 DEVX-167: feat(ci): verify producer container artifact before opening dependency PR
Post-merge / detect-and-configure (push) Successful in 10s
Post-merge / release-and-maintain (push) Successful in 1m15s
2026-09-19 02:43:55 +00:00
gitea-actions-bot 779aa0dfa4 chore: update badge URLs to commit 9f6cf573 [skip ci] 2026-09-19 02:34:58 +00:00
devx-ci-bot 5c4959b67a release: v0.51.12 [skip ci] 2026-09-19 02:34:17 +00:00
kireto 4ce25f16b2 DEVX-166: fix: create_dependency_pr clones target repo instead of editing producer checkout
Post-merge / detect-and-configure (push) Successful in 20s
Post-merge / release-and-maintain (push) Successful in 1m7s
2026-09-19 02:33:30 +00:00
devx-ci-bot f0b9b71811 release: v0.51.11 [skip ci] 2026-09-19 02:05:46 +00:00
10 changed files with 175 additions and 87 deletions
+12
View File
@@ -2,6 +2,18 @@
All notable changes to this project will be documented in this file.
## [0.51.12] - 2026-09-19
### Bug Fixes
- Create_dependency_pr clones target repo instead of editing producer checkout
## [0.51.11] - 2026-09-19
### Bug Fixes
- *(ci)* Retry Vikunja lookups and surface self-approval merge failures
## [0.51.10] - 2026-09-17
### Bug Fixes
+9 -9
View File
@@ -16,12 +16,12 @@ quality badges.
[![CI](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions/workflows/ci.yml/badge.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![License: GPL-3.0](https://img.shields.io/badge/license-GPL--3.0-blue)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/src/branch/master/LICENSE)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/python.svg)](https://www.python.org/downloads/)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/python.svg)](https://www.python.org/downloads/)
## Why devx?
@@ -87,7 +87,7 @@ extra index and list devx in your dependencies:
```toml
[project]
dependencies = [
"devx>=0.51.10",
"devx>=0.51.12",
]
[tool.pip]
@@ -101,8 +101,8 @@ pip install -e .
```
> **Note:** If your project requires a specific devx version, pin it in
> `dependencies` (for example, `"devx==0.51.10"`) or use a version constraint
> (for example, `"devx>=0.51.10,<0.52"`).
> `dependencies` (for example, `"devx==0.51.12"`) or use a version constraint
> (for example, `"devx>=0.51.12,<0.52"`).
### Optional extras
+8 -8
View File
@@ -12,12 +12,12 @@ project to be reusable across all oblachno-oss repositories.
[![CI](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions/workflows/ci.yml/badge.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![License: GPL-3.0](https://img.shields.io/badge/license-GPL--3.0-blue)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/src/branch/master/LICENSE)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/ef6e8cf76365d1332a88437ae62a93ef63335e68/python.svg)](https://www.python.org/downloads/)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/9f6cf5738cdf4edb7be7691a0bd7a4c4584ff9a2/python.svg)](https://www.python.org/downloads/)
## Overview
@@ -74,14 +74,14 @@ Add devx to your `pyproject.toml` dependencies and configure the registry:
```toml
[project]
dependencies = [
"devx>=0.51.10",
"devx>=0.51.12",
]
[tool.pip]
extra-index-url = "https://git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple"
```
Pin a specific version if needed: `"devx==0.51.10"` or `"devx>=0.51.10,<0.52"`.
Pin a specific version if needed: `"devx==0.51.12"` or `"devx>=0.51.12,<0.52"`.
### Optional extras
+35 -15
View File
@@ -1,27 +1,47 @@
# DEVX-166: Exclude docs/plans/* from PR size check
# DEVX-166: create_dependency_pr must clone the target repo
## Problem
Planning docs in `docs/plans/` are legitimately large (700+ lines) but
fail the PR size check (max 500 lines). This blocks PRs that only add
planning documents.
`create_dependency_pr` resolves the pinned-version file and runs all
git operations in the current working directory. Producer post-merge
workflows (grm, sso-bridge) invoke it from the *producer* checkout, so
it searches/modifies the wrong repository: `find_pinned_version` reads
files that do not exist there, and the git fetch/checkout/commit/push
sequence runs in the producer clone. The failure is silent — producer
workflows append `|| echo warning`, so a no-op looks like success.
## Approach
REQ-1: Add `docs/plans/*` to `DEFAULT_EXCLUDED_PATTERNS` in
`src/devx/ci/check_pr_size.py`
REQ-2: Add test coverage for the new exclusion pattern
REQ-1: Clone the target repo (`--repo`) into a temporary directory with
an authenticated `http.extraHeader`, then run every file lookup and git
operation (fetch, checkout, add, commit, push) inside that clone. The
push uses the same auth header config.
REQ-2: Tests mock `subprocess.run` so no real clone happens in the unit
suite (test-isolation gate).
## Files Affected
- `src/devx/ci/create_dependency_pr.py`
- `tests/unit/test_create_dependency_pr.py`
## Test Plan
- `make pytest-cov` passes with 100% coverage
- `make lint-all` passes
- Existing CLI tests keep passing with the subprocess mock in place.
- Verify the clone command targets the `--repo` URL and that git ops
run with `cwd=<clone>` (asserted via the mock's call list).
## Deploy Plan
- Merge to master → post-merge auto-publishes new devx version
- Infra PR #1179 picks up the fix once devx is bumped
Merge via auto-merge after green CI. The fix takes effect the next time
a producer post-merge workflow invokes `create_dependency_pr`.
## Rollback Plan
- Revert the merge commit
Revert the squash-merge commit on master; the previous (broken) CWD
behavior returns, which is strictly worse — no state is created.
## Acceptance Criteria
- [x] REQ-1: Add `docs/plans/*` to `DEFAULT_EXCLUDED_PATTERNS` in
`src/devx/ci/check_pr_size.py`
- [x] REQ-2: Add test coverage for the new exclusion pattern
- [x] REQ-1: target repo cloned to tempdir; all file/git ops run in the clone
- [x] REQ-2: unit tests never spawn a real git subprocess
+64
View File
@@ -0,0 +1,64 @@
# DEVX-167: Add dependency-graph, deployment-coordination, and skill-creation skills
## Problem
Agents working across the oblachno ecosystem lack shared, persistent
context for three recurring pain points:
1. **Cross-repo dependency ordering** — agents frequently merge
downstream PRs before the upstream publish job completes, or forget
to bump infra. There is no single reference for which repo produces
what and in what order changes must propagate.
2. **devx release coordination** — devx is the base package pinned by
grm, sso-bridge, and infra. Agents repeatedly merge devx PRs and
immediately merge downstream bumps without waiting for the PyPI
publish job, or bump only one consumer when a change affects all
three.
3. **Skill quality drift** — skills are created ad hoc with inconsistent
structure, vague advice, and no automated validation reference. New
skills miss required sections, reference nonexistent make targets,
and drift across repos.
## Approach
Add three SKILL.md files under `.devin/skills/`:
REQ-1: `dependency-graph` — shared skill mapping the oblachno ecosystem
(repos, what each produces, consumers, release triggers, correct
cross-repo change order, state verification checklist)
REQ-2: `deployment-coordination` — devx-specific skill covering the
devx release flow, downstream consumers, manual bump procedure, and
common mistakes when coordinating a devx change
REQ-3: `skill-creation` — shared skill defining skill structure,
quality standards, scope rules, automated validation reference, and a
creation checklist
## Files Affected
- `.devin/skills/dependency-graph/SKILL.md` (new)
- `.devin/skills/deployment-coordination/SKILL.md` (new)
- `.devin/skills/skill-creation/SKILL.md` (new)
- `docs/specs/DEVX-167.md` (new)
## Test Plan
- Verify all three SKILL.md files follow the required structure (H1
title, When to Invoke, Prerequisites sections)
- Verify referenced make targets and file paths exist
- Run `make pytest-cov` — skill validation tests must pass
## Deploy Plan
- Merge to master; skills are consumed by agents immediately on next
invocation — no build or deploy step required
## Rollback Plan
- Revert the merge commit; remove the three skill directories
## Acceptance Criteria
- [x] REQ-1: dependency-graph skill exists with ecosystem map, repo
table, dependency chain, cross-repo change order, and state
verification checklist
- [x] REQ-2: deployment-coordination skill exists with devx release
flow, downstream consumer table, coordination steps, and common
mistakes
- [x] REQ-3: skill-creation skill exists with structure template,
quality standards, scope rules, validation reference, and
creation checklist
+40 -47
View File
@@ -1,64 +1,57 @@
# DEVX-167: Add dependency-graph, deployment-coordination, and skill-creation skills
# DEVX-167: S03 artifact integrity — verify producer artifact + cleanup protection
## Problem
Agents working across the oblachno ecosystem lack shared, persistent
context for three recurring pain points:
1. **Cross-repo dependency ordering** — agents frequently merge
downstream PRs before the upstream publish job completes, or forget
to bump infra. There is no single reference for which repo produces
what and in what order changes must propagate.
2. **devx release coordination** — devx is the base package pinned by
grm, sso-bridge, and infra. Agents repeatedly merge devx PRs and
immediately merge downstream bumps without waiting for the PyPI
publish job, or bump only one consumer when a change affects all
three.
3. **Skill quality drift** — skills are created ad hoc with inconsistent
structure, vague advice, and no automated validation reference. New
skills miss required sections, reference nonexistent make targets,
and drift across repos.
S03 (OBL-INFRA-548 REQ-3) requires that dependency PRs only open after
the producer artifact exists and is content-addressable, and that
registry cleanup never deletes a version pinned by a release manifest.
Two gaps:
1. `create_dependency_pr` opens a bump PR unconditionally — if the
producer's publish job lagged or failed, the consumer pins a
nonexistent artifact.
2. The sso-bridge image tag is derived from `__init__.py.__version__`,
which does not always equal the release git tag, so the tag to
verify must be decoupled from `--new-version`.
## Approach
Add three SKILL.md files under `.devin/skills/`:
REQ-1: `dependency-graph` — shared skill mapping the oblachno ecosystem
(repos, what each produces, consumers, release triggers, correct
cross-repo change order, state verification checklist)
REQ-1: `create_dependency_pr` gains `--verify-container <owner/name>`
and `--container-tag <tag>`: before any branch/PR work it resolves the
OCI digest of the image tag via the Gitea packages API (`manifest.json`
blob sha256) and refuses the PR when the artifact is missing or
unreadable. `--container-tag` decouples the image tag from the release
version (sso-bridge tags images from `__init__.py.__version__`, not the
git tag).
REQ-2: `deployment-coordination` — devx-specific skill covering the
devx release flow, downstream consumers, manual bump procedure, and
common mistakes when coordinating a devx change
REQ-3: `skill-creation` — shared skill defining skill structure,
quality standards, scope rules, automated validation reference, and a
creation checklist
REQ-2: Regression tests cover digest resolution, verification-failure
aborts, invalid container format, and the `--container-tag` override.
## Files Affected
- `.devin/skills/dependency-graph/SKILL.md` (new)
- `.devin/skills/deployment-coordination/SKILL.md` (new)
- `.devin/skills/skill-creation/SKILL.md` (new)
- `docs/specs/DEVX-167.md` (new)
- `src/devx/ci/create_dependency_pr.py`
- `src/devx/translations.json`
- `tests/unit/test_create_dependency_pr.py`
## Test Plan
- Verify all three SKILL.md files follow the required structure (H1
title, When to Invoke, Prerequisites sections)
- Verify referenced make targets and file paths exist
- Run `make pytest-cov` — skill validation tests must pass
- Unit tests for `resolve_container_digest` (digest from manifest blob,
missing tag, missing blob, connection error).
- CLI tests: verify runs before version lookup, digest resolution,
invalid format rejection, container-tag override.
## Deploy Plan
- Merge to master; skills are consumed by agents immediately on next
invocation — no build or deploy step required
Merge via auto-merge after green CI. Producer post-merge workflows adopt
the new flags in their own PRs (sso-bridge SSO-22 already passes them).
## Rollback Plan
- Revert the merge commit; remove the three skill directories
Revert the squash-merge commit; the new options disappear and callers
without them behave exactly as before.
## Acceptance Criteria
- [x] REQ-1: dependency-graph skill exists with ecosystem map, repo
table, dependency chain, cross-repo change order, and state
verification checklist
- [x] REQ-2: deployment-coordination skill exists with devx release
flow, downstream consumer table, coordination steps, and common
mistakes
- [x] REQ-3: skill-creation skill exists with structure template,
quality standards, scope rules, validation reference, and
creation checklist
- [x] REQ-1: pre-PR OCI digest verification with --verify-container/--container-tag
- [x] REQ-2: regression tests for all new behavior
+2 -2
View File
@@ -48,12 +48,12 @@ Add devx to your `pyproject.toml`:
```toml
[project]
dependencies = [
"devx>=0.51.10",
"devx>=0.51.12",
]
[project.optional-dependencies]
dev = [
"devx>=0.51.10",
"devx>=0.51.12",
]
```
+1 -1
View File
@@ -6,4 +6,4 @@ create_dependency_pr, auto_merge, release, publish), developer tooling
molecule testing helpers for Ansible projects.
"""
__version__ = "0.51.10"
__version__ = "0.51.12"
+3 -4
View File
@@ -21,6 +21,7 @@ from __future__ import annotations
import re
import subprocess # nosec B404
import tempfile
from datetime import UTC, datetime
from pathlib import Path
@@ -283,10 +284,8 @@ def cli(
)
# Clone the target repo — this tool runs from the *producer* repo's CI,
# so every file lookup and git operation must happen in a clone of the
# target repo, not the producer checkout in CWD.
import tempfile
# so every file lookup and git operation must happen inside a clone of
# the target repo, not the producer checkout in CWD.
workdir = Path(tempfile.mkdtemp(prefix="dep-pr-"))
clone_url = f"{GITEA_API_URL.removesuffix('/api/v1')}/{repo}.git"
auth_cfg = f"http.extraHeader=Authorization: token {token}"
+1 -1
View File
@@ -17,7 +17,7 @@ from devx.ci.create_dependency_pr import (
@pytest.fixture(autouse=True)
def _mock_subprocess() -> MagicMock:
def _mock_subprocess():
"""Mock subprocess so CLI tests never run a real git clone."""
with patch("devx.ci.create_dependency_pr.subprocess.run") as m:
yield m