apexcodexpy 0.5.4__tar.gz → 0.6.2__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.
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/PKG-INFO +1 -1
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/service.py +11 -6
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/typer/root.py +7 -1
- apexcodexpy-0.6.2/codex/infra/workflows/__init__.py +9 -0
- apexcodexpy-0.6.2/codex/infra/workflows/base.py +53 -0
- apexcodexpy-0.6.2/codex/infra/workflows/build.py +78 -0
- apexcodexpy-0.6.2/codex/infra/workflows/ci.py +57 -0
- apexcodexpy-0.6.2/codex/infra/workflows/dependabot.py +62 -0
- apexcodexpy-0.6.2/codex/infra/workflows/validate.py +81 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/yamler.py +1 -1
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/pyproject.toml +1 -1
- apexcodexpy-0.5.4/codex/infra/workflows.py +0 -222
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/LICENSE +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/README.md +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/__init__.py +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/__init__.py +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/program.py +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/pyproject.py +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/reporters.py +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/result.py +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/tools.py +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/typer/__init__.py +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/typer/device.py +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/infra/typer/testing.py +0 -0
- {apexcodexpy-0.5.4 → apexcodexpy-0.6.2}/codex/runner.py +0 -0
|
@@ -17,7 +17,11 @@ from codex.infra.tools import (
|
|
|
17
17
|
Ruff,
|
|
18
18
|
Version,
|
|
19
19
|
)
|
|
20
|
-
from codex.infra.workflows import
|
|
20
|
+
from codex.infra.workflows import (
|
|
21
|
+
BuildCodeWorkflow,
|
|
22
|
+
CheckCodeWorkflow,
|
|
23
|
+
DependabotWorkflow,
|
|
24
|
+
)
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
@dataclass(frozen=True)
|
|
@@ -38,8 +42,8 @@ class Codex:
|
|
|
38
42
|
def version() -> TaskResult:
|
|
39
43
|
return ProgramResult(name="version").success(message=str(Version()))
|
|
40
44
|
|
|
41
|
-
def sync(self) -> TaskResult:
|
|
42
|
-
return self.tools.sync().execute()
|
|
45
|
+
def sync(self, force: bool) -> TaskResult:
|
|
46
|
+
return self.tools.sync(force).execute()
|
|
43
47
|
|
|
44
48
|
def lock(self) -> TaskResult:
|
|
45
49
|
return self.tools.lock().execute()
|
|
@@ -126,12 +130,13 @@ class CiCodex:
|
|
|
126
130
|
class CodexTools:
|
|
127
131
|
target: Path
|
|
128
132
|
|
|
129
|
-
def sync(self) -> Executable:
|
|
133
|
+
def sync(self, force: bool) -> Executable:
|
|
130
134
|
return (
|
|
131
135
|
MultiProgram()
|
|
132
136
|
.attach(PyProjectToml().sync(self.target))
|
|
133
|
-
.attach(DependabotWorkflow().sync(self.target))
|
|
134
|
-
.attach(CheckCodeWorkflow().sync(self.target))
|
|
137
|
+
.attach(DependabotWorkflow().sync(self.target, force=force))
|
|
138
|
+
.attach(CheckCodeWorkflow().sync(self.target, force=force))
|
|
139
|
+
.attach(BuildCodeWorkflow(disclaimer=False).sync(self.target, force=force))
|
|
135
140
|
)
|
|
136
141
|
|
|
137
142
|
def lock(self) -> Executable:
|
|
@@ -27,10 +27,16 @@ def _(
|
|
|
27
27
|
"-p",
|
|
28
28
|
help="Target directory.",
|
|
29
29
|
),
|
|
30
|
+
force: bool = typer.Option(
|
|
31
|
+
False,
|
|
32
|
+
"--force",
|
|
33
|
+
"-f",
|
|
34
|
+
help="Force sync.",
|
|
35
|
+
),
|
|
30
36
|
) -> None:
|
|
31
37
|
(
|
|
32
38
|
Codex.target(Path(path))
|
|
33
|
-
.sync()
|
|
39
|
+
.sync(force=force)
|
|
34
40
|
.report(using=DefaultReporter())
|
|
35
41
|
.exit(using=typer.Exit)
|
|
36
42
|
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from datetime import UTC, datetime
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from codex.infra.program import Executable
|
|
9
|
+
from codex.infra.result import ProgramResult
|
|
10
|
+
from codex.infra.tools import Version
|
|
11
|
+
from codex.infra.yamler import Yamler
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True, kw_only=True)
|
|
15
|
+
class YamlWorkflow(ABC):
|
|
16
|
+
name: str
|
|
17
|
+
path: Path
|
|
18
|
+
|
|
19
|
+
disclaimer: bool = True
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def standards(self) -> Yamler:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
def sync(self, target: Path, force: bool = False) -> Executable:
|
|
27
|
+
path = target / self.path
|
|
28
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
29
|
+
path.touch(exist_ok=True)
|
|
30
|
+
|
|
31
|
+
standards = self.standards
|
|
32
|
+
if not force and Yamler.read(path) == standards:
|
|
33
|
+
return ProgramResult(name=self.name).no_changes()
|
|
34
|
+
|
|
35
|
+
if self.disclaimer:
|
|
36
|
+
standards = standards.comment(
|
|
37
|
+
"Auto Generated",
|
|
38
|
+
f"By: Apex Codex {Version()}",
|
|
39
|
+
f"At: {self._utcnow()}",
|
|
40
|
+
"Do not edit this file manually!\n\n",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
standards.dump_to(path)
|
|
44
|
+
|
|
45
|
+
return self.success()
|
|
46
|
+
|
|
47
|
+
def _utcnow(self) -> str:
|
|
48
|
+
return datetime.now(tz=UTC).replace(microsecond=0).isoformat(sep=" ")
|
|
49
|
+
|
|
50
|
+
def success(self) -> ProgramResult:
|
|
51
|
+
return ProgramResult(name=self.name).success(
|
|
52
|
+
message=f"{self.name} workflow succeeded.\n"
|
|
53
|
+
)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from ruamel.yaml.scalarstring import FoldedScalarString
|
|
7
|
+
|
|
8
|
+
from codex.infra.tools import Version
|
|
9
|
+
from codex.infra.yamler import Yamler
|
|
10
|
+
|
|
11
|
+
from .base import YamlWorkflow
|
|
12
|
+
from .ci import CiJob
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True, kw_only=True)
|
|
16
|
+
class BuildCodeWorkflow(YamlWorkflow):
|
|
17
|
+
name: str = "BuildCode"
|
|
18
|
+
path: Path = Path(".github") / "workflows" / "build_code.yml"
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def standards(self) -> Yamler:
|
|
22
|
+
workflow = Yamler.read(self.path).as_mapping()
|
|
23
|
+
workflow["name"] = "Build Python Application"
|
|
24
|
+
workflow["on"] = {"push": {"branches": ["main"]}}
|
|
25
|
+
workflow["permissions"] = "write-all"
|
|
26
|
+
workflow["jobs"] = workflow.get("jobs", {})
|
|
27
|
+
workflow["jobs"]["build"] = (
|
|
28
|
+
CiJob(name="build")
|
|
29
|
+
.with_step(
|
|
30
|
+
Yamler.parse(
|
|
31
|
+
{
|
|
32
|
+
"name": "Checkout Code",
|
|
33
|
+
"uses": "actions/checkout@v7",
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
.with_step(
|
|
38
|
+
Yamler.parse(
|
|
39
|
+
{
|
|
40
|
+
"name": "Setup Python",
|
|
41
|
+
"uses": "actions/setup-python@v6",
|
|
42
|
+
"with": {
|
|
43
|
+
"python-version": Version.of_python(),
|
|
44
|
+
"pip-install": "apexcodexpy",
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
.run(
|
|
50
|
+
step="Build Docker image",
|
|
51
|
+
command=FoldedScalarString(
|
|
52
|
+
"\n".join(
|
|
53
|
+
[
|
|
54
|
+
"codex build",
|
|
55
|
+
" --tag ${{ github.event.repository.name }}:latest",
|
|
56
|
+
]
|
|
57
|
+
)
|
|
58
|
+
),
|
|
59
|
+
)
|
|
60
|
+
.run(
|
|
61
|
+
step="Push Docker image",
|
|
62
|
+
command=FoldedScalarString(
|
|
63
|
+
"\n".join(
|
|
64
|
+
[
|
|
65
|
+
"codex push",
|
|
66
|
+
" --tag ${{ github.event.repository.name }}:latest",
|
|
67
|
+
" --token ${{ secrets.GITHUB_TOKEN }}",
|
|
68
|
+
" --actor ${{ github.actor }}",
|
|
69
|
+
" --organization ${{ github.repository_owner }}",
|
|
70
|
+
]
|
|
71
|
+
)
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
.yamlify()
|
|
75
|
+
.as_mapping()
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
return Yamler.parse(workflow)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import MutableMapping, MutableSequence
|
|
4
|
+
from dataclasses import dataclass, field, replace
|
|
5
|
+
|
|
6
|
+
from codex.infra.yamler import Yamler
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class CiWorkflow:
|
|
11
|
+
name: str
|
|
12
|
+
|
|
13
|
+
jobs: MutableMapping[str, Yamler] = field(default_factory=dict)
|
|
14
|
+
|
|
15
|
+
def with_job(self, value: CiJob) -> CiWorkflow:
|
|
16
|
+
if value.is_enabled:
|
|
17
|
+
self.jobs[value.name] = value.yamlify()
|
|
18
|
+
|
|
19
|
+
return self
|
|
20
|
+
|
|
21
|
+
def yamlify(self) -> Yamler:
|
|
22
|
+
return Yamler.parse(
|
|
23
|
+
{
|
|
24
|
+
"name": self.name,
|
|
25
|
+
"on": {"pull_request": {"branches": ["main"]}},
|
|
26
|
+
"permissions": {"contents": "read"},
|
|
27
|
+
"jobs": {name: job.as_mapping() for name, job in self.jobs.items()},
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
class CiJob:
|
|
34
|
+
name: str
|
|
35
|
+
|
|
36
|
+
is_enabled: bool = True
|
|
37
|
+
platform: str = "ubuntu-latest"
|
|
38
|
+
steps: MutableSequence[Yamler] = field(default_factory=list)
|
|
39
|
+
|
|
40
|
+
def with_step(self, step: Yamler) -> CiJob:
|
|
41
|
+
self.steps.append(step)
|
|
42
|
+
|
|
43
|
+
return self
|
|
44
|
+
|
|
45
|
+
def run(self, step: str, command: str) -> CiJob:
|
|
46
|
+
return self.with_step(Yamler.parse({"name": step, "run": command}))
|
|
47
|
+
|
|
48
|
+
def enabled(self, when: bool) -> CiJob:
|
|
49
|
+
return replace(self, is_enabled=when)
|
|
50
|
+
|
|
51
|
+
def yamlify(self) -> Yamler:
|
|
52
|
+
return Yamler.parse(
|
|
53
|
+
{
|
|
54
|
+
"runs-on": self.platform,
|
|
55
|
+
"steps": [step.as_mapping() for step in self.steps],
|
|
56
|
+
}
|
|
57
|
+
)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from codex.infra.yamler import Yamler
|
|
7
|
+
|
|
8
|
+
from .base import YamlWorkflow
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True, kw_only=True)
|
|
12
|
+
class DependabotWorkflow(YamlWorkflow):
|
|
13
|
+
name: str = "Dependabot"
|
|
14
|
+
path: Path = Path(".github") / "dependabot.yml"
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def standards(self) -> Yamler:
|
|
18
|
+
return Yamler.parse(
|
|
19
|
+
{
|
|
20
|
+
"version": 2,
|
|
21
|
+
"updates": [
|
|
22
|
+
self._pip_config().as_mapping(),
|
|
23
|
+
self._gh_actions_config().as_mapping(),
|
|
24
|
+
],
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
@staticmethod
|
|
29
|
+
def _pip_config() -> Yamler:
|
|
30
|
+
return Yamler.parse(
|
|
31
|
+
{
|
|
32
|
+
"package-ecosystem": "pip",
|
|
33
|
+
"directory": "/",
|
|
34
|
+
"schedule": {
|
|
35
|
+
"interval": "weekly",
|
|
36
|
+
"day": "thursday",
|
|
37
|
+
},
|
|
38
|
+
"groups": {
|
|
39
|
+
"python": {
|
|
40
|
+
"patterns": ["*"],
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def _gh_actions_config() -> Yamler:
|
|
48
|
+
return Yamler.parse(
|
|
49
|
+
{
|
|
50
|
+
"package-ecosystem": "github-actions",
|
|
51
|
+
"directory": "/",
|
|
52
|
+
"schedule": {
|
|
53
|
+
"interval": "weekly",
|
|
54
|
+
"day": "thursday",
|
|
55
|
+
},
|
|
56
|
+
"groups": {
|
|
57
|
+
"gh-actions": {
|
|
58
|
+
"patterns": ["*"],
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from codex.infra.tools import Version
|
|
7
|
+
from codex.infra.yamler import Yamler
|
|
8
|
+
|
|
9
|
+
from .base import YamlWorkflow
|
|
10
|
+
from .ci import CiJob, CiWorkflow
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True, kw_only=True)
|
|
14
|
+
class CheckCodeWorkflow(YamlWorkflow):
|
|
15
|
+
name: str = "CheckCode"
|
|
16
|
+
path: Path = Path(".github") / "workflows" / "check_code.yml"
|
|
17
|
+
|
|
18
|
+
CHECKOUT = Yamler.parse(
|
|
19
|
+
{
|
|
20
|
+
"name": "Checkout Code",
|
|
21
|
+
"uses": "actions/checkout@v7",
|
|
22
|
+
}
|
|
23
|
+
).anchor("checkout")
|
|
24
|
+
|
|
25
|
+
SETUP = Yamler.parse(
|
|
26
|
+
{
|
|
27
|
+
"name": "Setup Python",
|
|
28
|
+
"uses": "actions/setup-python@v6",
|
|
29
|
+
"with": {
|
|
30
|
+
"python-version": Version.of_python(),
|
|
31
|
+
"pip-install": f"apexcodexpy=={Version()}",
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
).anchor("setup")
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def standards(self) -> Yamler:
|
|
38
|
+
return (
|
|
39
|
+
CiWorkflow(name="Validate Python Code")
|
|
40
|
+
.with_job(
|
|
41
|
+
CiJob(name="lint")
|
|
42
|
+
.with_step(self.CHECKOUT)
|
|
43
|
+
.with_step(self.SETUP)
|
|
44
|
+
.run(
|
|
45
|
+
step="Lint Code",
|
|
46
|
+
command="codex lint --ci",
|
|
47
|
+
)
|
|
48
|
+
.enabled(True)
|
|
49
|
+
)
|
|
50
|
+
.with_job(
|
|
51
|
+
CiJob(name="test-unit")
|
|
52
|
+
.with_step(self.CHECKOUT)
|
|
53
|
+
.with_step(self.SETUP)
|
|
54
|
+
.run(
|
|
55
|
+
step="Run unit tests",
|
|
56
|
+
command="codex test unit --ci",
|
|
57
|
+
)
|
|
58
|
+
.enabled(True)
|
|
59
|
+
)
|
|
60
|
+
.with_job(
|
|
61
|
+
CiJob(name="test-integration")
|
|
62
|
+
.with_step(self.CHECKOUT)
|
|
63
|
+
.with_step(self.SETUP)
|
|
64
|
+
.run(
|
|
65
|
+
step="Run integration tests",
|
|
66
|
+
command="codex test integration --ci",
|
|
67
|
+
)
|
|
68
|
+
.enabled(when=Version().is_installed("pytest-docker"))
|
|
69
|
+
)
|
|
70
|
+
.with_job(
|
|
71
|
+
CiJob(name="test-behaviour")
|
|
72
|
+
.with_step(self.CHECKOUT)
|
|
73
|
+
.with_step(self.SETUP)
|
|
74
|
+
.run(
|
|
75
|
+
step="Run behaviour tests",
|
|
76
|
+
command="codex test behaviour --ci",
|
|
77
|
+
)
|
|
78
|
+
.enabled(when=Version().is_installed("behave"))
|
|
79
|
+
)
|
|
80
|
+
.yamlify()
|
|
81
|
+
)
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from abc import ABC, abstractmethod
|
|
4
|
-
from collections.abc import MutableMapping, MutableSequence
|
|
5
|
-
from dataclasses import dataclass, field, replace
|
|
6
|
-
from datetime import UTC, datetime
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
from codex.infra.program import Executable
|
|
10
|
-
from codex.infra.result import ProgramResult
|
|
11
|
-
from codex.infra.tools import Version
|
|
12
|
-
from codex.infra.yamler import Yamler
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@dataclass(frozen=True, kw_only=True)
|
|
16
|
-
class YamlWorkflow(ABC):
|
|
17
|
-
name: str
|
|
18
|
-
path: Path
|
|
19
|
-
|
|
20
|
-
@property
|
|
21
|
-
@abstractmethod
|
|
22
|
-
def standards(self) -> Yamler:
|
|
23
|
-
pass
|
|
24
|
-
|
|
25
|
-
def sync(self, target: Path) -> Executable:
|
|
26
|
-
path = target / self.path
|
|
27
|
-
path.parent.mkdir(parents=True, exist_ok=True)
|
|
28
|
-
path.touch(exist_ok=True)
|
|
29
|
-
|
|
30
|
-
if Yamler.read(path) == self.standards:
|
|
31
|
-
return ProgramResult(name=self.name).no_changes()
|
|
32
|
-
|
|
33
|
-
self.standards.comment(
|
|
34
|
-
"Auto Generated",
|
|
35
|
-
f"By: Apex Codex {Version()}",
|
|
36
|
-
f"At: {self._utcnow()}",
|
|
37
|
-
"Do not edit this file manually!\n\n",
|
|
38
|
-
).dump_to(path)
|
|
39
|
-
|
|
40
|
-
return self.success()
|
|
41
|
-
|
|
42
|
-
def _utcnow(self) -> str:
|
|
43
|
-
return datetime.now(tz=UTC).replace(microsecond=0).isoformat(sep=" ")
|
|
44
|
-
|
|
45
|
-
def success(self) -> ProgramResult:
|
|
46
|
-
return ProgramResult(name=self.name).success(
|
|
47
|
-
message=f"{self.name} workflow succeeded.\n"
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@dataclass(frozen=True, kw_only=True)
|
|
52
|
-
class DependabotWorkflow(YamlWorkflow):
|
|
53
|
-
name: str = "Dependabot"
|
|
54
|
-
path: Path = Path(".github") / "dependabot.yml"
|
|
55
|
-
|
|
56
|
-
@property
|
|
57
|
-
def standards(self) -> Yamler:
|
|
58
|
-
return Yamler.parse(
|
|
59
|
-
{
|
|
60
|
-
"version": 2,
|
|
61
|
-
"updates": [
|
|
62
|
-
self._pip_config().as_mapping(),
|
|
63
|
-
self._gh_actions_config().as_mapping(),
|
|
64
|
-
],
|
|
65
|
-
}
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
@staticmethod
|
|
69
|
-
def _pip_config() -> Yamler:
|
|
70
|
-
return Yamler.parse(
|
|
71
|
-
{
|
|
72
|
-
"package-ecosystem": "pip",
|
|
73
|
-
"directory": "/",
|
|
74
|
-
"schedule": {
|
|
75
|
-
"interval": "weekly",
|
|
76
|
-
"day": "thursday",
|
|
77
|
-
},
|
|
78
|
-
"groups": {
|
|
79
|
-
"python": {
|
|
80
|
-
"patterns": ["*"],
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
}
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
@staticmethod
|
|
87
|
-
def _gh_actions_config() -> Yamler:
|
|
88
|
-
return Yamler.parse(
|
|
89
|
-
{
|
|
90
|
-
"package-ecosystem": "github-actions",
|
|
91
|
-
"directory": "/",
|
|
92
|
-
"schedule": {
|
|
93
|
-
"interval": "weekly",
|
|
94
|
-
"day": "thursday",
|
|
95
|
-
},
|
|
96
|
-
"groups": {
|
|
97
|
-
"gh-actions": {
|
|
98
|
-
"patterns": ["*"],
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
}
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
@dataclass(frozen=True, kw_only=True)
|
|
106
|
-
class CheckCodeWorkflow(YamlWorkflow):
|
|
107
|
-
name: str = "CheckCode"
|
|
108
|
-
path: Path = Path(".github") / "workflows" / "check_code.yml"
|
|
109
|
-
|
|
110
|
-
@property
|
|
111
|
-
def standards(self) -> Yamler:
|
|
112
|
-
return (
|
|
113
|
-
CiWorkflow(name="Validate Python Code")
|
|
114
|
-
.with_job(
|
|
115
|
-
CodeCheckJob(name="lint")
|
|
116
|
-
.run(
|
|
117
|
-
step="Lint Code",
|
|
118
|
-
command="codex lint --ci",
|
|
119
|
-
)
|
|
120
|
-
.enabled(True)
|
|
121
|
-
)
|
|
122
|
-
.with_job(
|
|
123
|
-
CodeCheckJob(name="test-unit")
|
|
124
|
-
.run(
|
|
125
|
-
step="Run unit tests",
|
|
126
|
-
command="codex test unit --ci",
|
|
127
|
-
)
|
|
128
|
-
.enabled(True)
|
|
129
|
-
)
|
|
130
|
-
.with_job(
|
|
131
|
-
CodeCheckJob(name="test-integration")
|
|
132
|
-
.run(
|
|
133
|
-
step="Run integration tests",
|
|
134
|
-
command="codex test integration --ci",
|
|
135
|
-
)
|
|
136
|
-
.enabled(when=Version().is_installed("pytest-docker"))
|
|
137
|
-
)
|
|
138
|
-
.with_job(
|
|
139
|
-
CodeCheckJob(name="test-behaviour")
|
|
140
|
-
.run(
|
|
141
|
-
step="Run behaviour tests",
|
|
142
|
-
command="codex test behaviour --ci",
|
|
143
|
-
)
|
|
144
|
-
.enabled(when=Version().is_installed("behave"))
|
|
145
|
-
)
|
|
146
|
-
.yamlify()
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
@dataclass(frozen=True)
|
|
151
|
-
class CiWorkflow:
|
|
152
|
-
name: str
|
|
153
|
-
|
|
154
|
-
jobs: MutableMapping[str, Yamler] = field(default_factory=dict)
|
|
155
|
-
|
|
156
|
-
def with_job(self, value: CiJob) -> CiWorkflow:
|
|
157
|
-
if value.is_enabled:
|
|
158
|
-
self.jobs[value.name] = value.yamlify()
|
|
159
|
-
|
|
160
|
-
return self
|
|
161
|
-
|
|
162
|
-
def yamlify(self) -> Yamler:
|
|
163
|
-
return Yamler.parse(
|
|
164
|
-
{
|
|
165
|
-
"name": self.name,
|
|
166
|
-
"on": {"pull_request": {"branches": ["main"]}},
|
|
167
|
-
"permissions": {"contents": "read"},
|
|
168
|
-
"jobs": {name: job.as_mapping() for name, job in self.jobs.items()},
|
|
169
|
-
}
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
@dataclass(frozen=True)
|
|
174
|
-
class CiJob:
|
|
175
|
-
name: str
|
|
176
|
-
|
|
177
|
-
is_enabled: bool = True
|
|
178
|
-
platform: str = "ubuntu-latest"
|
|
179
|
-
steps: MutableSequence[Yamler] = field(default_factory=list)
|
|
180
|
-
|
|
181
|
-
def with_step(self, step: Yamler) -> CiJob:
|
|
182
|
-
self.steps.append(step)
|
|
183
|
-
|
|
184
|
-
return self
|
|
185
|
-
|
|
186
|
-
def enabled(self, when: bool) -> CiJob:
|
|
187
|
-
return replace(self, is_enabled=when)
|
|
188
|
-
|
|
189
|
-
def yamlify(self) -> Yamler:
|
|
190
|
-
return Yamler.parse(
|
|
191
|
-
{
|
|
192
|
-
"runs-on": self.platform,
|
|
193
|
-
"steps": [step.as_mapping() for step in self.steps],
|
|
194
|
-
}
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
CHECKOUT = Yamler.parse(
|
|
199
|
-
{
|
|
200
|
-
"name": "Checkout Code",
|
|
201
|
-
"uses": "actions/checkout@v7",
|
|
202
|
-
}
|
|
203
|
-
).anchor("checkout")
|
|
204
|
-
|
|
205
|
-
SETUP = Yamler.parse(
|
|
206
|
-
{
|
|
207
|
-
"name": "Setup Python",
|
|
208
|
-
"uses": "actions/setup-python@v6",
|
|
209
|
-
"with": {
|
|
210
|
-
"python-version": Version.of_python(),
|
|
211
|
-
"pip-install": f"apexcodexpy=={Version()}",
|
|
212
|
-
},
|
|
213
|
-
}
|
|
214
|
-
).anchor("setup")
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
@dataclass(frozen=True)
|
|
218
|
-
class CodeCheckJob(CiJob):
|
|
219
|
-
steps: MutableSequence[Yamler] = field(default_factory=lambda: [CHECKOUT, SETUP])
|
|
220
|
-
|
|
221
|
-
def run(self, step: str, command: str) -> CiJob:
|
|
222
|
-
return self.with_step(Yamler.parse({"name": step, "run": command}))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|