release-scope 0.3.1__tar.gz → 0.4.0__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.
- {release_scope-0.3.1 → release_scope-0.4.0}/PKG-INFO +38 -4
- {release_scope-0.3.1 → release_scope-0.4.0}/README.md +37 -3
- {release_scope-0.3.1 → release_scope-0.4.0}/pyproject.toml +1 -1
- {release_scope-0.3.1 → release_scope-0.4.0}/pyproject.toml.orig +1 -1
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/__main__.py +44 -25
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_gitlab.py +18 -1
- release_scope-0.4.0/release_scope/_publish.py +51 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_settings.py +2 -2
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/ioc.py +4 -2
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/__init__.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_cache.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_errors.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_files.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_jira.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_jira_keys.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_links.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_messages.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_render.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_report.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_rows.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/_use_case.py +0 -0
- {release_scope-0.3.1 → release_scope-0.4.0}/release_scope/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: release-scope
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Collect what sits between production and the default branch across GitLab services: tags, MRs, Jira keys, failed jobs
|
|
5
5
|
Keywords: release,gitlab,jira,deployments,merge-requests,ci,cli,python
|
|
6
6
|
Author: Artur Shiriev
|
|
@@ -65,7 +65,7 @@ issue's Web links whenever a commit or MR mentions it; a link counts only if it
|
|
|
65
65
|
|
|
66
66
|
```sh
|
|
67
67
|
export RELEASE_SCOPE_GITLAB__ENDPOINT=https://gitlab.example.com
|
|
68
|
-
export RELEASE_SCOPE_GITLAB__TOKEN=glpat-... # read_api scope
|
|
68
|
+
export RELEASE_SCOPE_GITLAB__TOKEN=glpat-... # read_api scope; api for publish
|
|
69
69
|
export RELEASE_SCOPE_ENVIRONMENTS='["prod", "preview"]'
|
|
70
70
|
export RELEASE_SCOPE_PRODUCTION_ENVIRONMENT=prod
|
|
71
71
|
|
|
@@ -152,6 +152,39 @@ Chain the two commands with `;`, not `&&`: `collect` exits `1` when a service fa
|
|
|
152
152
|
should show it. Alert on the exit code of `collect`, not on whether to render. `render` fails only when it cannot
|
|
153
153
|
read the report or write the page.
|
|
154
154
|
|
|
155
|
+
## Wiki
|
|
156
|
+
|
|
157
|
+
`publish` replaces the content of an existing page in a project wiki with a rendered page:
|
|
158
|
+
|
|
159
|
+
```sh
|
|
160
|
+
uvx release-scope publish report.md --project team/docs --page releases/backend
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`--page` is the page slug, as in its URL after `/-/wikis/`. The page must already exist; `publish` never creates
|
|
164
|
+
one, so create it once in GitLab. It keeps the page title and format, and skips the write when the content is
|
|
165
|
+
unchanged, so a scheduled run does not add a page version every time. Publishing needs a token with the `api` scope
|
|
166
|
+
whose user has at least the Developer role in the wiki's project; a denied token exits `3`, a missing page or any
|
|
167
|
+
other failed request exits `4`. GitLab rejects pages larger than its wiki page size limit, 5 MB by default; the error
|
|
168
|
+
then names the size of the page.
|
|
169
|
+
|
|
170
|
+
A scheduled GitLab CI job keeps the page current. It publishes even when a service failed, then fails the job:
|
|
171
|
+
|
|
172
|
+
```yaml
|
|
173
|
+
release-page:
|
|
174
|
+
image: python:3.13-slim
|
|
175
|
+
rules:
|
|
176
|
+
- if: $CI_PIPELINE_SOURCE == "schedule"
|
|
177
|
+
script:
|
|
178
|
+
- pip install 'release-scope>=0.4,<0.5'
|
|
179
|
+
- release-scope collect --group team/backend --output report.json || status=$?
|
|
180
|
+
- release-scope render report.json --output report.md
|
|
181
|
+
- release-scope publish report.md --project team/docs --page releases/backend
|
|
182
|
+
- exit "${status:-0}"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Set `RELEASE_SCOPE_GITLAB__ENDPOINT` and a masked `RELEASE_SCOPE_GITLAB__TOKEN` as CI/CD variables of the project
|
|
186
|
+
that runs the job, along with the other settings.
|
|
187
|
+
|
|
155
188
|
## Cache
|
|
156
189
|
|
|
157
190
|
`--cache` names a JSON file that is read if present and rewritten atomically after the run. It holds only facts
|
|
@@ -167,7 +200,8 @@ requests and never changes the report.
|
|
|
167
200
|
skill that runs `release-scope` through `uvx` and answers release questions from the report. Ask your coding agent
|
|
168
201
|
what in the current repository has not reached production, what a group will ship with the next tag, or whether a
|
|
169
202
|
Jira issue is released and which services it touches. For the current repository the skill takes `--project` from
|
|
170
|
-
the git remote. It keeps the report and cache outside the repository and
|
|
203
|
+
the git remote. It keeps the report and cache outside the repository, and publishes to a wiki page only when you ask
|
|
204
|
+
for it and name the page.
|
|
171
205
|
|
|
172
206
|
Install it with [skills](https://github.com/vercel-labs/skills):
|
|
173
207
|
|
|
@@ -176,4 +210,4 @@ npx skills add modern-python/release-scope
|
|
|
176
210
|
```
|
|
177
211
|
|
|
178
212
|
The agent reads the same environment variables as the CLI, so set them first as described under Configuration.
|
|
179
|
-
The skill runs `release-scope>=0.
|
|
213
|
+
The skill runs `release-scope>=0.4,<0.5`, the range whose flags and report schema it describes.
|
|
@@ -32,7 +32,7 @@ issue's Web links whenever a commit or MR mentions it; a link counts only if it
|
|
|
32
32
|
|
|
33
33
|
```sh
|
|
34
34
|
export RELEASE_SCOPE_GITLAB__ENDPOINT=https://gitlab.example.com
|
|
35
|
-
export RELEASE_SCOPE_GITLAB__TOKEN=glpat-... # read_api scope
|
|
35
|
+
export RELEASE_SCOPE_GITLAB__TOKEN=glpat-... # read_api scope; api for publish
|
|
36
36
|
export RELEASE_SCOPE_ENVIRONMENTS='["prod", "preview"]'
|
|
37
37
|
export RELEASE_SCOPE_PRODUCTION_ENVIRONMENT=prod
|
|
38
38
|
|
|
@@ -119,6 +119,39 @@ Chain the two commands with `;`, not `&&`: `collect` exits `1` when a service fa
|
|
|
119
119
|
should show it. Alert on the exit code of `collect`, not on whether to render. `render` fails only when it cannot
|
|
120
120
|
read the report or write the page.
|
|
121
121
|
|
|
122
|
+
## Wiki
|
|
123
|
+
|
|
124
|
+
`publish` replaces the content of an existing page in a project wiki with a rendered page:
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
uvx release-scope publish report.md --project team/docs --page releases/backend
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`--page` is the page slug, as in its URL after `/-/wikis/`. The page must already exist; `publish` never creates
|
|
131
|
+
one, so create it once in GitLab. It keeps the page title and format, and skips the write when the content is
|
|
132
|
+
unchanged, so a scheduled run does not add a page version every time. Publishing needs a token with the `api` scope
|
|
133
|
+
whose user has at least the Developer role in the wiki's project; a denied token exits `3`, a missing page or any
|
|
134
|
+
other failed request exits `4`. GitLab rejects pages larger than its wiki page size limit, 5 MB by default; the error
|
|
135
|
+
then names the size of the page.
|
|
136
|
+
|
|
137
|
+
A scheduled GitLab CI job keeps the page current. It publishes even when a service failed, then fails the job:
|
|
138
|
+
|
|
139
|
+
```yaml
|
|
140
|
+
release-page:
|
|
141
|
+
image: python:3.13-slim
|
|
142
|
+
rules:
|
|
143
|
+
- if: $CI_PIPELINE_SOURCE == "schedule"
|
|
144
|
+
script:
|
|
145
|
+
- pip install 'release-scope>=0.4,<0.5'
|
|
146
|
+
- release-scope collect --group team/backend --output report.json || status=$?
|
|
147
|
+
- release-scope render report.json --output report.md
|
|
148
|
+
- release-scope publish report.md --project team/docs --page releases/backend
|
|
149
|
+
- exit "${status:-0}"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Set `RELEASE_SCOPE_GITLAB__ENDPOINT` and a masked `RELEASE_SCOPE_GITLAB__TOKEN` as CI/CD variables of the project
|
|
153
|
+
that runs the job, along with the other settings.
|
|
154
|
+
|
|
122
155
|
## Cache
|
|
123
156
|
|
|
124
157
|
`--cache` names a JSON file that is read if present and rewritten atomically after the run. It holds only facts
|
|
@@ -134,7 +167,8 @@ requests and never changes the report.
|
|
|
134
167
|
skill that runs `release-scope` through `uvx` and answers release questions from the report. Ask your coding agent
|
|
135
168
|
what in the current repository has not reached production, what a group will ship with the next tag, or whether a
|
|
136
169
|
Jira issue is released and which services it touches. For the current repository the skill takes `--project` from
|
|
137
|
-
the git remote. It keeps the report and cache outside the repository and
|
|
170
|
+
the git remote. It keeps the report and cache outside the repository, and publishes to a wiki page only when you ask
|
|
171
|
+
for it and name the page.
|
|
138
172
|
|
|
139
173
|
Install it with [skills](https://github.com/vercel-labs/skills):
|
|
140
174
|
|
|
@@ -143,4 +177,4 @@ npx skills add modern-python/release-scope
|
|
|
143
177
|
```
|
|
144
178
|
|
|
145
179
|
The agent reads the same environment variables as the CLI, so set them first as described under Configuration.
|
|
146
|
-
The skill runs `release-scope>=0.
|
|
180
|
+
The skill runs `release-scope>=0.4,<0.5`, the range whose flags and report schema it describes.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import functools
|
|
1
2
|
import importlib.metadata
|
|
2
3
|
import json
|
|
3
4
|
import pathlib
|
|
@@ -11,9 +12,9 @@ from release_scope._cache import Cache
|
|
|
11
12
|
from release_scope._errors import ConfigError, ReleaseScopeError
|
|
12
13
|
from release_scope._files import write_text_atomic
|
|
13
14
|
from release_scope._jira_keys import JIRA_KEY_PATTERN
|
|
15
|
+
from release_scope._publish import PublishUseCase
|
|
14
16
|
from release_scope._render import render_markdown
|
|
15
17
|
from release_scope._report import SCHEMA_VERSION, Report
|
|
16
|
-
from release_scope._settings import Settings, load_settings
|
|
17
18
|
from release_scope._use_case import CollectUseCase
|
|
18
19
|
|
|
19
20
|
|
|
@@ -47,16 +48,26 @@ def _main_callback(
|
|
|
47
48
|
pass
|
|
48
49
|
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
) ->
|
|
54
|
-
|
|
51
|
+
_P = typing.ParamSpec("_P")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _exit_on_error(func: typing.Callable[_P, None]) -> typing.Callable[_P, None]:
|
|
55
|
+
@functools.wraps(func)
|
|
56
|
+
def wrapper(*args: _P.args, **kwargs: _P.kwargs) -> None:
|
|
57
|
+
try:
|
|
58
|
+
func(*args, **kwargs)
|
|
59
|
+
except ReleaseScopeError as err:
|
|
60
|
+
typer.echo(f"Error: {err}", err=True)
|
|
61
|
+
raise typer.Exit(code=err.exit_code) from err
|
|
62
|
+
|
|
63
|
+
return wrapper
|
|
55
64
|
|
|
56
65
|
|
|
57
66
|
@MAIN_APP.command("collect", help="Collect pending changes per service into a JSON report.")
|
|
67
|
+
@_exit_on_error
|
|
68
|
+
@modern_di_typer.inject
|
|
58
69
|
def _collect_command( # noqa: PLR0913, PLR0917
|
|
59
|
-
|
|
70
|
+
use_case: typing.Annotated[CollectUseCase, modern_di_typer.FromDI(CollectUseCase)],
|
|
60
71
|
output: typing.Annotated[pathlib.Path, typer.Option("--output", "-o", help="Where to write the report JSON.")],
|
|
61
72
|
group: typing.Annotated[
|
|
62
73
|
list[str] | None, typer.Option("--group", "-g", help="GitLab group path; repeatable.")
|
|
@@ -76,24 +87,14 @@ def _collect_command( # noqa: PLR0913, PLR0917
|
|
|
76
87
|
typer.Option("--jira", "-j", help="Jira issue key; collect only the services it links to. Repeatable."),
|
|
77
88
|
] = None,
|
|
78
89
|
) -> None:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if jira:
|
|
88
|
-
report = use_case.for_issues(keys=list(dict.fromkeys(jira)), cache=cache)
|
|
89
|
-
else:
|
|
90
|
-
report = use_case(
|
|
91
|
-
groups=group or [], projects=project or [], include_subgroups=include_subgroups, cache=cache
|
|
92
|
-
)
|
|
93
|
-
except ReleaseScopeError as err:
|
|
94
|
-
typer.echo(f"Error: {err}", err=True)
|
|
95
|
-
raise typer.Exit(code=err.exit_code) from err
|
|
96
|
-
|
|
90
|
+
_check_selection(groups=group or [], projects=project or [], keys=jira or [])
|
|
91
|
+
cache, cache_warning = Cache.load(cache_path) if cache_path else (Cache(), None)
|
|
92
|
+
if cache_warning:
|
|
93
|
+
typer.echo(f"Warning: {cache_warning}", err=True)
|
|
94
|
+
if jira:
|
|
95
|
+
report = use_case.for_issues(keys=list(dict.fromkeys(jira)), cache=cache)
|
|
96
|
+
else:
|
|
97
|
+
report = use_case(groups=group or [], projects=project or [], include_subgroups=include_subgroups, cache=cache)
|
|
97
98
|
write_text_atomic(output, report.model_dump_json(indent=2))
|
|
98
99
|
if cache_path:
|
|
99
100
|
cache.save(cache_path)
|
|
@@ -160,6 +161,24 @@ def _render_command(
|
|
|
160
161
|
typer.echo(f"{len(report.services)} services -> {output}", err=True)
|
|
161
162
|
|
|
162
163
|
|
|
164
|
+
@MAIN_APP.command("publish", help="Replace the content of an existing GitLab wiki page with a rendered page.")
|
|
165
|
+
@_exit_on_error
|
|
166
|
+
@modern_di_typer.inject
|
|
167
|
+
def _publish_command(
|
|
168
|
+
use_case: typing.Annotated[PublishUseCase, modern_di_typer.FromDI(PublishUseCase)],
|
|
169
|
+
page_path: typing.Annotated[pathlib.Path, typer.Argument(help="Markdown page written by `render`.")],
|
|
170
|
+
project: typing.Annotated[str, typer.Option("--project", "-p", help="GitLab project path that holds the wiki.")],
|
|
171
|
+
page: typing.Annotated[str, typer.Option("--page", help="Slug of the wiki page, such as releases/backend.")],
|
|
172
|
+
) -> None:
|
|
173
|
+
try:
|
|
174
|
+
content = page_path.read_text(encoding="utf-8")
|
|
175
|
+
except (OSError, ValueError) as exc:
|
|
176
|
+
typer.echo(f"Error: Cannot read page {page_path}: {type(exc).__name__}.", err=True)
|
|
177
|
+
raise typer.Exit(code=ConfigError.exit_code) from exc
|
|
178
|
+
published: typing.Final = use_case(project=project, slug=page, content=content)
|
|
179
|
+
typer.echo(f"{'Updated' if published.updated else 'Unchanged'} {published.url}", err=True)
|
|
180
|
+
|
|
181
|
+
|
|
163
182
|
def main() -> None:
|
|
164
183
|
with ioc.container:
|
|
165
184
|
MAIN_APP()
|
|
@@ -104,6 +104,11 @@ class Bridge(Job):
|
|
|
104
104
|
downstream_pipeline: DownstreamPipeline | None = None
|
|
105
105
|
|
|
106
106
|
|
|
107
|
+
class WikiPage(pydantic.BaseModel):
|
|
108
|
+
slug: str
|
|
109
|
+
content: str
|
|
110
|
+
|
|
111
|
+
|
|
107
112
|
class _Projects(pydantic.RootModel[list[Project]]):
|
|
108
113
|
pass
|
|
109
114
|
|
|
@@ -137,7 +142,7 @@ class _Bridges(pydantic.RootModel[list[Bridge]]):
|
|
|
137
142
|
|
|
138
143
|
|
|
139
144
|
Resource: typing.TypeAlias = typing.Literal[
|
|
140
|
-
"group", "project", "deployments", "pipelines", "repository", "merge_requests"
|
|
145
|
+
"group", "project", "deployments", "pipelines", "repository", "merge_requests", "wiki"
|
|
141
146
|
]
|
|
142
147
|
|
|
143
148
|
|
|
@@ -165,6 +170,12 @@ class GitLabApi:
|
|
|
165
170
|
except httpware.ClientError as exc:
|
|
166
171
|
raise _translate(exc, url=url, resource=resource) from exc
|
|
167
172
|
|
|
173
|
+
def _put(self, url: str, body: dict[str, typing.Any], *, resource: Resource) -> None:
|
|
174
|
+
try:
|
|
175
|
+
self.http.put(url, json=body)
|
|
176
|
+
except httpware.ClientError as exc:
|
|
177
|
+
raise _translate(exc, url=url, resource=resource) from exc
|
|
178
|
+
|
|
168
179
|
def _pages(
|
|
169
180
|
self,
|
|
170
181
|
url: str,
|
|
@@ -288,3 +299,9 @@ class GitLabApi:
|
|
|
288
299
|
resource="pipelines",
|
|
289
300
|
)
|
|
290
301
|
return bridges
|
|
302
|
+
|
|
303
|
+
def get_wiki_page(self, project: str, slug: str) -> WikiPage:
|
|
304
|
+
return self._get(f"{_API}/projects/{_quote(project)}/wikis/{_quote(slug)}", {}, WikiPage, resource="wiki")
|
|
305
|
+
|
|
306
|
+
def update_wiki_page(self, project: str, slug: str, *, content: str) -> None:
|
|
307
|
+
self._put(f"{_API}/projects/{_quote(project)}/wikis/{_quote(slug)}", {"content": content}, resource="wiki")
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import http
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
from release_scope._errors import AuthError, GitLabError, ReleaseScopeError
|
|
6
|
+
from release_scope._gitlab import GitLabApi
|
|
7
|
+
from release_scope._settings import Settings
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
|
|
11
|
+
class Published:
|
|
12
|
+
url: str
|
|
13
|
+
updated: bool
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _wiki_error(error: GitLabError, *, project: str, slug: str, size: int | None) -> ReleaseScopeError:
|
|
17
|
+
if error.status == http.HTTPStatus.FORBIDDEN:
|
|
18
|
+
return AuthError(
|
|
19
|
+
f"GitLab denied access to the wiki of project '{project}' (403). Check that the token has the 'api' "
|
|
20
|
+
"scope and that its user has at least the Developer role there."
|
|
21
|
+
)
|
|
22
|
+
if error.status == http.HTTPStatus.NOT_FOUND:
|
|
23
|
+
return GitLabError(
|
|
24
|
+
f"Wiki page '{slug}' does not exist in project '{project}', or the token cannot see it. "
|
|
25
|
+
"Create the page in GitLab first.",
|
|
26
|
+
resource="wiki",
|
|
27
|
+
status=error.status,
|
|
28
|
+
)
|
|
29
|
+
if size is None:
|
|
30
|
+
return error
|
|
31
|
+
return GitLabError(f"{error} The page is {size} bytes.", resource="wiki", status=error.status, reason=error.reason)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
|
|
35
|
+
class PublishUseCase:
|
|
36
|
+
api: GitLabApi
|
|
37
|
+
settings: Settings
|
|
38
|
+
|
|
39
|
+
def __call__(self, *, project: str, slug: str, content: str) -> Published:
|
|
40
|
+
url: typing.Final = f"{self.settings.gitlab.endpoint.rstrip('/')}/{project}/-/wikis/{slug}"
|
|
41
|
+
try:
|
|
42
|
+
page = self.api.get_wiki_page(project, slug)
|
|
43
|
+
except GitLabError as exc:
|
|
44
|
+
raise _wiki_error(exc, project=project, slug=slug, size=None) from exc
|
|
45
|
+
if page.content == content:
|
|
46
|
+
return Published(url=url, updated=False)
|
|
47
|
+
try:
|
|
48
|
+
self.api.update_wiki_page(project, slug, content=content)
|
|
49
|
+
except GitLabError as exc:
|
|
50
|
+
raise _wiki_error(exc, project=project, slug=slug, size=len(content.encode())) from exc
|
|
51
|
+
return Published(url=url, updated=True)
|
|
@@ -49,9 +49,9 @@ class Settings(pydantic_settings.BaseSettings):
|
|
|
49
49
|
return self
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
def load_settings(
|
|
52
|
+
def load_settings() -> Settings:
|
|
53
53
|
try:
|
|
54
|
-
settings: typing.Final = Settings(
|
|
54
|
+
settings: typing.Final = Settings()
|
|
55
55
|
except pydantic.ValidationError as exc:
|
|
56
56
|
msg = f"Invalid configuration: {exc}"
|
|
57
57
|
raise ConfigError(msg) from exc
|
|
@@ -6,7 +6,8 @@ from modern_di import Scope, providers
|
|
|
6
6
|
|
|
7
7
|
from release_scope._gitlab import GitLabApi
|
|
8
8
|
from release_scope._jira import JiraApi
|
|
9
|
-
from release_scope.
|
|
9
|
+
from release_scope._publish import PublishUseCase
|
|
10
|
+
from release_scope._settings import Settings, load_settings
|
|
10
11
|
from release_scope._use_case import CollectUseCase
|
|
11
12
|
|
|
12
13
|
|
|
@@ -47,7 +48,7 @@ def _close_client(client: httpware.Client | None) -> None:
|
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
class SettingsGroup(modern_di.Group):
|
|
50
|
-
settings = providers.
|
|
51
|
+
settings = providers.Factory(scope=Scope.APP, creator=load_settings, cache=True)
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
class ClientsGroup(modern_di.Group):
|
|
@@ -73,6 +74,7 @@ class UseCasesGroup(modern_di.Group):
|
|
|
73
74
|
collect_use_case = providers.Factory(
|
|
74
75
|
scope=Scope.APP, creator=CollectUseCase, kwargs={"jira": ClientsGroup.jira_api}
|
|
75
76
|
)
|
|
77
|
+
publish_use_case = providers.Factory(scope=Scope.APP, creator=PublishUseCase)
|
|
76
78
|
|
|
77
79
|
|
|
78
80
|
ALL_GROUPS: typing.Final[list[type[modern_di.Group]]] = [SettingsGroup, ClientsGroup, UseCasesGroup]
|
|
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
|