Skip to content

Commit b634077

Browse files
authored
feat: change configuration file format (#813)
This change changes the configuration format to: ``` scopes: merge_queue_scope: merge-queue mode: parallel source: files: js: include: - "**/*.js" python: include: - "**/*.py" other: include: - "**/*" exclude: - "**/*.py" - "**/*.js" ``` Sources will later have value like: `bazel`, `nx`, `turporepo` We will have something like: ``` scopes: merge_queue_scope: merge-queue mode: parallel source: nx: command: ["npx", "nx"] ``` To get the scopes, this will run: `npx nx show projects --affected --base={base} --head={head}"`
1 parent 8ca8587 commit b634077

File tree

2 files changed

+194
-54
lines changed

2 files changed

+194
-54
lines changed

mergify_cli/ci/scopes/cli.py

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,38 @@ class ConfigInvalidError(exceptions.ScopesError):
2626
pass
2727

2828

29-
class ScopeConfig(pydantic.BaseModel):
30-
include: tuple[str, ...] = pydantic.Field(default_factory=tuple)
31-
exclude: tuple[str, ...] = pydantic.Field(default_factory=tuple)
32-
33-
3429
ScopeName = typing.Annotated[
3530
str,
3631
pydantic.StringConstraints(pattern=SCOPE_NAME_RE, min_length=1),
3732
]
3833

3934

40-
class Config(pydantic.BaseModel):
41-
scopes: dict[ScopeName, ScopeConfig]
35+
class FileFilters(pydantic.BaseModel):
36+
include: tuple[str, ...] = pydantic.Field(default_factory=lambda: ("**/*",))
37+
exclude: tuple[str, ...] = pydantic.Field(default_factory=tuple)
38+
39+
40+
class SourceFiles(pydantic.BaseModel):
41+
files: dict[ScopeName, FileFilters]
42+
43+
44+
class SourceOther(pydantic.BaseModel):
45+
other: None
46+
47+
48+
class ScopesConfig(pydantic.BaseModel):
49+
model_config = pydantic.ConfigDict(extra="forbid")
50+
51+
mode: typing.Literal["serial", "parallel"] = "serial"
52+
source: SourceFiles | SourceOther | None = None
4253
merge_queue_scope: str | None = "merge-queue"
4354

55+
56+
class Config(pydantic.BaseModel):
57+
model_config = pydantic.ConfigDict(extra="ignore")
58+
59+
scopes: ScopesConfig
60+
4461
@classmethod
4562
def from_dict(cls, data: dict[str, typing.Any] | typing.Any) -> Config: # noqa: ANN401
4663
try:
@@ -60,15 +77,15 @@ def from_yaml(cls, path: str) -> Config:
6077

6178

6279
def match_scopes(
63-
config: Config,
6480
files: abc.Iterable[str],
81+
filters: dict[ScopeName, FileFilters],
6582
) -> tuple[set[str], dict[str, list[str]]]:
6683
scopes_hit: set[str] = set()
67-
per_scope: dict[str, list[str]] = {s: [] for s in config.scopes}
84+
per_scope: dict[str, list[str]] = {s: [] for s in filters}
6885
for f in files:
6986
# NOTE(sileht): we use pathlib.full_match to support **, as fnmatch does not
7087
p = pathlib.PurePosixPath(f)
71-
for scope, scope_config in config.scopes.items():
88+
for scope, scope_config in filters.items():
7289
if not scope_config.include and not scope_config.exclude:
7390
continue
7491

@@ -128,14 +145,32 @@ def load_from_file(cls, filename: str) -> DetectedScope:
128145
def detect(config_path: str) -> DetectedScope:
129146
cfg = Config.from_yaml(config_path)
130147
base = base_detector.detect()
131-
changed = changed_files.git_changed_files(base.ref)
132-
scopes_hit, per_scope = match_scopes(cfg, changed)
133148

134-
all_scopes = set(cfg.scopes.keys())
135-
if cfg.merge_queue_scope is not None:
136-
all_scopes.add(cfg.merge_queue_scope)
149+
scopes_hit: set[str]
150+
per_scope: dict[str, list[str]]
151+
152+
source = cfg.scopes.source
153+
if source is None:
154+
all_scopes = set()
155+
scopes_hit = set()
156+
per_scope = {}
157+
elif isinstance(source, SourceFiles):
158+
changed = changed_files.git_changed_files(base.ref)
159+
all_scopes = set(source.files.keys())
160+
scopes_hit, per_scope = match_scopes(changed, source.files)
161+
elif isinstance(source, SourceOther):
162+
msg = (
163+
"source `other` has been set, scopes must be send with `scopes-send` or API"
164+
)
165+
raise exceptions.ScopesError(msg)
166+
else:
167+
msg = "Unsupported source type" # type:ignore[unreachable]
168+
raise RuntimeError(msg)
169+
170+
if cfg.scopes.merge_queue_scope is not None:
171+
all_scopes.add(cfg.scopes.merge_queue_scope)
137172
if base.is_merge_queue:
138-
scopes_hit.add(cfg.merge_queue_scope)
173+
scopes_hit.add(cfg.scopes.merge_queue_scope)
139174

140175
click.echo(f"Base: {base.ref}")
141176
if scopes_hit:

0 commit comments

Comments
 (0)