csspin-python 2.0.0__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.
- csspin_python/aws_auth.py +195 -0
- csspin_python/aws_auth_schema.yaml +38 -0
- csspin_python/behave.py +150 -0
- csspin_python/behave_schema.yaml +39 -0
- csspin_python/debugpy.py +32 -0
- csspin_python/debugpy_schema.yaml +14 -0
- csspin_python/devpi.py +82 -0
- csspin_python/devpi_schema.yaml +17 -0
- csspin_python/playwright.py +126 -0
- csspin_python/playwright_schema.yaml +33 -0
- csspin_python/pytest.py +97 -0
- csspin_python/pytest_schema.yaml +27 -0
- csspin_python/python.py +970 -0
- csspin_python/python_schema.yaml +131 -0
- csspin_python/radon.py +59 -0
- csspin_python/radon_schema.yaml +17 -0
- csspin_python-2.0.0.dist-info/METADATA +109 -0
- csspin_python-2.0.0.dist-info/RECORD +21 -0
- csspin_python-2.0.0.dist-info/WHEEL +5 -0
- csspin_python-2.0.0.dist-info/licenses/LICENSE +176 -0
- csspin_python-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# -*- mode: python; coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2025 CONTACT Software GmbH
|
|
4
|
+
# https://www.contact-software.com/
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
"""Module implementing the aws_auth plugin for spin"""
|
|
20
|
+
|
|
21
|
+
import configparser
|
|
22
|
+
import os
|
|
23
|
+
|
|
24
|
+
from csspin import Path, config, debug, die, exists, info, interpolate1
|
|
25
|
+
|
|
26
|
+
defaults = config(
|
|
27
|
+
aws_role_arn="arn:aws:iam::373369985286:role/cs-central1-codeartifact-ecr-read-role",
|
|
28
|
+
aws_region="eu-central-1",
|
|
29
|
+
aws_role_session_name="CodeArtifactSession",
|
|
30
|
+
aws_codeartifact_domain="contact",
|
|
31
|
+
aws_key_duration=3600,
|
|
32
|
+
keycloak_url="https://login.contact-cloud.com/realms/contact/protocol/openid-connect/token",
|
|
33
|
+
client_id="central1-auth-oidc-read",
|
|
34
|
+
requires=config(
|
|
35
|
+
spin=[
|
|
36
|
+
"csspin_python.python",
|
|
37
|
+
],
|
|
38
|
+
),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def configure(cfg): # pylint: disable=too-many-statements
|
|
43
|
+
"""Configure the plugin and apply changes to the configuration tree"""
|
|
44
|
+
# Could be useful in CI e.g. when you want to build docs
|
|
45
|
+
# and need to include this plugin in spinfile
|
|
46
|
+
# without using it's functionality
|
|
47
|
+
if os.environ.get("AWS_AUTH_DISABLE"):
|
|
48
|
+
info("AWS_AUTH_DISABLE is set, ignoring aws_auth plugin")
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
from sys import platform
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
import boto3
|
|
55
|
+
import requests
|
|
56
|
+
from botocore.exceptions import ClientError
|
|
57
|
+
except ImportError:
|
|
58
|
+
die(
|
|
59
|
+
"Failed to import required modules. Please install them by setting:"
|
|
60
|
+
"\n\tplugin_packages:\n\t\t- csspin_python[aws_auth]\n"
|
|
61
|
+
"in your project's spinfile.yaml"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
cfg.aws_auth.client_secret = os.environ.get("KEYCLOAK_CLIENT_SECRET")
|
|
65
|
+
if not cfg.aws_auth.client_secret:
|
|
66
|
+
die(
|
|
67
|
+
"Neither aws_auth.client_secret config"
|
|
68
|
+
"entry nor KEYCLOAK_CLIENT_SECRET environment variable was found."
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
def get_keycloak_access_token(keycloak_url, client_id, client_secret):
|
|
72
|
+
"""
|
|
73
|
+
Obtain the Keycloak access token using client credentials.
|
|
74
|
+
"""
|
|
75
|
+
debug("Requesting Keycloak access token...")
|
|
76
|
+
payload = {
|
|
77
|
+
"grant_type": "client_credentials",
|
|
78
|
+
"client_id": client_id,
|
|
79
|
+
"client_secret": client_secret,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
response = requests.post(keycloak_url, data=payload, timeout=15)
|
|
84
|
+
response.raise_for_status()
|
|
85
|
+
data = response.json()
|
|
86
|
+
access_token = data.get("access_token")
|
|
87
|
+
if not access_token:
|
|
88
|
+
raise ValueError("Response doesn't contain access_token")
|
|
89
|
+
except (ValueError, requests.exceptions.RequestException) as e:
|
|
90
|
+
die(f"Failed to fetch Keycloak access token: {e}")
|
|
91
|
+
|
|
92
|
+
return access_token
|
|
93
|
+
|
|
94
|
+
def assume_aws_role_with_web_identity(
|
|
95
|
+
keycloak_access_token,
|
|
96
|
+
role_arn,
|
|
97
|
+
role_session_name,
|
|
98
|
+
region,
|
|
99
|
+
key_duration_seconds,
|
|
100
|
+
):
|
|
101
|
+
"""
|
|
102
|
+
Request AWS STS credentials using the Keycloak token as a web identity.
|
|
103
|
+
"""
|
|
104
|
+
debug("Requesting AWS STS credentials...")
|
|
105
|
+
sts_client = boto3.client("sts", region_name=region)
|
|
106
|
+
try:
|
|
107
|
+
sts_response = sts_client.assume_role_with_web_identity(
|
|
108
|
+
RoleArn=role_arn,
|
|
109
|
+
RoleSessionName=role_session_name,
|
|
110
|
+
WebIdentityToken=keycloak_access_token,
|
|
111
|
+
DurationSeconds=key_duration_seconds,
|
|
112
|
+
)
|
|
113
|
+
credentials = sts_response.get("Credentials", {})
|
|
114
|
+
if not (
|
|
115
|
+
credentials.get("AccessKeyId")
|
|
116
|
+
and credentials.get("SecretAccessKey")
|
|
117
|
+
and credentials.get("SessionToken")
|
|
118
|
+
):
|
|
119
|
+
raise ValueError("Incomplete AWS credentials received")
|
|
120
|
+
except (ValueError, ClientError) as e:
|
|
121
|
+
die(f"Failed to assume AWS role with web identity: {e}")
|
|
122
|
+
|
|
123
|
+
return credentials
|
|
124
|
+
|
|
125
|
+
def get_codeartifact_auth_token(credentials, domain, region):
|
|
126
|
+
"""
|
|
127
|
+
Retrieve the AWS CodeArtifact authentication token using temporary AWS credentials.
|
|
128
|
+
"""
|
|
129
|
+
debug("Requesting CodeArtifact authentication token...")
|
|
130
|
+
codeartifact_client = boto3.client(
|
|
131
|
+
"codeartifact",
|
|
132
|
+
region_name=region,
|
|
133
|
+
aws_access_key_id=credentials.get("AccessKeyId"),
|
|
134
|
+
aws_secret_access_key=credentials.get("SecretAccessKey"),
|
|
135
|
+
aws_session_token=credentials.get("SessionToken"),
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
response = codeartifact_client.get_authorization_token(domain=domain)
|
|
140
|
+
auth_token = response.get("authorizationToken")
|
|
141
|
+
if not auth_token:
|
|
142
|
+
raise ValueError("Failed to retrieve CodeArtifact authentication token")
|
|
143
|
+
except (ValueError, ClientError) as e:
|
|
144
|
+
die(f"Failed to retrieve CodeArtifact authentication token: {e}")
|
|
145
|
+
|
|
146
|
+
return auth_token
|
|
147
|
+
|
|
148
|
+
keycloak_access_token = get_keycloak_access_token(
|
|
149
|
+
cfg.aws_auth.keycloak_url, cfg.aws_auth.client_id, cfg.aws_auth.client_secret
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
credentials = assume_aws_role_with_web_identity(
|
|
153
|
+
keycloak_access_token,
|
|
154
|
+
cfg.aws_auth.aws_role_arn,
|
|
155
|
+
cfg.aws_auth.aws_role_session_name,
|
|
156
|
+
cfg.aws_auth.aws_region,
|
|
157
|
+
cfg.aws_auth.aws_key_duration,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
codeartifact_auth_token = get_codeartifact_auth_token(
|
|
161
|
+
credentials, cfg.aws_auth.aws_codeartifact_domain, cfg.aws_auth.aws_region
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
domain_owner = cfg.aws_auth.aws_role_arn.split(":")[4]
|
|
165
|
+
|
|
166
|
+
cfg.aws_auth.codeartifact_auth_token = codeartifact_auth_token
|
|
167
|
+
cfg.python.index_url = (
|
|
168
|
+
f"https://aws:{codeartifact_auth_token}@"
|
|
169
|
+
f"{cfg.aws_auth.aws_codeartifact_domain}-{domain_owner}"
|
|
170
|
+
f".d.codeartifact.{cfg.aws_auth.aws_region}.amazonaws.com/pypi/elements/simple/"
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
pipconf = interpolate1(cfg.python.venv) / Path(
|
|
174
|
+
"pip.ini" if platform == "win32" else "pip.conf"
|
|
175
|
+
)
|
|
176
|
+
if exists(pipconf):
|
|
177
|
+
# Need to update pip.conf with the new index_url
|
|
178
|
+
# for "spin run pip ..." to use the right index and
|
|
179
|
+
# not the default one
|
|
180
|
+
_update_pipconf_url(pipconf, cfg.python.index_url)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _update_pipconf_url(filename, url):
|
|
184
|
+
"""Upates the python.index_url in the pip.conf file with the new value"""
|
|
185
|
+
info(f"Updating python.index_url in {filename} with a fresh token...")
|
|
186
|
+
config_parser = configparser.ConfigParser()
|
|
187
|
+
config_parser.read(filename)
|
|
188
|
+
if not config_parser.has_section("global"):
|
|
189
|
+
config_parser.add_section("global")
|
|
190
|
+
option = (
|
|
191
|
+
"index-url" if config_parser.has_option("global", "index-url") else "index_url"
|
|
192
|
+
)
|
|
193
|
+
config_parser.set("global", option, url)
|
|
194
|
+
with open(filename, mode="w", encoding="utf-8") as f:
|
|
195
|
+
config_parser.write(f)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# -*- mode: yaml; coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Schema of the aws_auth plugin for spin
|
|
4
|
+
|
|
5
|
+
aws_auth:
|
|
6
|
+
type: object
|
|
7
|
+
help: |
|
|
8
|
+
Configuration for the aws_auth plugin in spin.
|
|
9
|
+
This plugin handles authentication with AWS and retrieves
|
|
10
|
+
secret keys from AWS CodeArtifact.
|
|
11
|
+
properties:
|
|
12
|
+
aws_role_arn:
|
|
13
|
+
type: str
|
|
14
|
+
help: The ARN of the AWS IAM role to assume for authentication.
|
|
15
|
+
aws_region:
|
|
16
|
+
type: str
|
|
17
|
+
help: The AWS region where the CodeArtifact repository is located.
|
|
18
|
+
role_session_name:
|
|
19
|
+
type: str
|
|
20
|
+
help: The name for the AWS STS session when assuming a role.
|
|
21
|
+
aws_codeartifact_domain:
|
|
22
|
+
type: str
|
|
23
|
+
help: The domain name of the AWS CodeArtifact repository.
|
|
24
|
+
aws_key_duration:
|
|
25
|
+
type: int
|
|
26
|
+
help: The duration in seconds for which the temporary key will be valid.
|
|
27
|
+
keycloak_url:
|
|
28
|
+
type: str
|
|
29
|
+
help: The URL of the Keycloak authentication server.
|
|
30
|
+
client_id:
|
|
31
|
+
type: str
|
|
32
|
+
help: The client ID for authentication with Keycloak.
|
|
33
|
+
client_secret:
|
|
34
|
+
type: str
|
|
35
|
+
help: The client secret for authentication with Keycloak.
|
|
36
|
+
codeartifact_auth_token:
|
|
37
|
+
type: str
|
|
38
|
+
help: The CodeArtifact auth token.
|
csspin_python/behave.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# -*- mode: python; coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2022 CONTACT Software GmbH
|
|
4
|
+
# https://www.contact-software.com
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
"""Module implementing the behave plugin for spin"""
|
|
20
|
+
|
|
21
|
+
import contextlib
|
|
22
|
+
import sys
|
|
23
|
+
from typing import Generator
|
|
24
|
+
|
|
25
|
+
from csspin import config, die, info, option, rmtree, setenv, sh, task, writetext
|
|
26
|
+
from csspin.tree import ConfigTree
|
|
27
|
+
from path import Path
|
|
28
|
+
|
|
29
|
+
defaults = config(
|
|
30
|
+
# Exclude the flaky tests in the defaults for now.
|
|
31
|
+
# Will switch the default back to True as soon as
|
|
32
|
+
# we have an easy way to set this in the CI.
|
|
33
|
+
flaky=False,
|
|
34
|
+
coverage=False,
|
|
35
|
+
cov_report="python-at-coverage.xml",
|
|
36
|
+
cov_config="setup.cfg",
|
|
37
|
+
# Default to concise and readable output
|
|
38
|
+
opts=[
|
|
39
|
+
"--no-source",
|
|
40
|
+
"--tags=~skip",
|
|
41
|
+
"--format=pretty",
|
|
42
|
+
"--no-skipped",
|
|
43
|
+
],
|
|
44
|
+
report=config(
|
|
45
|
+
name="cept_test_results.json",
|
|
46
|
+
format="json.pretty",
|
|
47
|
+
),
|
|
48
|
+
# This is the default location of behave tests
|
|
49
|
+
tests=["tests/accepttests"],
|
|
50
|
+
requires=config(
|
|
51
|
+
spin=[
|
|
52
|
+
"csspin_python.python",
|
|
53
|
+
],
|
|
54
|
+
python=[
|
|
55
|
+
"behave",
|
|
56
|
+
"coverage",
|
|
57
|
+
],
|
|
58
|
+
),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def configure(cfg: ConfigTree) -> None:
|
|
63
|
+
"""Add some runtime-dependent options"""
|
|
64
|
+
if sys.platform == "win32":
|
|
65
|
+
cfg.behave.opts.append("--tags=~linux")
|
|
66
|
+
else:
|
|
67
|
+
cfg.behave.opts.append("--tags=~windows")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def create_coverage_pth(cfg: ConfigTree) -> str: # pylint: disable=unused-argument
|
|
71
|
+
"""Creating the coverage path file and returning its path"""
|
|
72
|
+
coverage_pth_path = cfg.python.site_packages / "coverage.pth"
|
|
73
|
+
info(f"Create {coverage_pth_path}")
|
|
74
|
+
writetext(coverage_pth_path, "import coverage; coverage.process_startup()")
|
|
75
|
+
return coverage_pth_path
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@contextlib.contextmanager
|
|
79
|
+
def with_coverage(cfg: ConfigTree) -> Generator:
|
|
80
|
+
"""Context-manager enabling to run coverage"""
|
|
81
|
+
coverage_pth = ""
|
|
82
|
+
try:
|
|
83
|
+
|
|
84
|
+
sh("coverage", "erase", check=False)
|
|
85
|
+
setenv(COVERAGE_PROCESS_START=cfg.behave.cov_config)
|
|
86
|
+
coverage_pth = create_coverage_pth(cfg)
|
|
87
|
+
yield
|
|
88
|
+
finally:
|
|
89
|
+
setenv(COVERAGE_PROCESS_START=None)
|
|
90
|
+
rmtree(coverage_pth)
|
|
91
|
+
sh("coverage", "combine", check=False)
|
|
92
|
+
sh("coverage", "report", check=False)
|
|
93
|
+
sh("coverage", "xml", "-o", cfg.behave.cov_report, check=False)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@task(when="cept")
|
|
97
|
+
def behave( # pylint: disable=too-many-arguments,too-many-positional-arguments
|
|
98
|
+
cfg,
|
|
99
|
+
instance: option(
|
|
100
|
+
"-i", # noqa: F821
|
|
101
|
+
"--instance", # noqa: F821
|
|
102
|
+
help="Directory of the CONTACT Elements instance.", # noqa: F722
|
|
103
|
+
),
|
|
104
|
+
coverage: option(
|
|
105
|
+
"-c", # noqa: F821
|
|
106
|
+
"--coverage", # noqa: F821
|
|
107
|
+
is_flag=True,
|
|
108
|
+
help="Run the tests while collecting coverage.", # noqa: F722
|
|
109
|
+
),
|
|
110
|
+
debug: option(
|
|
111
|
+
"--debug", is_flag=True, help="Start debug server." # noqa: F722,F821
|
|
112
|
+
),
|
|
113
|
+
with_test_report: option(
|
|
114
|
+
"--with-test-report", # noqa: F722
|
|
115
|
+
is_flag=True,
|
|
116
|
+
help="Create a test execution report.", # noqa: F722
|
|
117
|
+
),
|
|
118
|
+
args,
|
|
119
|
+
):
|
|
120
|
+
"""Run Gherkin tests using behave."""
|
|
121
|
+
# pylint: disable=missing-function-docstring
|
|
122
|
+
coverage_enabled = coverage or cfg.behave.coverage
|
|
123
|
+
coverage_context = with_coverage if coverage_enabled else contextlib.nullcontext
|
|
124
|
+
opts = cfg.behave.opts
|
|
125
|
+
if not cfg.behave.flaky:
|
|
126
|
+
opts.append("--tags=~flaky")
|
|
127
|
+
if with_test_report and cfg.behave.report.name and cfg.behave.report.format:
|
|
128
|
+
opts = [
|
|
129
|
+
f"--format={cfg.behave.report.format}",
|
|
130
|
+
f"-o={cfg.behave.report.name}",
|
|
131
|
+
] + opts
|
|
132
|
+
if cfg.loaded.get("csspin_ce.mkinstance"):
|
|
133
|
+
inst = Path(instance or cfg.mkinstance.base.instance_location).absolute()
|
|
134
|
+
if not (inst).is_dir():
|
|
135
|
+
die(f"Cannot find the CE instance '{inst}'.")
|
|
136
|
+
setenv(CADDOK_BASE=inst)
|
|
137
|
+
|
|
138
|
+
cmd = ["powerscript"]
|
|
139
|
+
if debug:
|
|
140
|
+
cmd.append("--debugpy")
|
|
141
|
+
|
|
142
|
+
with coverage_context(cfg):
|
|
143
|
+
sh(*cmd, "-m", "behave", *opts, *args, *cfg.behave.tests)
|
|
144
|
+
else:
|
|
145
|
+
cmd = ["python"]
|
|
146
|
+
if debug:
|
|
147
|
+
cmd = ["debugpy"] + cfg.debugpy.opts
|
|
148
|
+
|
|
149
|
+
with coverage_context(cfg):
|
|
150
|
+
sh(*cmd, "-m", "behave", *opts, *args, *cfg.behave.tests)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# -*- mode: yaml; coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Schema for the behave plugin for spin
|
|
4
|
+
|
|
5
|
+
behave:
|
|
6
|
+
type: object
|
|
7
|
+
help: |
|
|
8
|
+
The behave plugin for spin enables running behave tests in the
|
|
9
|
+
context of spin.
|
|
10
|
+
properties:
|
|
11
|
+
flaky:
|
|
12
|
+
type: bool
|
|
13
|
+
help: Enable or disable flaky tests
|
|
14
|
+
coverage:
|
|
15
|
+
type: bool
|
|
16
|
+
help: Collect coverage while running behave.
|
|
17
|
+
cov_report:
|
|
18
|
+
type: path
|
|
19
|
+
help: Filepath to store the coverage report.
|
|
20
|
+
cov_config:
|
|
21
|
+
type: path
|
|
22
|
+
help: Filepath to the configuration that behave should respect.
|
|
23
|
+
opts:
|
|
24
|
+
type: list
|
|
25
|
+
help: Additional options for the behave command.
|
|
26
|
+
tests:
|
|
27
|
+
type: list
|
|
28
|
+
help: List of test files or directories to include.
|
|
29
|
+
report:
|
|
30
|
+
type: object
|
|
31
|
+
help: Configuration regarding the test report generation.
|
|
32
|
+
properties:
|
|
33
|
+
name:
|
|
34
|
+
type: path
|
|
35
|
+
help: Path to write the test report to.
|
|
36
|
+
format:
|
|
37
|
+
type: str
|
|
38
|
+
help: |
|
|
39
|
+
A valid formatter of behave to use for the test report.
|
csspin_python/debugpy.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# -*- mode: python; coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2022 CONTACT Software GmbH
|
|
4
|
+
# https://www.contact-software.com
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
"""Module providing configurations for the debugpy plugin for spin"""
|
|
20
|
+
|
|
21
|
+
from csspin import config
|
|
22
|
+
|
|
23
|
+
defaults = config(
|
|
24
|
+
opts=[
|
|
25
|
+
"--listen localhost:5678",
|
|
26
|
+
"--wait-for-client",
|
|
27
|
+
],
|
|
28
|
+
requires=config(
|
|
29
|
+
spin=["csspin_python.python"],
|
|
30
|
+
python=["debugpy"],
|
|
31
|
+
),
|
|
32
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# -*- mode: yaml; coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Schema for the debugpy plugin for spin
|
|
4
|
+
|
|
5
|
+
debugpy:
|
|
6
|
+
type: object
|
|
7
|
+
help: Configuration of the debugpy plugin for spin
|
|
8
|
+
properties:
|
|
9
|
+
enabled:
|
|
10
|
+
type: bool
|
|
11
|
+
help: Enable debugpy for usage.
|
|
12
|
+
opts:
|
|
13
|
+
type: list
|
|
14
|
+
help: Additional options used when executing debugpy.
|
csspin_python/devpi.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# -*- mode: python; coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2020 CONTACT Software GmbH
|
|
4
|
+
# https://www.contact-software.com/
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
"""Module implementing the devpi plugin for spin"""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
from csspin import Command, config, die, exists, readyaml, setenv, sh, task
|
|
22
|
+
|
|
23
|
+
defaults = config(
|
|
24
|
+
formats=["bdist_wheel"],
|
|
25
|
+
url=None,
|
|
26
|
+
user=None,
|
|
27
|
+
requires=config(
|
|
28
|
+
spin=["csspin_python.python"],
|
|
29
|
+
python=[
|
|
30
|
+
"devpi-client",
|
|
31
|
+
"keyring",
|
|
32
|
+
],
|
|
33
|
+
),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def init(cfg): # pylint: disable=unused-argument
|
|
38
|
+
"""Sets some environment variables"""
|
|
39
|
+
setenv(DEVPI_VENV="{python.venv}", DEVPI_CLIENTDIR="{spin.spin_dir}/devpi")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@task("devpi:upload")
|
|
43
|
+
def upload(cfg):
|
|
44
|
+
"""Upload project wheel to a package server."""
|
|
45
|
+
if not cfg.devpi.user:
|
|
46
|
+
die("devpi.user is required!")
|
|
47
|
+
|
|
48
|
+
if exists(current_json := f"{cfg.spin.spin_dir}/devpi/current.json"):
|
|
49
|
+
data = readyaml(current_json)
|
|
50
|
+
else:
|
|
51
|
+
data = {}
|
|
52
|
+
|
|
53
|
+
devpi_ = Command("devpi")
|
|
54
|
+
|
|
55
|
+
if data.get("index") != (url := cfg.devpi.url):
|
|
56
|
+
if url == "None":
|
|
57
|
+
die("devpi.url not provided!")
|
|
58
|
+
devpi_("use", "-t", "yes", url)
|
|
59
|
+
|
|
60
|
+
devpi_("login", cfg.devpi.user)
|
|
61
|
+
devpi_(
|
|
62
|
+
"upload",
|
|
63
|
+
"-p",
|
|
64
|
+
cfg.python.python,
|
|
65
|
+
"--no-vcs",
|
|
66
|
+
f"--wheel={','.join(cfg.devpi.formats)}",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@task()
|
|
71
|
+
def devpi(cfg, args):
|
|
72
|
+
"""Run the 'devpi' command inside the project's virtual environment.
|
|
73
|
+
|
|
74
|
+
All command line arguments are simply passed through to 'devpi'.
|
|
75
|
+
|
|
76
|
+
"""
|
|
77
|
+
if cfg.devpi.url:
|
|
78
|
+
sh("devpi", "use", cfg.devpi.url)
|
|
79
|
+
if cfg.devpi.user:
|
|
80
|
+
sh("devpi", "login", cfg.devpi.user)
|
|
81
|
+
|
|
82
|
+
sh("devpi", *args)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# -*- mode: yaml; coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Schema for the devpi plugin for spin
|
|
4
|
+
|
|
5
|
+
devpi:
|
|
6
|
+
type: object
|
|
7
|
+
help: Configuration of the devpi plugin for spin
|
|
8
|
+
properties:
|
|
9
|
+
formats:
|
|
10
|
+
type: list
|
|
11
|
+
help: A list of formats to pass to devpi's --wheel option
|
|
12
|
+
url:
|
|
13
|
+
type: str
|
|
14
|
+
help: The URL of the package server to communicate with
|
|
15
|
+
user:
|
|
16
|
+
type: str
|
|
17
|
+
help: The user to authenticate with the package server
|