fogies 0.0.0.dev10__tar.gz → 0.0.0.dev12__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.
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/PKG-INFO +2 -1
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/pyproject.toml +3 -1
- fogies-0.0.0.dev12/src/fogies/age_key.py +48 -0
- fogies-0.0.0.dev12/src/fogies/includes/templates/claude_sync.toml.template +16 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tasks/access_key.py +5 -0
- fogies-0.0.0.dev12/src/fogies/tasks/claude_sync.py +145 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tasks/format.py +3 -1
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tasks/lint.py +3 -1
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tasks/poetry.py +6 -2
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tasks/terraform.py +101 -49
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tasks/terraform_backend.py +13 -24
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tasks/test.py +3 -1
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/templates.py +4 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/terraform/backend.py +76 -36
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tools/aws_environ.py +8 -5
- fogies-0.0.0.dev12/src/fogies/tools/claude_sync.py +302 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tools/terraform.py +53 -24
- fogies-0.0.0.dev10/src/fogies/tools/claude_sync.py +0 -130
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/README.md +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/__init__.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/aws_access_key.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/boto_clients.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/download_verified.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/includes/templates/aws.toml.template +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/includes/templates/backend_status.toml.template +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/includes/templates/poetry.toml.template +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/py.typed +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/pyfogies.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/ready_poll.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/retry.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tasks/__init__.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/terraform/__init__.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/terraform/alb.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/terraform/cloudwatch.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/terraform/ecr.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/terraform/ecs.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/terraform/hosted_zone.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/terraform/network.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tools/__init__.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tools/boto.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tools/command.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tools/environ.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tools/go.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tools/ollama.py +0 -0
- {fogies-0.0.0.dev10 → fogies-0.0.0.dev12}/src/fogies/tools/terraform_backend.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fogies
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev12
|
|
4
4
|
Summary:
|
|
5
5
|
Author: James Fogarty
|
|
6
6
|
Author-email: jayfo@users.noreply.github.com
|
|
@@ -12,6 +12,7 @@ Requires-Dist: filelock (>=3.25.2,<4.0.0)
|
|
|
12
12
|
Requires-Dist: ollama (>=0.6.2,<0.7.0)
|
|
13
13
|
Requires-Dist: psutil (>=7.2.2,<8.0.0)
|
|
14
14
|
Requires-Dist: pydantic (>=2.12.5,<3.0.0)
|
|
15
|
+
Requires-Dist: pyrage (>=1.4.0,<2.0.0)
|
|
15
16
|
Requires-Dist: requests (>=2.33.0,<2.34.0)
|
|
16
17
|
Requires-Dist: tenacity (>=9.1.4,<10.0.0)
|
|
17
18
|
Requires-Dist: tomlkit (>=0.15.1,<0.16.0)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fogies"
|
|
3
3
|
# Version follows semantic versioning <https://semver.org/>.
|
|
4
|
-
version = "0.0.0-dev.
|
|
4
|
+
version = "0.0.0-dev.12"
|
|
5
5
|
description = ""
|
|
6
6
|
authors = [
|
|
7
7
|
{name = "James Fogarty",email = "jayfo@users.noreply.github.com"}
|
|
@@ -18,6 +18,7 @@ include = [
|
|
|
18
18
|
{path = "src/fogies/includes/templates/aws.toml.template", format = ["sdist", "wheel"]},
|
|
19
19
|
{path = "src/fogies/includes/templates/poetry.toml.template", format = ["sdist", "wheel"]},
|
|
20
20
|
{path = "src/fogies/includes/templates/backend_status.toml.template", format = ["sdist", "wheel"]},
|
|
21
|
+
{path = "src/fogies/includes/templates/claude_sync.toml.template", format = ["sdist", "wheel"]},
|
|
21
22
|
]
|
|
22
23
|
|
|
23
24
|
[tool.poetry.dependencies]
|
|
@@ -33,6 +34,7 @@ pydantic = "^2.12.5"
|
|
|
33
34
|
requests = "~2.33.0"
|
|
34
35
|
tenacity = "^9.1.4"
|
|
35
36
|
tomlkit = "^0.15.1"
|
|
37
|
+
pyrage = "^1.4.0"
|
|
36
38
|
|
|
37
39
|
[tool.poetry.group.dev.dependencies]
|
|
38
40
|
# ^ allows all minor and patch releases.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Age secret keys, which encrypt what claude-sync uploads.
|
|
2
|
+
|
|
3
|
+
An age secret key is a string like AGE-SECRET-KEY-1...: see
|
|
4
|
+
<https://github.com/FiloSottile/age>. pyrage, which binds to a Rust
|
|
5
|
+
implementation of age, creates and checks them. It ships no type stubs, so the
|
|
6
|
+
little of it that is used is given types here and nowhere else.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Protocol, cast
|
|
10
|
+
|
|
11
|
+
import pyrage # pyright: ignore[reportMissingTypeStubs]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class _IdentityFactory(Protocol):
|
|
15
|
+
"""The parts of pyrage's x25519 Identity class that are used."""
|
|
16
|
+
|
|
17
|
+
def generate(self) -> object: ...
|
|
18
|
+
|
|
19
|
+
def from_str(self, value: str) -> object: ...
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
_IDENTITY = cast(
|
|
23
|
+
_IdentityFactory,
|
|
24
|
+
pyrage.x25519.Identity, # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
_IDENTITY_ERROR = cast(
|
|
28
|
+
type[Exception],
|
|
29
|
+
pyrage.IdentityError, # pyright: ignore[reportAttributeAccessIssue]
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def generate_age_key() -> str:
|
|
34
|
+
"""Return a new, random age secret key."""
|
|
35
|
+
return str(_IDENTITY.generate())
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def validate_age_key(value: str) -> str:
|
|
39
|
+
"""Return value, if it is an age secret key.
|
|
40
|
+
|
|
41
|
+
Raises ValueError if it is not, including a key with a mistyped character,
|
|
42
|
+
since the checksum is checked.
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
_ = _IDENTITY.from_str(value)
|
|
46
|
+
except _IDENTITY_ERROR as exc:
|
|
47
|
+
raise ValueError("Not an age secret key") from exc
|
|
48
|
+
return value
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Config for claude-sync tasks.
|
|
2
|
+
# See https://github.com/tawanorg/claude-sync
|
|
3
|
+
|
|
4
|
+
# Profile in the AWS config, for an IAM user that can use the bucket.
|
|
5
|
+
aws_profile = "..."
|
|
6
|
+
|
|
7
|
+
# S3 bucket.
|
|
8
|
+
bucket = "..."
|
|
9
|
+
region = "..."
|
|
10
|
+
|
|
11
|
+
# What to sync: "sessions" or "full".
|
|
12
|
+
scope = "sessions"
|
|
13
|
+
|
|
14
|
+
# Encryption key.
|
|
15
|
+
# claude-sync.configure will create, so that all machines have the same key.
|
|
16
|
+
# age_key = "AGE-SECRET-KEY-1..."
|
|
@@ -98,6 +98,7 @@ def get_task_create(
|
|
|
98
98
|
) -> Task[Callable[..., None]]:
|
|
99
99
|
@task(
|
|
100
100
|
name="create",
|
|
101
|
+
auto_shortflags=False,
|
|
101
102
|
positional=[],
|
|
102
103
|
help={
|
|
103
104
|
"prompt": "Prompt for admin credentials.",
|
|
@@ -125,6 +126,7 @@ def get_task_delete(
|
|
|
125
126
|
) -> Task[Callable[..., None]]:
|
|
126
127
|
@task(
|
|
127
128
|
name="delete",
|
|
129
|
+
auto_shortflags=False,
|
|
128
130
|
positional=[],
|
|
129
131
|
help={
|
|
130
132
|
"prompt": "Prompt for admin credentials.",
|
|
@@ -159,6 +161,7 @@ def get_task_delete_key(
|
|
|
159
161
|
) -> Task[Callable[..., None]]:
|
|
160
162
|
@task(
|
|
161
163
|
name="delete-key",
|
|
164
|
+
auto_shortflags=False,
|
|
162
165
|
positional=[],
|
|
163
166
|
help={
|
|
164
167
|
"prompt": "Prompt for admin credentials.",
|
|
@@ -206,6 +209,7 @@ def get_task_list(
|
|
|
206
209
|
) -> Task[Callable[..., None]]:
|
|
207
210
|
@task(
|
|
208
211
|
name="list",
|
|
212
|
+
auto_shortflags=False,
|
|
209
213
|
help={
|
|
210
214
|
"prompt": "Prompt for admin credentials.",
|
|
211
215
|
},
|
|
@@ -235,6 +239,7 @@ def get_task_rotate_key(
|
|
|
235
239
|
) -> Task[Callable[..., None]]:
|
|
236
240
|
@task(
|
|
237
241
|
name="rotate-key",
|
|
242
|
+
auto_shortflags=False,
|
|
238
243
|
positional=[],
|
|
239
244
|
help={
|
|
240
245
|
"prompt": "Prompt for admin credentials.",
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""Tasks for setting up and running claude-sync."""
|
|
2
|
+
|
|
3
|
+
import pathlib
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from typing import cast
|
|
6
|
+
|
|
7
|
+
from invoke.collection import Collection
|
|
8
|
+
from invoke.context import Context
|
|
9
|
+
from invoke.tasks import Task, task
|
|
10
|
+
|
|
11
|
+
from fogies.tools.claude_sync import claude_sync, configure_claude_sync
|
|
12
|
+
from fogies.tools.command import CommandParams
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_task_configure(
|
|
16
|
+
*,
|
|
17
|
+
binary_cache_path: pathlib.Path,
|
|
18
|
+
claude_sync_config_path: pathlib.Path,
|
|
19
|
+
aws_config_path: pathlib.Path,
|
|
20
|
+
) -> Task[Callable[..., None]]:
|
|
21
|
+
@task(
|
|
22
|
+
name="configure",
|
|
23
|
+
auto_shortflags=False,
|
|
24
|
+
help={
|
|
25
|
+
"force": "Force overwrite based on current configuration.",
|
|
26
|
+
},
|
|
27
|
+
) # pyright: ignore[reportUntypedFunctionDecorator]
|
|
28
|
+
def task_configure(context: Context, force: bool = False) -> None:
|
|
29
|
+
"""
|
|
30
|
+
Configure claude-sync on this machine.
|
|
31
|
+
"""
|
|
32
|
+
setup = configure_claude_sync(
|
|
33
|
+
claude_sync_config_path=claude_sync_config_path,
|
|
34
|
+
aws_config_path=aws_config_path,
|
|
35
|
+
force=force,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
if setup.generated_age_key:
|
|
39
|
+
print("Generated encryption key.")
|
|
40
|
+
if setup.applied_to_claude_sync_files:
|
|
41
|
+
print("Applied configuration to claude-sync files.")
|
|
42
|
+
else:
|
|
43
|
+
print("Already configured.")
|
|
44
|
+
|
|
45
|
+
# Reads from the bucket and changes nothing, so this fails now, and
|
|
46
|
+
# clearly, if the credentials, bucket or key are wrong.
|
|
47
|
+
print("Checking the connection:")
|
|
48
|
+
with claude_sync(
|
|
49
|
+
binary_cache_path=binary_cache_path, raise_if_env_exists=False
|
|
50
|
+
) as cs:
|
|
51
|
+
_ = cs.pull(command_params=CommandParams(context=context), dry_run=True)
|
|
52
|
+
|
|
53
|
+
return cast(Task[Callable[..., None]], task_configure)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_task_pull(
|
|
57
|
+
*,
|
|
58
|
+
binary_cache_path: pathlib.Path,
|
|
59
|
+
default_dry_run: bool = False,
|
|
60
|
+
default_force: bool = False,
|
|
61
|
+
default_rebuild_history: bool = True,
|
|
62
|
+
) -> Task[Callable[..., None]]:
|
|
63
|
+
@task(
|
|
64
|
+
name="pull",
|
|
65
|
+
auto_shortflags=False,
|
|
66
|
+
help={
|
|
67
|
+
"dry_run": "Show what would be downloaded.",
|
|
68
|
+
"force": "Force overwrite of local files.",
|
|
69
|
+
"rebuild_history": "Rebuild history from session files.",
|
|
70
|
+
},
|
|
71
|
+
) # pyright: ignore[reportUntypedFunctionDecorator]
|
|
72
|
+
def task_pull(
|
|
73
|
+
context: Context,
|
|
74
|
+
dry_run: bool = default_dry_run,
|
|
75
|
+
force: bool = default_force,
|
|
76
|
+
rebuild_history: bool = default_rebuild_history,
|
|
77
|
+
) -> None:
|
|
78
|
+
"""
|
|
79
|
+
Download remote changes.
|
|
80
|
+
"""
|
|
81
|
+
with claude_sync(
|
|
82
|
+
binary_cache_path=binary_cache_path, raise_if_env_exists=False
|
|
83
|
+
) as cs:
|
|
84
|
+
_ = cs.pull(
|
|
85
|
+
command_params=CommandParams(context=context),
|
|
86
|
+
dry_run=dry_run,
|
|
87
|
+
force=force,
|
|
88
|
+
rebuild_history=rebuild_history,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
return cast(Task[Callable[..., None]], task_pull)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_task_push(*, binary_cache_path: pathlib.Path) -> Task[Callable[..., None]]:
|
|
95
|
+
@task(
|
|
96
|
+
name="push", auto_shortflags=False
|
|
97
|
+
) # pyright: ignore[reportUntypedFunctionDecorator]
|
|
98
|
+
def task_push(context: Context) -> None:
|
|
99
|
+
"""
|
|
100
|
+
Upload local changes.
|
|
101
|
+
"""
|
|
102
|
+
with claude_sync(
|
|
103
|
+
binary_cache_path=binary_cache_path, raise_if_env_exists=False
|
|
104
|
+
) as cs:
|
|
105
|
+
_ = cs.push(command_params=CommandParams(context=context))
|
|
106
|
+
|
|
107
|
+
return cast(Task[Callable[..., None]], task_push)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def get_task_status(*, binary_cache_path: pathlib.Path) -> Task[Callable[..., None]]:
|
|
111
|
+
@task(
|
|
112
|
+
name="status", auto_shortflags=False
|
|
113
|
+
) # pyright: ignore[reportUntypedFunctionDecorator]
|
|
114
|
+
def task_status(context: Context) -> None:
|
|
115
|
+
"""
|
|
116
|
+
Show local changes since prior synchronization.
|
|
117
|
+
"""
|
|
118
|
+
with claude_sync(
|
|
119
|
+
binary_cache_path=binary_cache_path, raise_if_env_exists=False
|
|
120
|
+
) as cs:
|
|
121
|
+
_ = cs.status(command_params=CommandParams(context=context))
|
|
122
|
+
|
|
123
|
+
return cast(Task[Callable[..., None]], task_status)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def get_collection(
|
|
127
|
+
*,
|
|
128
|
+
collection_name: str,
|
|
129
|
+
binary_cache_path: pathlib.Path,
|
|
130
|
+
claude_sync_config_path: pathlib.Path,
|
|
131
|
+
aws_config_path: pathlib.Path,
|
|
132
|
+
) -> Collection:
|
|
133
|
+
"""Get a collection of tasks for setting up and running claude-sync."""
|
|
134
|
+
collection = Collection(collection_name)
|
|
135
|
+
collection.add_task(
|
|
136
|
+
get_task_configure(
|
|
137
|
+
binary_cache_path=binary_cache_path,
|
|
138
|
+
claude_sync_config_path=claude_sync_config_path,
|
|
139
|
+
aws_config_path=aws_config_path,
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
collection.add_task(get_task_pull(binary_cache_path=binary_cache_path))
|
|
143
|
+
collection.add_task(get_task_push(binary_cache_path=binary_cache_path))
|
|
144
|
+
collection.add_task(get_task_status(binary_cache_path=binary_cache_path))
|
|
145
|
+
return collection
|
|
@@ -26,7 +26,9 @@ def get_task_format(
|
|
|
26
26
|
if not (fmt_black or fmt_isort or fmt_terraform):
|
|
27
27
|
raise ValueError("At least one fmt flag must be set.")
|
|
28
28
|
|
|
29
|
-
@task(
|
|
29
|
+
@task(
|
|
30
|
+
name="format", auto_shortflags=False
|
|
31
|
+
) # pyright: ignore[reportUntypedFunctionDecorator]
|
|
30
32
|
def task_format(context: Context) -> None:
|
|
31
33
|
"""
|
|
32
34
|
Apply code formatting.
|
|
@@ -9,7 +9,9 @@ from invoke.tasks import Task, task
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def get_task_lint() -> Task[Callable[[Context], None]]:
|
|
12
|
-
@task(
|
|
12
|
+
@task(
|
|
13
|
+
name="lint", auto_shortflags=False
|
|
14
|
+
) # pyright: ignore[reportUntypedFunctionDecorator]
|
|
13
15
|
def task_lint(context: Context) -> None:
|
|
14
16
|
"""
|
|
15
17
|
Run linting.
|
|
@@ -14,7 +14,9 @@ from fogies.templates import ensure_from_template, poetry_toml_template_factory
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def get_task_build() -> Task[Callable[[Context], None]]:
|
|
17
|
-
@task(
|
|
17
|
+
@task(
|
|
18
|
+
name="build", auto_shortflags=False
|
|
19
|
+
) # pyright: ignore[reportUntypedFunctionDecorator]
|
|
18
20
|
def task_build(context: Context) -> None:
|
|
19
21
|
"""
|
|
20
22
|
Build package artifacts.
|
|
@@ -33,7 +35,9 @@ def get_task_build() -> Task[Callable[[Context], None]]:
|
|
|
33
35
|
|
|
34
36
|
|
|
35
37
|
def get_task_publish(*, secrets_poetry_path: Path) -> Task[Callable[[Context], None]]:
|
|
36
|
-
@task(
|
|
38
|
+
@task(
|
|
39
|
+
name="publish", auto_shortflags=False
|
|
40
|
+
) # pyright: ignore[reportUntypedFunctionDecorator]
|
|
37
41
|
def task_publish(context: Context) -> None:
|
|
38
42
|
"""
|
|
39
43
|
Publish package to PyPI.
|
|
@@ -21,62 +21,94 @@ from fogies.tools.terraform import (
|
|
|
21
21
|
)
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
def validate_init_params(*, init: bool, init_params: InitParams) -> None:
|
|
25
|
+
"""Raise ValueError for task flags that cannot be given together.
|
|
26
|
+
|
|
27
|
+
The init options only apply when init runs, and Terraform does not allow
|
|
28
|
+
migrating state while also reconfiguring the backend.
|
|
29
|
+
"""
|
|
30
|
+
if init_params.migrate_state and not init:
|
|
31
|
+
raise ValueError("--init-migrate-state requires --init")
|
|
32
|
+
if init_params.reconfigure and not init:
|
|
33
|
+
raise ValueError("--init-reconfigure requires --init")
|
|
34
|
+
if init_params.upgrade and not init:
|
|
35
|
+
raise ValueError("--init-upgrade requires --init")
|
|
36
|
+
if init_params.migrate_state and init_params.reconfigure:
|
|
37
|
+
raise ValueError(
|
|
38
|
+
"--init-migrate-state and --init-reconfigure cannot be combined"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
24
42
|
def get_task_apply(
|
|
25
43
|
*,
|
|
26
44
|
binary_cache_path: pathlib.Path,
|
|
27
45
|
module_path: pathlib.Path,
|
|
28
46
|
aws_environ_factory: AwsEnvironFactory | None = None,
|
|
29
|
-
|
|
47
|
+
backend_config: BackendConfig | None = None,
|
|
30
48
|
backend_status_path: pathlib.Path | None = None,
|
|
31
49
|
tfbackend_factory: TfbackendFactory | None = None,
|
|
32
50
|
tfvars_factory: TfvarsFactory | None = None,
|
|
33
51
|
default_init: bool = True,
|
|
34
|
-
|
|
52
|
+
default_init_migrate_state: bool = False,
|
|
35
53
|
default_init_reconfigure: bool = False,
|
|
54
|
+
default_init_upgrade: bool = False,
|
|
36
55
|
default_apply_auto_approve: bool = False,
|
|
37
|
-
) -> Task[Callable[[Context, bool, bool, bool, bool], None]]:
|
|
38
|
-
if
|
|
39
|
-
raise ValueError("tfbackend_factory is required when
|
|
40
|
-
if (
|
|
41
|
-
|
|
56
|
+
) -> Task[Callable[[Context, bool, bool, bool, bool, bool], None]]:
|
|
57
|
+
if backend_config is not None and tfbackend_factory is None:
|
|
58
|
+
raise ValueError("tfbackend_factory is required when backend_config is set")
|
|
59
|
+
if (backend_config is not None or tfbackend_factory is not None) and (
|
|
60
|
+
aws_environ_factory is None
|
|
61
|
+
):
|
|
62
|
+
raise ValueError(
|
|
63
|
+
"aws_environ_factory is required when backend_config or tfbackend_factory is set"
|
|
64
|
+
)
|
|
65
|
+
if (backend_status_path is None) != (backend_config is None):
|
|
66
|
+
raise ValueError(
|
|
67
|
+
"backend_status_path and backend_config must be provided together"
|
|
68
|
+
)
|
|
42
69
|
|
|
43
70
|
@task(
|
|
44
71
|
name="apply",
|
|
72
|
+
auto_shortflags=False,
|
|
45
73
|
help={
|
|
46
74
|
"init": "Include terraform init. Skip with --no-init.",
|
|
47
|
-
"
|
|
75
|
+
"init_migrate_state": "During init, migrate state to a changed backend.",
|
|
48
76
|
"init_reconfigure": "During init, reconfigure the backend.",
|
|
77
|
+
"init_upgrade": "During init, upgrade providers.",
|
|
49
78
|
"apply_auto_approve": "Skip interactive confirmation.",
|
|
50
79
|
},
|
|
51
80
|
) # pyright: ignore[reportUntypedFunctionDecorator]
|
|
52
81
|
def task_apply(
|
|
53
82
|
context: Context,
|
|
54
83
|
init: bool = default_init,
|
|
55
|
-
|
|
84
|
+
init_migrate_state: bool = default_init_migrate_state,
|
|
56
85
|
init_reconfigure: bool = default_init_reconfigure,
|
|
86
|
+
init_upgrade: bool = default_init_upgrade,
|
|
57
87
|
apply_auto_approve: bool = default_apply_auto_approve,
|
|
58
88
|
) -> None:
|
|
59
89
|
"""
|
|
60
90
|
Apply a Terraform configuration.
|
|
61
91
|
"""
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
92
|
+
init_params = InitParams(
|
|
93
|
+
migrate_state=init_migrate_state,
|
|
94
|
+
reconfigure=init_reconfigure,
|
|
95
|
+
upgrade=init_upgrade,
|
|
96
|
+
)
|
|
97
|
+
validate_init_params(init=init, init_params=init_params)
|
|
66
98
|
|
|
67
99
|
command_params = CommandParams(context=context)
|
|
68
|
-
init_params = (
|
|
69
|
-
InitParams(upgrade=init_upgrade, reconfigure=init_reconfigure)
|
|
70
|
-
if init
|
|
71
|
-
else None
|
|
72
|
-
)
|
|
73
100
|
|
|
74
101
|
with ExitStack() as stack:
|
|
75
|
-
|
|
76
|
-
|
|
102
|
+
aws_environ = (
|
|
103
|
+
stack.enter_context(aws_environ_factory())
|
|
104
|
+
if aws_environ_factory
|
|
105
|
+
else None
|
|
106
|
+
)
|
|
77
107
|
|
|
78
108
|
tfbackend_path = (
|
|
79
|
-
stack.enter_context(tfbackend_factory())
|
|
109
|
+
stack.enter_context(tfbackend_factory(aws_environ))
|
|
110
|
+
if tfbackend_factory and aws_environ
|
|
111
|
+
else None
|
|
80
112
|
)
|
|
81
113
|
tfvars_path = (
|
|
82
114
|
stack.enter_context(tfvars_factory()) if tfvars_factory else None
|
|
@@ -87,7 +119,8 @@ def get_task_apply(
|
|
|
87
119
|
binary_cache_path=binary_cache_path,
|
|
88
120
|
command_params=command_params,
|
|
89
121
|
module_path=module_path,
|
|
90
|
-
|
|
122
|
+
backend_config=backend_config,
|
|
123
|
+
aws_environ=aws_environ,
|
|
91
124
|
backend_status_path=backend_status_path,
|
|
92
125
|
tfbackend_path=tfbackend_path,
|
|
93
126
|
tfvars_path=tfvars_path,
|
|
@@ -99,7 +132,9 @@ def get_task_apply(
|
|
|
99
132
|
)
|
|
100
133
|
)
|
|
101
134
|
|
|
102
|
-
return cast(
|
|
135
|
+
return cast(
|
|
136
|
+
Task[Callable[[Context, bool, bool, bool, bool, bool], None]], task_apply
|
|
137
|
+
)
|
|
103
138
|
|
|
104
139
|
|
|
105
140
|
def get_task_destroy(
|
|
@@ -107,57 +142,71 @@ def get_task_destroy(
|
|
|
107
142
|
binary_cache_path: pathlib.Path,
|
|
108
143
|
module_path: pathlib.Path,
|
|
109
144
|
aws_environ_factory: AwsEnvironFactory | None = None,
|
|
110
|
-
|
|
145
|
+
backend_config: BackendConfig | None = None,
|
|
111
146
|
backend_status_path: pathlib.Path | None = None,
|
|
112
147
|
tfbackend_factory: TfbackendFactory | None = None,
|
|
113
148
|
tfvars_factory: TfvarsFactory | None = None,
|
|
114
149
|
default_init: bool = True,
|
|
115
|
-
|
|
150
|
+
default_init_migrate_state: bool = False,
|
|
116
151
|
default_init_reconfigure: bool = False,
|
|
152
|
+
default_init_upgrade: bool = False,
|
|
117
153
|
default_destroy_auto_approve: bool = False,
|
|
118
|
-
) -> Task[Callable[[Context, bool, bool, bool, bool], None]]:
|
|
119
|
-
if
|
|
120
|
-
raise ValueError("tfbackend_factory is required when
|
|
121
|
-
if (
|
|
122
|
-
|
|
154
|
+
) -> Task[Callable[[Context, bool, bool, bool, bool, bool], None]]:
|
|
155
|
+
if backend_config is not None and tfbackend_factory is None:
|
|
156
|
+
raise ValueError("tfbackend_factory is required when backend_config is set")
|
|
157
|
+
if (backend_config is not None or tfbackend_factory is not None) and (
|
|
158
|
+
aws_environ_factory is None
|
|
159
|
+
):
|
|
160
|
+
raise ValueError(
|
|
161
|
+
"aws_environ_factory is required when backend_config or tfbackend_factory is set"
|
|
162
|
+
)
|
|
163
|
+
if (backend_status_path is None) != (backend_config is None):
|
|
164
|
+
raise ValueError(
|
|
165
|
+
"backend_status_path and backend_config must be provided together"
|
|
166
|
+
)
|
|
123
167
|
|
|
124
168
|
@task(
|
|
125
169
|
name="destroy",
|
|
170
|
+
auto_shortflags=False,
|
|
126
171
|
help={
|
|
127
172
|
"init": "Include terraform init. Skip with --no-init.",
|
|
128
|
-
"
|
|
173
|
+
"init_migrate_state": "During init, migrate state to a changed backend.",
|
|
129
174
|
"init_reconfigure": "During init, reconfigure the backend.",
|
|
175
|
+
"init_upgrade": "During init, upgrade providers.",
|
|
130
176
|
"destroy_auto_approve": "Skip interactive confirmation.",
|
|
131
177
|
},
|
|
132
178
|
) # pyright: ignore[reportUntypedFunctionDecorator]
|
|
133
179
|
def task_destroy(
|
|
134
180
|
context: Context,
|
|
135
181
|
init: bool = default_init,
|
|
136
|
-
|
|
182
|
+
init_migrate_state: bool = default_init_migrate_state,
|
|
137
183
|
init_reconfigure: bool = default_init_reconfigure,
|
|
184
|
+
init_upgrade: bool = default_init_upgrade,
|
|
138
185
|
destroy_auto_approve: bool = default_destroy_auto_approve,
|
|
139
186
|
) -> None:
|
|
140
187
|
"""
|
|
141
188
|
Destroy a Terraform configuration.
|
|
142
189
|
"""
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
190
|
+
init_params = InitParams(
|
|
191
|
+
migrate_state=init_migrate_state,
|
|
192
|
+
reconfigure=init_reconfigure,
|
|
193
|
+
upgrade=init_upgrade,
|
|
194
|
+
)
|
|
195
|
+
validate_init_params(init=init, init_params=init_params)
|
|
147
196
|
|
|
148
197
|
command_params = CommandParams(context=context)
|
|
149
|
-
init_params = (
|
|
150
|
-
InitParams(upgrade=init_upgrade, reconfigure=init_reconfigure)
|
|
151
|
-
if init
|
|
152
|
-
else None
|
|
153
|
-
)
|
|
154
198
|
|
|
155
199
|
with ExitStack() as stack:
|
|
156
|
-
|
|
157
|
-
|
|
200
|
+
aws_environ = (
|
|
201
|
+
stack.enter_context(aws_environ_factory())
|
|
202
|
+
if aws_environ_factory
|
|
203
|
+
else None
|
|
204
|
+
)
|
|
158
205
|
|
|
159
206
|
tfbackend_path = (
|
|
160
|
-
stack.enter_context(tfbackend_factory())
|
|
207
|
+
stack.enter_context(tfbackend_factory(aws_environ))
|
|
208
|
+
if tfbackend_factory and aws_environ
|
|
209
|
+
else None
|
|
161
210
|
)
|
|
162
211
|
tfvars_path = (
|
|
163
212
|
stack.enter_context(tfvars_factory()) if tfvars_factory else None
|
|
@@ -168,7 +217,8 @@ def get_task_destroy(
|
|
|
168
217
|
binary_cache_path=binary_cache_path,
|
|
169
218
|
command_params=command_params,
|
|
170
219
|
module_path=module_path,
|
|
171
|
-
|
|
220
|
+
backend_config=backend_config,
|
|
221
|
+
aws_environ=aws_environ,
|
|
172
222
|
backend_status_path=backend_status_path,
|
|
173
223
|
tfbackend_path=tfbackend_path,
|
|
174
224
|
tfvars_path=tfvars_path,
|
|
@@ -179,7 +229,9 @@ def get_task_destroy(
|
|
|
179
229
|
)
|
|
180
230
|
)
|
|
181
231
|
|
|
182
|
-
return cast(
|
|
232
|
+
return cast(
|
|
233
|
+
Task[Callable[[Context, bool, bool, bool, bool, bool], None]], task_destroy
|
|
234
|
+
)
|
|
183
235
|
|
|
184
236
|
|
|
185
237
|
def get_collection(
|
|
@@ -188,7 +240,7 @@ def get_collection(
|
|
|
188
240
|
binary_cache_path: pathlib.Path,
|
|
189
241
|
module_path: pathlib.Path,
|
|
190
242
|
aws_environ_factory: AwsEnvironFactory | None = None,
|
|
191
|
-
|
|
243
|
+
backend_config: BackendConfig | None = None,
|
|
192
244
|
backend_status_path: pathlib.Path | None = None,
|
|
193
245
|
tfbackend_factory: TfbackendFactory | None = None,
|
|
194
246
|
tfvars_factory: TfvarsFactory | None = None,
|
|
@@ -200,7 +252,7 @@ def get_collection(
|
|
|
200
252
|
binary_cache_path=binary_cache_path,
|
|
201
253
|
module_path=module_path,
|
|
202
254
|
aws_environ_factory=aws_environ_factory,
|
|
203
|
-
|
|
255
|
+
backend_config=backend_config,
|
|
204
256
|
backend_status_path=backend_status_path,
|
|
205
257
|
tfbackend_factory=tfbackend_factory,
|
|
206
258
|
tfvars_factory=tfvars_factory,
|
|
@@ -211,7 +263,7 @@ def get_collection(
|
|
|
211
263
|
binary_cache_path=binary_cache_path,
|
|
212
264
|
module_path=module_path,
|
|
213
265
|
aws_environ_factory=aws_environ_factory,
|
|
214
|
-
|
|
266
|
+
backend_config=backend_config,
|
|
215
267
|
backend_status_path=backend_status_path,
|
|
216
268
|
tfbackend_factory=tfbackend_factory,
|
|
217
269
|
tfvars_factory=tfvars_factory,
|