action-platform 0.1.1__py3-none-any.whl

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.
Files changed (45) hide show
  1. action_platform/__init__.py +10 -0
  2. action_platform/abc/__init__.py +7 -0
  3. action_platform/abc/ci_runner.py +25 -0
  4. action_platform/abc/deploy_target.py +46 -0
  5. action_platform/abc/source_host.py +51 -0
  6. action_platform/cli/__init__.py +1 -0
  7. action_platform/cli/commands/__init__.py +1 -0
  8. action_platform/cli/commands/cloud.py +52 -0
  9. action_platform/cli/commands/deploy.py +90 -0
  10. action_platform/cli/commands/init.py +136 -0
  11. action_platform/cli/commands/mcp.py +26 -0
  12. action_platform/cli/commands/release.py +22 -0
  13. action_platform/cli/commands/service.py +50 -0
  14. action_platform/cli/setup.py +27 -0
  15. action_platform/core/__init__.py +1 -0
  16. action_platform/core/action_platform.py +63 -0
  17. action_platform/core/changelog.py +73 -0
  18. action_platform/core/config.py +109 -0
  19. action_platform/core/context.py +65 -0
  20. action_platform/core/exception.py +25 -0
  21. action_platform/core/generate.py +217 -0
  22. action_platform/core/git.py +91 -0
  23. action_platform/core/module.py +21 -0
  24. action_platform/core/pipeline.py +150 -0
  25. action_platform/core/templates.py +261 -0
  26. action_platform/core/versioning.py +43 -0
  27. action_platform/logging.py +14 -0
  28. action_platform/main.py +27 -0
  29. action_platform/mcp/__init__.py +11 -0
  30. action_platform/mcp/__main__.py +4 -0
  31. action_platform/mcp/annotations.py +33 -0
  32. action_platform/mcp/server.py +63 -0
  33. action_platform/mcp/tools/__init__.py +3 -0
  34. action_platform/mcp/tools/lifecycle.py +111 -0
  35. action_platform/mcp/tools/matrix.py +49 -0
  36. action_platform/mcp/tools/project.py +109 -0
  37. action_platform/providers/__init__.py +5 -0
  38. action_platform/providers/source_github.py +110 -0
  39. action_platform/settings.py +27 -0
  40. action_platform/testing/__init__.py +1 -0
  41. action_platform-0.1.1.dist-info/METADATA +390 -0
  42. action_platform-0.1.1.dist-info/RECORD +45 -0
  43. action_platform-0.1.1.dist-info/WHEEL +4 -0
  44. action_platform-0.1.1.dist-info/entry_points.txt +4 -0
  45. action_platform-0.1.1.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,10 @@
1
+ """Action Platform __init__ module."""
2
+
3
+ __version__ = "0.1.0"
4
+ __description__ = "🛠️ Action Platform padroniza init, release e deploy."
5
+
6
+ from .core.config import Config
7
+ from .core.context import Context
8
+ from .core.action_platform import ActionPlatform
9
+
10
+ __all__ = ["Config", "Context", "ActionPlatform"]
@@ -0,0 +1,7 @@
1
+ """Action Platform abstract base classes."""
2
+
3
+ from .ci_runner import CIRunner
4
+ from .deploy_target import DeployTarget
5
+ from .source_host import SourceHost
6
+
7
+ __all__ = ["CIRunner", "DeployTarget", "SourceHost"]
@@ -0,0 +1,25 @@
1
+ """CIRunner ABC."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import TYPE_CHECKING, Iterator
5
+
6
+ if TYPE_CHECKING:
7
+ from action_platform.core.context import Context, RunRef, RunResult
8
+
9
+
10
+ class CIRunner(ABC):
11
+ """CIRunner"""
12
+
13
+ name: str
14
+
15
+ @abstractmethod
16
+ def trigger(self, ctx: "Context", job: str, params: dict) -> "RunRef":
17
+ """Enqueue pipeline run."""
18
+
19
+ @abstractmethod
20
+ def wait(self, ctx: "Context", run: "RunRef", timeout: int = 1800) -> "RunResult":
21
+ """Block until pipeline finishes or timeout."""
22
+
23
+ @abstractmethod
24
+ def logs(self, ctx: "Context", run: "RunRef") -> Iterator[str]:
25
+ """Stream pipeline logs."""
@@ -0,0 +1,46 @@
1
+ """DeployTarget ABC — the lifecycle every deploy target answers to.
2
+
3
+ Vocabulary mirrors what a deployment scope needs over its life: provision the
4
+ target once, ship versions, move traffic, undo, inspect, tear down. A target
5
+ that cannot do one of them raises NotImplementedError and the CLI says so.
6
+ """
7
+
8
+ from abc import ABC, abstractmethod
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from action_platform.core.context import Context, DeployResult, Diagnosis
13
+
14
+
15
+ class DeployTarget(ABC):
16
+ """DeployTarget"""
17
+
18
+ name: str
19
+
20
+ @abstractmethod
21
+ def preflight(self, ctx: "Context") -> None:
22
+ """Validate credentials, tooling, artifacts. Raise DeployError otherwise."""
23
+
24
+ def create(self, ctx: "Context") -> None:
25
+ """Provision the target itself (stack, app, registry). Idempotent."""
26
+ raise NotImplementedError(f"{self.name} cannot create")
27
+
28
+ @abstractmethod
29
+ def deploy(self, ctx: "Context") -> "DeployResult":
30
+ """Ship the current version."""
31
+
32
+ def switch_traffic(self, ctx: "Context", weight: int) -> None:
33
+ """Move `weight` percent of traffic to the newest version (blue-green)."""
34
+ raise NotImplementedError(f"{self.name} cannot switch traffic")
35
+
36
+ def rollback(self, ctx: "Context", to_version: str | None = None) -> None:
37
+ """Revert to `to_version` or the previous one."""
38
+ raise NotImplementedError(f"{self.name} cannot rollback")
39
+
40
+ def diagnose(self, ctx: "Context") -> "Diagnosis":
41
+ """Health, last deploy, logs pointer."""
42
+ raise NotImplementedError(f"{self.name} cannot diagnose")
43
+
44
+ def delete(self, ctx: "Context") -> None:
45
+ """Tear the target down."""
46
+ raise NotImplementedError(f"{self.name} cannot delete")
@@ -0,0 +1,51 @@
1
+ """SourceHost ABC."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from pathlib import Path
5
+ from typing import TYPE_CHECKING
6
+
7
+ if TYPE_CHECKING:
8
+ from action_platform.core.context import Context, PRRef, ReleaseRef
9
+
10
+
11
+ class SourceHost(ABC):
12
+ """SourceHost"""
13
+
14
+ name: str
15
+
16
+ @abstractmethod
17
+ def detect(self, remote_url: str) -> bool:
18
+ """Return True if this provider handles remote_url."""
19
+
20
+ def create_repository(
21
+ self, repo: str, description: str = "", private: bool = False
22
+ ) -> str:
23
+ """Create the remote repository; return its clone URL."""
24
+ raise NotImplementedError(f"{self.name} cannot create repositories")
25
+
26
+ @abstractmethod
27
+ def create_tag(self, ctx: "Context", tag: str) -> None:
28
+ """Create annotated tag on remote."""
29
+
30
+ @abstractmethod
31
+ def create_release(
32
+ self,
33
+ ctx: "Context",
34
+ tag: str,
35
+ notes: str,
36
+ assets: list[Path] | None = None,
37
+ draft: bool = False,
38
+ prerelease: bool = False,
39
+ ) -> "ReleaseRef":
40
+ """Publish release on remote host."""
41
+
42
+ @abstractmethod
43
+ def open_pr(
44
+ self,
45
+ ctx: "Context",
46
+ base: str,
47
+ head: str,
48
+ title: str,
49
+ body: str,
50
+ ) -> "PRRef":
51
+ """Open pull/merge request."""
@@ -0,0 +1 @@
1
+ """Action Platform CLI package."""
@@ -0,0 +1 @@
1
+ """Action Platform CLI commands."""
@@ -0,0 +1,52 @@
1
+ """`action-platform cloud` commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import typer
8
+ from rich.console import Console
9
+
10
+ from action_platform.core.generate import apply_cloud, read_platform
11
+ from action_platform.core.templates import load_matrix
12
+ from action_platform.logging import logger
13
+
14
+ app = typer.Typer(
15
+ help="Apply deploy overlays to an existing project.", no_args_is_help=True
16
+ )
17
+ console = Console()
18
+
19
+
20
+ @app.command("set")
21
+ def set_(
22
+ name: str = typer.Argument(..., help="aws/lambda, docker, ..."),
23
+ project: Path = typer.Option(
24
+ None, "--project", "-p", help="Project directory (default: cwd)"
25
+ ),
26
+ update: bool = typer.Option(False, "--update", help="Refresh the templates cache"),
27
+ ) -> None:
28
+ """Apply a cloud overlay and set [deploy] target in platform.toml (replaces the previous one)."""
29
+ repo, matrix = load_matrix(update=update)
30
+ target = (project or Path.cwd()).resolve()
31
+
32
+ apply_cloud(repo, matrix.cloud(name), target)
33
+
34
+ logger.info("applied cloud %s to %s", name, target)
35
+
36
+
37
+ @app.command("list")
38
+ def list_(
39
+ project: Path = typer.Option(
40
+ None, "--project", "-p", help="Filter by what this project supports"
41
+ ),
42
+ ) -> None:
43
+ """List cloud overlays, optionally only those compatible with a project."""
44
+ _, matrix = load_matrix()
45
+ clouds = matrix.clouds
46
+
47
+ if project is not None:
48
+ meta = read_platform(project.resolve())
49
+ clouds = matrix.clouds_for(meta.get("type", ""), meta.get("language", ""))
50
+
51
+ for cloud in clouds:
52
+ console.print(f"[bold]{cloud.name}[/bold] {cloud.description}")
@@ -0,0 +1,90 @@
1
+ """`action-platform deploy | rollback | diagnose | destroy` commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import typer
8
+ from rich.console import Console
9
+
10
+ from action_platform.core.action_platform import ActionPlatform
11
+ from action_platform.core.config import Config
12
+ from action_platform.core.exception import DeployError
13
+ from action_platform.logging import logger
14
+ from action_platform.settings import settings
15
+
16
+ console = Console()
17
+
18
+ TARGET = typer.Option(
19
+ None, "--target", help="Filter by target name (aws/lambda, docker, ...)"
20
+ )
21
+ STAGE = typer.Option(
22
+ None, "--stage", help="dev | prod (default: prod on main/master, else dev)"
23
+ )
24
+
25
+
26
+ def _tool() -> ActionPlatform:
27
+ return ActionPlatform(config=Config.from_toml(Path.cwd() / settings.CONFIG_FILE))
28
+
29
+
30
+ def run(
31
+ target: str | None = TARGET,
32
+ stage: str | None = STAGE,
33
+ dry_run: bool = typer.Option(False, "--dry-run"),
34
+ ) -> None:
35
+ """Ship the current version to the [deploy] target in platform.toml."""
36
+ for r in _tool().deploy(target=target, dry_run=dry_run, stage=stage):
37
+ logger.info(
38
+ "deploy %s ok=%s version=%s url=%s", r.target, r.ok, r.version, r.url
39
+ )
40
+
41
+ if not r.ok:
42
+ raise DeployError(r.error or f"{r.target} failed")
43
+
44
+
45
+ def rollback(
46
+ to_version: str | None = typer.Argument(
47
+ None, help="Version to return to (default: previous)"
48
+ ),
49
+ target: str | None = TARGET,
50
+ stage: str | None = STAGE,
51
+ ) -> None:
52
+ """Return the target to a previous version."""
53
+ try:
54
+ _tool().rollback(target=target, to_version=to_version, stage=stage)
55
+ except NotImplementedError as e:
56
+ raise DeployError(str(e)) from e
57
+ logger.info("rollback done")
58
+
59
+
60
+ def diagnose(target: str | None = TARGET, stage: str | None = STAGE) -> None:
61
+ """Health, status and URL of the deployed target."""
62
+ try:
63
+ results = _tool().diagnose(target=target, stage=stage)
64
+ except NotImplementedError as e:
65
+ raise DeployError(str(e)) from e
66
+ for d in results:
67
+ mark = "[green]ok[/green]" if d.ok else "[red]not ok[/red]"
68
+ console.print(f"[bold]{d.target}[/bold] {mark} {d.status}")
69
+
70
+ if d.url:
71
+ console.print(f" url: {d.url}")
72
+
73
+ for k, v in d.details.items():
74
+ console.print(f" {k}: {v}")
75
+
76
+
77
+ def destroy(
78
+ target: str | None = TARGET,
79
+ stage: str | None = STAGE,
80
+ yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation"),
81
+ ) -> None:
82
+ """Tear the target down. Irreversible."""
83
+ if not yes and not typer.confirm("Delete the deployed target?"):
84
+ raise typer.Abort()
85
+
86
+ try:
87
+ _tool().destroy(target=target, stage=stage)
88
+ except NotImplementedError as e:
89
+ raise DeployError(str(e)) from e
90
+ logger.info("destroy done")
@@ -0,0 +1,136 @@
1
+ """`action-platform init` command."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import typer
8
+ from rich.console import Console
9
+ from rich.table import Table
10
+
11
+ from action_platform.core.exception import TemplateError
12
+ from action_platform.core.generate import apply_cloud, generate_project, push_project
13
+ from action_platform.core.templates import Matrix, load_matrix
14
+ from action_platform.logging import logger
15
+
16
+ CI_PROVIDERS = ["github", "gitlab", "jenkins"]
17
+
18
+ console = Console()
19
+
20
+
21
+ def run(
22
+ type_: str | None = typer.Argument(
23
+ None, metavar="TYPE", help="web, library, mcp, ..."
24
+ ),
25
+ stack: str | None = typer.Argument(None, help="python, go, node, ..."),
26
+ template: str | None = typer.Argument(
27
+ None, help="fastapi, gin, ... (default per stack)"
28
+ ),
29
+ name: str | None = typer.Option(None, "--name", "-n", help="Project name"),
30
+ ci: str | None = typer.Option(
31
+ None, "--ci", help="CI provider: " + ", ".join(CI_PROVIDERS)
32
+ ),
33
+ cloud: str | None = typer.Option(
34
+ None, "--cloud", help="Deploy overlay: aws/lambda, docker, ..."
35
+ ),
36
+ output: Path | None = typer.Option(
37
+ None, "--output", "-o", help="Where to create the project"
38
+ ),
39
+ push: bool = typer.Option(
40
+ True,
41
+ "--push/--no-push",
42
+ help="Create the remote repo via [source_host] and push (default: on)",
43
+ ),
44
+ private: bool = typer.Option(False, "--private", help="With --push: private repo"),
45
+ list_: bool = typer.Option(False, "--list", "-l", help="Show the template matrix"),
46
+ update: bool = typer.Option(False, "--update", help="Refresh the templates cache"),
47
+ ) -> None:
48
+ """Bootstrap a project from the templates matrix."""
49
+ repo, matrix = load_matrix(update=update)
50
+
51
+ if list_:
52
+ print_matrix(matrix)
53
+ return
54
+
55
+ if type_ is None:
56
+ type_ = choose("type", matrix.types())
57
+ if stack is None and matrix.stacks(type_):
58
+ stack = choose("stack", matrix.stacks(type_))
59
+ if template is None and stack is not None:
60
+ leaves = matrix.templates(type_, stack)
61
+ if len(leaves) > 1:
62
+ template = choose("template", [leaf.template for leaf in leaves])
63
+
64
+ leaf = matrix.resolve(type_, stack, template)
65
+
66
+ if name is None:
67
+ name = typer.prompt("project name")
68
+ if ci is None and leaf.type != "empty":
69
+ ci = choose("ci", CI_PROVIDERS)
70
+ if ci is not None and ci not in CI_PROVIDERS:
71
+ raise TemplateError(f"unknown ci: {ci} (available: {', '.join(CI_PROVIDERS)})")
72
+
73
+ project = generate_project(
74
+ repo, leaf, name=name, ci=ci, output=output or Path.cwd()
75
+ )
76
+ logger.info("created %s", project)
77
+
78
+ if cloud is not None:
79
+ apply_cloud(repo, matrix.cloud(cloud), project)
80
+ logger.info("applied cloud %s", cloud)
81
+
82
+ if push:
83
+ url = push_project(project, private=private)
84
+ logger.info("pushed to %s", url)
85
+
86
+
87
+ def choose(label: str, options: list[str]) -> str:
88
+ console.print(f"[bold]{label}[/bold]")
89
+ for i, opt in enumerate(options, 1):
90
+ console.print(f" {i}. {opt}")
91
+ while True:
92
+ raw = typer.prompt(f"{label} [1-{len(options)}]")
93
+ if raw in options:
94
+ return raw
95
+ if raw.isdigit() and 1 <= int(raw) <= len(options):
96
+ return options[int(raw) - 1]
97
+ console.print("[red]invalid choice[/red]")
98
+
99
+
100
+ def print_matrix(matrix: Matrix) -> None:
101
+ table = Table(title="Projects")
102
+ table.add_column("type")
103
+ table.add_column("stack")
104
+ table.add_column("template")
105
+ table.add_column("description")
106
+ for leaf in matrix.leaves:
107
+ tpl = f"{leaf.template} *" if leaf.default else leaf.template
108
+ table.add_row(leaf.type, leaf.stack, tpl, leaf.description)
109
+ console.print(table)
110
+ console.print("[dim]* default template for the stack[/dim]\n")
111
+
112
+ clouds = Table(title="Clouds")
113
+ clouds.add_column("cloud")
114
+ clouds.add_column("types")
115
+ clouds.add_column("languages")
116
+ clouds.add_column("description")
117
+ for cloud in matrix.clouds:
118
+ clouds.add_row(
119
+ cloud.name,
120
+ ", ".join(cloud.types) or "any",
121
+ ", ".join(cloud.languages) or "any",
122
+ cloud.description,
123
+ )
124
+ console.print(clouds)
125
+
126
+ services = Table(title="Services")
127
+ services.add_column("service")
128
+ services.add_column("providers")
129
+ services.add_column("description")
130
+
131
+ for service in matrix.services:
132
+ services.add_row(
133
+ service.name, ", ".join(service.providers), service.description
134
+ )
135
+
136
+ console.print(services)
@@ -0,0 +1,26 @@
1
+ """`action-platform mcp` command."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+
7
+ from action_platform.core.exception import ActionPlatformError
8
+
9
+
10
+ def run(
11
+ http: bool = typer.Option(
12
+ False, "--http", help="Serve over streamable HTTP instead of stdio"
13
+ ),
14
+ host: str = typer.Option("127.0.0.1", "--host"),
15
+ port: int = typer.Option(8765, "--port", help="Port for --http"),
16
+ ) -> None:
17
+ """Run the embedded MCP server so AI agents can scaffold, deploy and operate projects."""
18
+ try:
19
+ from action_platform.mcp.server import main
20
+ except ModuleNotFoundError as e:
21
+ raise ActionPlatformError(
22
+ "MCP support is not installed: pip install 'action-platform[mcp]'"
23
+ ) from e
24
+
25
+ argv = ["--http", "--host", host, "--port", str(port)] if http else []
26
+ main(argv)
@@ -0,0 +1,22 @@
1
+ """`action-platform release` command."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import typer
8
+
9
+ from action_platform.core.config import Config
10
+ from action_platform.core.action_platform import ActionPlatform
11
+ from action_platform.logging import logger
12
+
13
+
14
+ def run(
15
+ level: str = typer.Argument("patch", help="patch | minor | major | X.Y.Z"),
16
+ dry_run: bool = typer.Option(False, "--dry-run"),
17
+ ) -> None:
18
+ """Bump version, generate changelog, tag, and publish release."""
19
+ config = Config.from_toml(Path.cwd() / "platform.toml")
20
+ tool = ActionPlatform(config=config)
21
+ ctx = tool.release(level=level, dry_run=dry_run)
22
+ logger.info("release done: %s", ctx.next_version)
@@ -0,0 +1,50 @@
1
+ """`action-platform service` commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import typer
8
+ from rich.console import Console
9
+
10
+ from action_platform.core.generate import apply_service
11
+ from action_platform.core.templates import load_matrix
12
+ from action_platform.logging import logger
13
+
14
+ app = typer.Typer(
15
+ help="Add application dependencies (database, cache, storage) to a project.",
16
+ no_args_is_help=True,
17
+ )
18
+ console = Console()
19
+
20
+
21
+ @app.command("add")
22
+ def add(
23
+ name: str = typer.Argument(..., help="postgres, redis, s3, ..."),
24
+ provider: str | None = typer.Option(
25
+ None, "--provider", help="docker, aws-rds, aws, ... (default: first listed)"
26
+ ),
27
+ project: Path = typer.Option(
28
+ None, "--project", "-p", help="Project directory (default: cwd)"
29
+ ),
30
+ update: bool = typer.Option(False, "--update", help="Refresh the templates cache"),
31
+ ) -> None:
32
+ """Add services/<name>/ with up + link scripts and record it in platform.toml."""
33
+ repo, matrix = load_matrix(update=update)
34
+ target = (project or Path.cwd()).resolve()
35
+
36
+ apply_service(repo, matrix.service(name), target, provider=provider)
37
+
38
+ logger.info("added service %s to %s", name, target)
39
+
40
+
41
+ @app.command("list")
42
+ def list_() -> None:
43
+ """List available services and their providers."""
44
+ _, matrix = load_matrix()
45
+
46
+ for service in matrix.services:
47
+ console.print(
48
+ f"[bold]{service.name}[/bold] {service.description} "
49
+ f"[dim]({', '.join(service.providers)})[/dim]"
50
+ )
@@ -0,0 +1,27 @@
1
+ """Typer app assembly."""
2
+
3
+ import typer
4
+
5
+ from action_platform.cli.commands import cloud as cloud_cmd
6
+ from action_platform.cli.commands import deploy as deploy_cmd
7
+ from action_platform.cli.commands import init as init_cmd
8
+ from action_platform.cli.commands import mcp as mcp_cmd
9
+ from action_platform.cli.commands import release as release_cmd
10
+ from action_platform.cli.commands import service as service_cmd
11
+
12
+ app = typer.Typer(
13
+ name="action-platform",
14
+ help="Standardize init, release, and deploy across any stack.",
15
+ no_args_is_help=True,
16
+ pretty_exceptions_enable=False,
17
+ )
18
+
19
+ app.command("init")(init_cmd.run)
20
+ app.command("release")(release_cmd.run)
21
+ app.command("deploy")(deploy_cmd.run)
22
+ app.command("rollback")(deploy_cmd.rollback)
23
+ app.command("diagnose")(deploy_cmd.diagnose)
24
+ app.command("destroy")(deploy_cmd.destroy)
25
+ app.command("mcp")(mcp_cmd.run)
26
+ app.add_typer(cloud_cmd.app, name="cloud")
27
+ app.add_typer(service_cmd.app, name="service")
@@ -0,0 +1 @@
1
+ """Action Platform core module."""
@@ -0,0 +1,63 @@
1
+ """ActionPlatform orchestrator."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from action_platform.core import pipeline
8
+ from action_platform.core.config import Config
9
+ from action_platform.core.context import Context, DeployResult, Diagnosis
10
+
11
+
12
+ class ActionPlatform:
13
+ """
14
+ Import:
15
+ from action_platform import ActionPlatform, Config
16
+
17
+ Example:
18
+ tool = ActionPlatform(config=Config(...))
19
+ tool.release("patch")
20
+ tool.deploy()
21
+
22
+ Args:
23
+ config (Config): configuration with injected providers.
24
+ repo_root (Path): repository root. Defaults to cwd.
25
+
26
+ Attributes:
27
+ config (Config):
28
+ repo_root (Path):
29
+ """
30
+
31
+ def __init__(
32
+ self, config: Config | None = None, repo_root: Path | None = None
33
+ ) -> None:
34
+ self.config = config or Config()
35
+ self.repo_root = repo_root or Path.cwd()
36
+
37
+ def release(self, level: str = "patch", dry_run: bool = False) -> Context:
38
+ return pipeline.release(self.config, level, self.repo_root, dry_run=dry_run)
39
+
40
+ def deploy(
41
+ self, target: str | None = None, dry_run: bool = False, stage: str | None = None
42
+ ) -> list[DeployResult]:
43
+ return pipeline.deploy(
44
+ self.config, target, self.repo_root, dry_run=dry_run, stage=stage
45
+ )
46
+
47
+ def rollback(
48
+ self,
49
+ target: str | None = None,
50
+ to_version: str | None = None,
51
+ stage: str | None = None,
52
+ ) -> None:
53
+ pipeline.rollback(
54
+ self.config, target, self.repo_root, to_version=to_version, stage=stage
55
+ )
56
+
57
+ def diagnose(
58
+ self, target: str | None = None, stage: str | None = None
59
+ ) -> list[Diagnosis]:
60
+ return pipeline.diagnose(self.config, target, self.repo_root, stage=stage)
61
+
62
+ def destroy(self, target: str | None = None, stage: str | None = None) -> None:
63
+ pipeline.destroy(self.config, target, self.repo_root, stage=stage)