cici-tools 0.2.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.
- cici-tools-0.2.0/LICENSE +21 -0
- cici-tools-0.2.0/MANIFEST.in +2 -0
- cici-tools-0.2.0/PKG-INFO +63 -0
- cici-tools-0.2.0/README.md +37 -0
- cici-tools-0.2.0/cici/__init__.py +0 -0
- cici-tools-0.2.0/cici/__main__.py +4 -0
- cici-tools-0.2.0/cici/_version.py +1 -0
- cici-tools-0.2.0/cici/cli/__init__.py +0 -0
- cici-tools-0.2.0/cici/cli/build.py +55 -0
- cici-tools-0.2.0/cici/cli/bundle.py +104 -0
- cici-tools-0.2.0/cici/cli/fmt.py +30 -0
- cici-tools-0.2.0/cici/cli/update.py +112 -0
- cici-tools-0.2.0/cici/constants.py +26 -0
- cici-tools-0.2.0/cici/main.py +17 -0
- cici-tools-0.2.0/cici/providers/__init__.py +0 -0
- cici-tools-0.2.0/cici/providers/gitlab/__init__.py +3 -0
- cici-tools-0.2.0/cici/providers/gitlab/constants.py +77 -0
- cici-tools-0.2.0/cici/providers/gitlab/converter.py +203 -0
- cici-tools-0.2.0/cici/providers/gitlab/models.py +223 -0
- cici-tools-0.2.0/cici/providers/gitlab/serializers.py +115 -0
- cici-tools-0.2.0/cici/providers/gitlab/utils.py +26 -0
- cici-tools-0.2.0/cici/schema/LICENSE.gitlab +28 -0
- cici-tools-0.2.0/cici/schema/__init__.py +0 -0
- cici-tools-0.2.0/cici/schema/gitlab-ci.json +1842 -0
- cici-tools-0.2.0/cici/utils.py +60 -0
- cici-tools-0.2.0/cici_tools.egg-info/PKG-INFO +63 -0
- cici-tools-0.2.0/cici_tools.egg-info/SOURCES.txt +32 -0
- cici-tools-0.2.0/cici_tools.egg-info/dependency_links.txt +1 -0
- cici-tools-0.2.0/cici_tools.egg-info/entry_points.txt +3 -0
- cici-tools-0.2.0/cici_tools.egg-info/requires.txt +6 -0
- cici-tools-0.2.0/cici_tools.egg-info/top_level.txt +1 -0
- cici-tools-0.2.0/setup.cfg +7 -0
- cici-tools-0.2.0/setup.py +44 -0
cici-tools-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 BrettOps Inc
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: cici-tools
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Power tools for CI/CD.
|
|
5
|
+
Home-page: https://gitlab.com/brettops/tools/cici
|
|
6
|
+
Author: Brett Weir
|
|
7
|
+
Author-email: brett@brettops.io
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: ci pipeline python
|
|
10
|
+
Platform: UNKNOWN
|
|
11
|
+
Classifier: Development Status :: 1 - Planning
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Requires-Python: >=3.6
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
|
|
25
|
+
# cici-tools
|
|
26
|
+
|
|
27
|
+
<!-- BADGIE TIME -->
|
|
28
|
+
|
|
29
|
+
[](https://brettops.io)
|
|
30
|
+
[](https://gitlab.com/brettops/tools/cici/-/commits/main)
|
|
31
|
+
[](https://github.com/pre-commit/pre-commit)
|
|
32
|
+
[](https://github.com/psf/black)
|
|
33
|
+
[](https://pycqa.github.io/isort/)
|
|
34
|
+
[](https://github.com/prettier/prettier)
|
|
35
|
+
|
|
36
|
+
<!-- END BADGIE TIME -->
|
|
37
|
+
|
|
38
|
+
> **WARNING:** `cici` is experimental and I can't even decide on a name for it.
|
|
39
|
+
> Stay away!
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### `bundle`
|
|
44
|
+
|
|
45
|
+
Flatten `extends` keywords to make zero-dependency GitLab CI/CD files.
|
|
46
|
+
|
|
47
|
+
### `fmt`
|
|
48
|
+
|
|
49
|
+
Normalize the style of your GitLab CI/CD files:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cici fmt
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### `update`
|
|
56
|
+
|
|
57
|
+
Update to the latest GitLab CI/CD `include` versions available.
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
cici update
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# cici-tools
|
|
2
|
+
|
|
3
|
+
<!-- BADGIE TIME -->
|
|
4
|
+
|
|
5
|
+
[](https://brettops.io)
|
|
6
|
+
[](https://gitlab.com/brettops/tools/cici/-/commits/main)
|
|
7
|
+
[](https://github.com/pre-commit/pre-commit)
|
|
8
|
+
[](https://github.com/psf/black)
|
|
9
|
+
[](https://pycqa.github.io/isort/)
|
|
10
|
+
[](https://github.com/prettier/prettier)
|
|
11
|
+
|
|
12
|
+
<!-- END BADGIE TIME -->
|
|
13
|
+
|
|
14
|
+
> **WARNING:** `cici` is experimental and I can't even decide on a name for it.
|
|
15
|
+
> Stay away!
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### `bundle`
|
|
20
|
+
|
|
21
|
+
Flatten `extends` keywords to make zero-dependency GitLab CI/CD files.
|
|
22
|
+
|
|
23
|
+
### `fmt`
|
|
24
|
+
|
|
25
|
+
Normalize the style of your GitLab CI/CD files:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cici fmt
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### `update`
|
|
32
|
+
|
|
33
|
+
Update to the latest GitLab CI/CD `include` versions available.
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
cici update
|
|
37
|
+
```
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.0"
|
|
File without changes
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
from importlib import import_module
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from ..constants import DEFAULT_PROVIDER, PROVIDERS
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def build_command(parser, args):
|
|
10
|
+
logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s")
|
|
11
|
+
|
|
12
|
+
input_provider = import_module(f".{args.input_format}", "cici.providers")
|
|
13
|
+
output_provider = import_module(f".{args.output_format}", "cici.providers")
|
|
14
|
+
|
|
15
|
+
if not args.filename:
|
|
16
|
+
args.filename = input_provider.CI_FILE
|
|
17
|
+
|
|
18
|
+
if not Path(args.filename).exists():
|
|
19
|
+
parser.error(f"file not found: {args.filename}")
|
|
20
|
+
|
|
21
|
+
file = input_provider.load(args.filename)
|
|
22
|
+
output_provider.dump(file, sys.stdout)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def build_parser(subparsers):
|
|
26
|
+
parser = subparsers.add_parser(
|
|
27
|
+
"build", help="build BrettOps CI file into target format"
|
|
28
|
+
)
|
|
29
|
+
parser.add_argument("filename", nargs="?")
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"-f",
|
|
32
|
+
"--from",
|
|
33
|
+
dest="input_format",
|
|
34
|
+
choices=PROVIDERS,
|
|
35
|
+
default=DEFAULT_PROVIDER,
|
|
36
|
+
help=f"input format [{DEFAULT_PROVIDER}]",
|
|
37
|
+
)
|
|
38
|
+
parser.add_argument(
|
|
39
|
+
"-t",
|
|
40
|
+
"--to",
|
|
41
|
+
dest="output_format",
|
|
42
|
+
choices=PROVIDERS,
|
|
43
|
+
default=DEFAULT_PROVIDER,
|
|
44
|
+
help=f"output format [{DEFAULT_PROVIDER}]",
|
|
45
|
+
)
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"-o",
|
|
48
|
+
"--output",
|
|
49
|
+
metavar="DIR",
|
|
50
|
+
dest="output_path",
|
|
51
|
+
type=Path,
|
|
52
|
+
default=Path.cwd().absolute(),
|
|
53
|
+
)
|
|
54
|
+
parser.set_defaults(func=build_command)
|
|
55
|
+
return parser
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import logging
|
|
3
|
+
from importlib import import_module
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from termcolor import colored
|
|
8
|
+
|
|
9
|
+
from ..constants import CONFIG_DIR_NAME, DEFAULT_PROVIDER
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_job_prefix(pipeline_name: str, job_name: str) -> Optional[str]:
|
|
13
|
+
if job_name.startswith("."):
|
|
14
|
+
return None
|
|
15
|
+
return f"{pipeline_name}-"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def parse_groups(name, file, groups):
|
|
19
|
+
if groups:
|
|
20
|
+
groups = [group.strip() for group in groups.split(",")]
|
|
21
|
+
|
|
22
|
+
if not groups:
|
|
23
|
+
group_names = set()
|
|
24
|
+
for job_name in file.jobs.keys():
|
|
25
|
+
if job_name.startswith("."):
|
|
26
|
+
continue
|
|
27
|
+
group_name = job_name[len(f"{name}-") :]
|
|
28
|
+
group_name = group_name.split("-")[0]
|
|
29
|
+
group_names.add(group_name)
|
|
30
|
+
groups = sorted(list(group_names))
|
|
31
|
+
return groups
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def bundle_command(parser, args):
|
|
35
|
+
logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s")
|
|
36
|
+
print(colored("pipeline name:", color="yellow"), args.pipeline_name)
|
|
37
|
+
|
|
38
|
+
provider = import_module(f".{DEFAULT_PROVIDER}", "cici.providers")
|
|
39
|
+
|
|
40
|
+
ci_file_path = args.config_path / provider.CI_FILE
|
|
41
|
+
|
|
42
|
+
if not Path(ci_file_path).exists():
|
|
43
|
+
parser.error(f"file not found: {ci_file_path}")
|
|
44
|
+
|
|
45
|
+
file = provider.load(ci_file_path)
|
|
46
|
+
|
|
47
|
+
args.output_path = Path(args.output_path)
|
|
48
|
+
args.groups = parse_groups(args.pipeline_name, file, args.groups)
|
|
49
|
+
print(colored("bundle names:", color="yellow"), args.groups)
|
|
50
|
+
|
|
51
|
+
for bundle_name in args.groups:
|
|
52
|
+
pattern = f"{args.pipeline_name}-{bundle_name}"
|
|
53
|
+
|
|
54
|
+
bundle = copy.deepcopy(file)
|
|
55
|
+
bundle.jobs = {}
|
|
56
|
+
|
|
57
|
+
for job_name, job in file.jobs.items():
|
|
58
|
+
job_prefix = get_job_prefix(
|
|
59
|
+
pipeline_name=args.pipeline_name,
|
|
60
|
+
job_name=job_name,
|
|
61
|
+
)
|
|
62
|
+
if not job_prefix:
|
|
63
|
+
continue
|
|
64
|
+
assert job_name.startswith(job_prefix)
|
|
65
|
+
if job_name.startswith(pattern):
|
|
66
|
+
bundle.jobs[job_name] = job
|
|
67
|
+
|
|
68
|
+
bundle_filename = args.output_path / f"{bundle_name}.yml"
|
|
69
|
+
|
|
70
|
+
with open(bundle_filename, "w") as stream:
|
|
71
|
+
provider.dump(bundle, stream)
|
|
72
|
+
print(colored("created", "magenta"), bundle_filename.name)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def bundle_parser(subparsers):
|
|
76
|
+
parser = subparsers.add_parser(
|
|
77
|
+
"bundle", help="distill a CI file to a job and its dependencies"
|
|
78
|
+
)
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"config_path",
|
|
81
|
+
metavar="DIR",
|
|
82
|
+
nargs="?",
|
|
83
|
+
type=Path,
|
|
84
|
+
default=(Path.cwd() / CONFIG_DIR_NAME).absolute(),
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument("-g", "--groups", help="job group patterns")
|
|
87
|
+
parser.add_argument(
|
|
88
|
+
"-o",
|
|
89
|
+
"--output",
|
|
90
|
+
metavar="DIR",
|
|
91
|
+
dest="output_path",
|
|
92
|
+
type=Path,
|
|
93
|
+
default=Path.cwd().absolute(),
|
|
94
|
+
)
|
|
95
|
+
parser.add_argument(
|
|
96
|
+
"-n",
|
|
97
|
+
"--name",
|
|
98
|
+
metavar="DIR",
|
|
99
|
+
dest="pipeline_name",
|
|
100
|
+
default=str(Path.cwd().name),
|
|
101
|
+
help="the name of the pipeline",
|
|
102
|
+
)
|
|
103
|
+
parser.set_defaults(func=bundle_command)
|
|
104
|
+
return parser
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from importlib import import_module
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from termcolor import colored
|
|
5
|
+
|
|
6
|
+
from ..constants import DEFAULT_PROVIDER
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def fmt_command(parser, args):
|
|
10
|
+
provider = import_module(f".{DEFAULT_PROVIDER}", "cici.providers")
|
|
11
|
+
|
|
12
|
+
if not args.filenames:
|
|
13
|
+
args.filenames = [provider.CI_FILE]
|
|
14
|
+
|
|
15
|
+
for filename in args.filenames:
|
|
16
|
+
if not Path(filename).exists():
|
|
17
|
+
parser.error(f"file not found: {filename}")
|
|
18
|
+
|
|
19
|
+
for filename in args.filenames:
|
|
20
|
+
file = provider.load(filename)
|
|
21
|
+
with open(filename, "w") as stream:
|
|
22
|
+
provider.dump(file, stream)
|
|
23
|
+
print(colored(filename, "magenta"), "formatted")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def fmt_parser(subparsers):
|
|
27
|
+
parser = subparsers.add_parser("fmt", help="Reformat CI file")
|
|
28
|
+
parser.add_argument("filenames", metavar="FILE", nargs="*")
|
|
29
|
+
parser.set_defaults(func=fmt_command)
|
|
30
|
+
return parser
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import urllib.error
|
|
4
|
+
import urllib.parse
|
|
5
|
+
import urllib.request
|
|
6
|
+
|
|
7
|
+
import ruamel.yaml
|
|
8
|
+
from termcolor import colored
|
|
9
|
+
|
|
10
|
+
GITLAB_URL = "https://gitlab.com"
|
|
11
|
+
API_V4_URL = f"{GITLAB_URL}/api/v4"
|
|
12
|
+
|
|
13
|
+
HEADERS: dict[str, str] = {}
|
|
14
|
+
private_token = os.environ.get("GITLAB_PRIVATE_TOKEN")
|
|
15
|
+
if private_token:
|
|
16
|
+
HEADERS.update({"PRIVATE-TOKEN": private_token})
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def to_fragment(text):
|
|
20
|
+
if not isinstance(text, str):
|
|
21
|
+
return text
|
|
22
|
+
return urllib.parse.quote(text, safe="")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_apiv4_url(url):
|
|
26
|
+
try:
|
|
27
|
+
url = f"{API_V4_URL}{url}"
|
|
28
|
+
request = urllib.request.Request(url=url, headers=HEADERS)
|
|
29
|
+
response = urllib.request.urlopen(request)
|
|
30
|
+
content = response.read()
|
|
31
|
+
return json.loads(content)
|
|
32
|
+
except urllib.error.HTTPError:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_project(project_id):
|
|
37
|
+
return get_apiv4_url(f"/projects/{to_fragment(project_id)}")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_latest_release(project_id):
|
|
41
|
+
return get_apiv4_url(
|
|
42
|
+
f"/projects/{to_fragment(project_id)}/releases/permalink/latest"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def cproject(project_name):
|
|
47
|
+
return colored(project_name, "magenta")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def ctag(tag_name):
|
|
51
|
+
return colored(tag_name, "yellow", attrs=["bold"])
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def update_include(include):
|
|
55
|
+
if any(key not in include for key in ("project", "file")):
|
|
56
|
+
return include
|
|
57
|
+
|
|
58
|
+
project = get_project(include["project"])
|
|
59
|
+
project_name = project["path_with_namespace"]
|
|
60
|
+
|
|
61
|
+
latest_release = get_latest_release(project["id"])
|
|
62
|
+
if latest_release:
|
|
63
|
+
latest_tag = latest_release["tag_name"]
|
|
64
|
+
current_tag = include.get("ref", None)
|
|
65
|
+
if current_tag:
|
|
66
|
+
if current_tag != latest_tag:
|
|
67
|
+
print(
|
|
68
|
+
colored(project_name, "red", attrs=["bold"]),
|
|
69
|
+
"updated from {current} to {latest}".format(
|
|
70
|
+
current=ctag(current_tag),
|
|
71
|
+
latest=ctag(latest_tag),
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
else:
|
|
75
|
+
print(cproject(project_name), "is the latest at", ctag(current_tag))
|
|
76
|
+
elif not current_tag:
|
|
77
|
+
print(cproject(project_name), "pinned to", ctag(latest_tag))
|
|
78
|
+
include["ref"] = latest_tag
|
|
79
|
+
else:
|
|
80
|
+
print(cproject(project_name), "has no releases")
|
|
81
|
+
newinclude = {}
|
|
82
|
+
newinclude["project"] = include["project"]
|
|
83
|
+
if "ref" in include:
|
|
84
|
+
newinclude["ref"] = include["ref"]
|
|
85
|
+
newinclude["file"] = include["file"]
|
|
86
|
+
return newinclude
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def update_includes(includes):
|
|
90
|
+
if not isinstance(includes, list):
|
|
91
|
+
return includes
|
|
92
|
+
|
|
93
|
+
return [update_include(include) for include in includes]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def update_command(parser, args):
|
|
97
|
+
yaml = ruamel.yaml.YAML()
|
|
98
|
+
data = yaml.load(open(args.filename))
|
|
99
|
+
|
|
100
|
+
if "include" in data:
|
|
101
|
+
data["include"] = update_includes(data["include"])
|
|
102
|
+
|
|
103
|
+
with open(args.filename, "w") as handle:
|
|
104
|
+
yaml.indent(mapping=2, sequence=4, offset=2)
|
|
105
|
+
yaml.dump(data, handle)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def update_parser(subparsers):
|
|
109
|
+
parser = subparsers.add_parser("update")
|
|
110
|
+
parser.add_argument("filename", nargs="?", default=".gitlab-ci.yml")
|
|
111
|
+
parser.set_defaults(func=update_command)
|
|
112
|
+
return parser
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
BASE_DIR = Path(__file__).parent.absolute()
|
|
4
|
+
|
|
5
|
+
SCHEMA_DIR = BASE_DIR / "schema"
|
|
6
|
+
|
|
7
|
+
COMMAND_DIR = BASE_DIR / "cli"
|
|
8
|
+
|
|
9
|
+
COMMANDS = sorted(
|
|
10
|
+
[path.stem for path in COMMAND_DIR.glob("*.py") if not path.stem.startswith("_")]
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
PROVIDER_DIR = BASE_DIR / "providers"
|
|
14
|
+
|
|
15
|
+
PROVIDERS = sorted(
|
|
16
|
+
[path.stem for path in PROVIDER_DIR.glob("*.py") if not path.stem.startswith("_")]
|
|
17
|
+
+ [
|
|
18
|
+
path.stem
|
|
19
|
+
for path in PROVIDER_DIR.glob("*/")
|
|
20
|
+
if path.is_dir() and not path.stem.startswith("_")
|
|
21
|
+
]
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
DEFAULT_PROVIDER = PROVIDERS[0]
|
|
25
|
+
|
|
26
|
+
CONFIG_DIR_NAME = ".cici"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from importlib import import_module
|
|
3
|
+
|
|
4
|
+
from .constants import COMMANDS
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main():
|
|
8
|
+
parser = argparse.ArgumentParser()
|
|
9
|
+
|
|
10
|
+
subparsers = parser.add_subparsers(required=True)
|
|
11
|
+
|
|
12
|
+
for command_name in COMMANDS:
|
|
13
|
+
command = import_module(f".{command_name}", "cici.cli")
|
|
14
|
+
getattr(command, f"{command_name}_parser")(subparsers=subparsers)
|
|
15
|
+
|
|
16
|
+
args = parser.parse_args()
|
|
17
|
+
args.func(parser=parser, args=args)
|
|
File without changes
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
ACCESS = "access"
|
|
2
|
+
ALWAYS = "always"
|
|
3
|
+
DEVELOPMENT = "development"
|
|
4
|
+
IF_NOT_PRESENT = "if-not-present"
|
|
5
|
+
NEVER = "never"
|
|
6
|
+
ON_SUCCESS = "on_success"
|
|
7
|
+
ON_FAILURE = "on_failure"
|
|
8
|
+
OTHER = "other"
|
|
9
|
+
PREPARE = "prepare"
|
|
10
|
+
PRODUCTION = "production"
|
|
11
|
+
PULL = "pull"
|
|
12
|
+
PULL_PUSH = "pull-push"
|
|
13
|
+
PUSH = "push"
|
|
14
|
+
STAGING = "staging"
|
|
15
|
+
START = "start"
|
|
16
|
+
STOP = "stop"
|
|
17
|
+
TESTING = "testing"
|
|
18
|
+
VERIFY = "verify"
|
|
19
|
+
|
|
20
|
+
CACHE_POLICIES = (PULL, PUSH, PULL_PUSH)
|
|
21
|
+
|
|
22
|
+
DEPLOYMENT_TIERS = (
|
|
23
|
+
PRODUCTION,
|
|
24
|
+
STAGING,
|
|
25
|
+
TESTING,
|
|
26
|
+
DEVELOPMENT,
|
|
27
|
+
OTHER,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
ENVIRONMENT_ACTIONS = (
|
|
31
|
+
START,
|
|
32
|
+
PREPARE,
|
|
33
|
+
STOP,
|
|
34
|
+
VERIFY,
|
|
35
|
+
ACCESS,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
PULL_POLICIES = (
|
|
39
|
+
ALWAYS,
|
|
40
|
+
IF_NOT_PRESENT,
|
|
41
|
+
NEVER,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
WHEN_CHOICES = (ON_SUCCESS, ON_FAILURE, ALWAYS)
|
|
45
|
+
|
|
46
|
+
RETRY_MAX_CHOICES = (0, 1, 2)
|
|
47
|
+
|
|
48
|
+
UNKNOWN_FAILURE = "unknown_failure"
|
|
49
|
+
SCRIPT_FAILURE = "script_failure"
|
|
50
|
+
API_FAILURE = "api_failure"
|
|
51
|
+
STUCK_OR_TIMEOUT_FAILURE = "stuck_or_timeout_failure"
|
|
52
|
+
RUNNER_SYSTEM_FAILURE = "runner_system_failure"
|
|
53
|
+
RUNNER_UNSUPPORTED = "runner_unsupported"
|
|
54
|
+
STALE_SCHEDULE = "stale_schedule"
|
|
55
|
+
JOB_EXECUTION_TIMEOUT = "job_execution_timeout"
|
|
56
|
+
ARCHIVED_FAILURE = "archived_failure"
|
|
57
|
+
UNMET_PREREQUISITES = "unmet_prerequisites"
|
|
58
|
+
SCHEDULER_FAILURE = "scheduler_failure"
|
|
59
|
+
DATA_INTEGRITY_FAILURE = "data_integrity_failure"
|
|
60
|
+
|
|
61
|
+
RETRY_WHEN_CHOICES = (
|
|
62
|
+
ALWAYS,
|
|
63
|
+
UNKNOWN_FAILURE,
|
|
64
|
+
SCRIPT_FAILURE,
|
|
65
|
+
API_FAILURE,
|
|
66
|
+
STUCK_OR_TIMEOUT_FAILURE,
|
|
67
|
+
RUNNER_SYSTEM_FAILURE,
|
|
68
|
+
RUNNER_UNSUPPORTED,
|
|
69
|
+
STALE_SCHEDULE,
|
|
70
|
+
JOB_EXECUTION_TIMEOUT,
|
|
71
|
+
ARCHIVED_FAILURE,
|
|
72
|
+
UNMET_PREREQUISITES,
|
|
73
|
+
SCHEDULER_FAILURE,
|
|
74
|
+
DATA_INTEGRITY_FAILURE,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
CI_FILE = ".gitlab-ci.yml"
|