ci-environment 10.0.1__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.
- ci-environment-10.0.1/PKG-INFO +30 -0
- ci-environment-10.0.1/README.md +3 -0
- ci-environment-10.0.1/pyproject.toml +69 -0
- ci-environment-10.0.1/setup.cfg +21 -0
- ci-environment-10.0.1/src/ci_environment/CiEnvironments.json +160 -0
- ci-environment-10.0.1/src/ci_environment/__init__.py +3 -0
- ci-environment-10.0.1/src/ci_environment/ci_environment.py +89 -0
- ci-environment-10.0.1/src/ci_environment/variable_expression.py +43 -0
- ci-environment-10.0.1/src/ci_environment.egg-info/PKG-INFO +30 -0
- ci-environment-10.0.1/src/ci_environment.egg-info/SOURCES.txt +14 -0
- ci-environment-10.0.1/src/ci_environment.egg-info/dependency_links.txt +1 -0
- ci-environment-10.0.1/src/ci_environment.egg-info/requires.txt +5 -0
- ci-environment-10.0.1/src/ci_environment.egg-info/top_level.txt +1 -0
- ci-environment-10.0.1/tests/test_detect_ci_environment.py +21 -0
- ci-environment-10.0.1/tests/test_variable_expression.py +42 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ci-environment
|
|
3
|
+
Version: 10.0.1
|
|
4
|
+
Summary: This library detects the CI environment based on environment variables defined by CI servers.
|
|
5
|
+
Author-email: Cucumber Limited <cukes@googlegroups.com>
|
|
6
|
+
Maintainer-email: Konstantin Goloveshko <kostya.goloveshko@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Repository, https://github.com/cucumber/ci-environment
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: POSIX
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
15
|
+
Classifier: Topic :: Utilities
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Requires-Dist: importlib_resources
|
|
24
|
+
Requires-Dist: python-dotenv
|
|
25
|
+
Provides-Extra: test
|
|
26
|
+
Requires-Dist: tox; extra == "test"
|
|
27
|
+
|
|
28
|
+
# CiEnvironment
|
|
29
|
+
|
|
30
|
+
Python implementation of https://github.com/cucumber/ci-environment
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "setuptools.build_meta"
|
|
3
|
+
requires = ["setuptools", "wheel"]
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
authors = [
|
|
7
|
+
{name = "Cucumber Limited", email = "cukes@googlegroups.com"}
|
|
8
|
+
]
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 4 - Beta",
|
|
11
|
+
"Intended Audience :: Developers",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Operating System :: POSIX",
|
|
14
|
+
"Operating System :: Microsoft :: Windows",
|
|
15
|
+
"Operating System :: MacOS :: MacOS X",
|
|
16
|
+
"Topic :: Utilities",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.8",
|
|
19
|
+
"Programming Language :: Python :: 3.9",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11"
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"importlib_resources",
|
|
25
|
+
"python-dotenv"
|
|
26
|
+
]
|
|
27
|
+
dynamic = [
|
|
28
|
+
"optional-dependencies"
|
|
29
|
+
]
|
|
30
|
+
description = "This library detects the CI environment based on environment variables defined by CI servers."
|
|
31
|
+
readme = {file = "README.md", content-type = "text/markdown"}
|
|
32
|
+
license = {text = "MIT"}
|
|
33
|
+
maintainers = [
|
|
34
|
+
{name = "Konstantin Goloveshko", email = "kostya.goloveshko@gmail.com"}
|
|
35
|
+
]
|
|
36
|
+
name = "ci-environment"
|
|
37
|
+
requires-python = ">=3.8"
|
|
38
|
+
urls = {Repository = "https://github.com/cucumber/ci-environment"}
|
|
39
|
+
version = "10.0.1"
|
|
40
|
+
|
|
41
|
+
[project.entry-points]
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
|
|
45
|
+
[tool.black]
|
|
46
|
+
line-length = 120
|
|
47
|
+
target-version = ["py38", "py39", "py310", "py311"]
|
|
48
|
+
verbose = true
|
|
49
|
+
|
|
50
|
+
[tool.isort]
|
|
51
|
+
line_length = 120
|
|
52
|
+
multi_line_output = 3
|
|
53
|
+
profile = "black"
|
|
54
|
+
|
|
55
|
+
[tool.mypy]
|
|
56
|
+
files = "src/ci_environment/**/*.py"
|
|
57
|
+
install_types = true
|
|
58
|
+
non_interactive = true
|
|
59
|
+
plugins = [
|
|
60
|
+
"pydantic.mypy"
|
|
61
|
+
]
|
|
62
|
+
show_error_codes = true
|
|
63
|
+
warn_return_any = true
|
|
64
|
+
warn_unused_configs = true
|
|
65
|
+
|
|
66
|
+
[[tool.mypy.overrides]]
|
|
67
|
+
ignore_missing_imports = true
|
|
68
|
+
module = [
|
|
69
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[options]
|
|
2
|
+
include_package_data = True
|
|
3
|
+
packages = find:
|
|
4
|
+
package_dir =
|
|
5
|
+
=src
|
|
6
|
+
|
|
7
|
+
[options.packages.find]
|
|
8
|
+
where = src
|
|
9
|
+
|
|
10
|
+
[options.package_data]
|
|
11
|
+
ci_environment =
|
|
12
|
+
CiEnvironments.json
|
|
13
|
+
|
|
14
|
+
[options.extras_require]
|
|
15
|
+
test =
|
|
16
|
+
tox
|
|
17
|
+
|
|
18
|
+
[egg_info]
|
|
19
|
+
tag_build =
|
|
20
|
+
tag_date = 0
|
|
21
|
+
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "Azure Pipelines",
|
|
4
|
+
"url": "${BUILD_BUILDURI}",
|
|
5
|
+
"buildNumber": "${BUILD_BUILDNUMBER}",
|
|
6
|
+
"git": {
|
|
7
|
+
"remote": "${BUILD_REPOSITORY_URI}",
|
|
8
|
+
"revision": "${BUILD_SOURCEVERSION}",
|
|
9
|
+
"branch": "${BUILD_SOURCEBRANCH/refs\/heads\/(.*)/\\1}",
|
|
10
|
+
"tag": "${BUILD_SOURCEBRANCH/refs\/tags\/(.*)/\\1}"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "Bamboo",
|
|
15
|
+
"url": "${bamboo_buildResultsUrl}",
|
|
16
|
+
"buildNumber": "${bamboo_buildNumber}",
|
|
17
|
+
"git": {
|
|
18
|
+
"remote": "${bamboo_planRepository_repositoryUrl}",
|
|
19
|
+
"revision": "${bamboo_planRepository_revision}",
|
|
20
|
+
"branch": "${bamboo_planRepository_branch}"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "Buddy",
|
|
25
|
+
"url": "${BUDDY_EXECUTION_URL}",
|
|
26
|
+
"buildNumber": "${BUDDY_EXECUTION_ID}",
|
|
27
|
+
"git": {
|
|
28
|
+
"remote": "${BUDDY_SCM_URL}",
|
|
29
|
+
"revision": "${BUDDY_EXECUTION_REVISION}",
|
|
30
|
+
"branch": "${BUDDY_EXECUTION_BRANCH}",
|
|
31
|
+
"tag": "${BUDDY_EXECUTION_TAG}"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "Bitrise",
|
|
36
|
+
"url": "${BITRISE_BUILD_URL}",
|
|
37
|
+
"buildNumber": "${BITRISE_BUILD_NUMBER}",
|
|
38
|
+
"git": {
|
|
39
|
+
"remote": "${GIT_REPOSITORY_URL}",
|
|
40
|
+
"revision": "${BITRISE_GIT_COMMIT}",
|
|
41
|
+
"branch": "${BITRISE_GIT_BRANCH}",
|
|
42
|
+
"tag": "${BITRISE_GIT_TAG}"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "CircleCI",
|
|
47
|
+
"url": "${CIRCLE_BUILD_URL}",
|
|
48
|
+
"buildNumber": "${CIRCLE_BUILD_NUM}",
|
|
49
|
+
"git": {
|
|
50
|
+
"remote": "${CIRCLE_REPOSITORY_URL}",
|
|
51
|
+
"revision": "${CIRCLE_SHA1}",
|
|
52
|
+
"branch": "${CIRCLE_BRANCH}",
|
|
53
|
+
"tag": "${CIRCLE_TAG}"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "CodeFresh",
|
|
58
|
+
"url": "${CF_BUILD_URL}",
|
|
59
|
+
"buildNumber": "${CF_BUILD_ID}",
|
|
60
|
+
"git": {
|
|
61
|
+
"remote": "${CF_COMMIT_URL/(.*)\\/commit.+$/\\1}.git",
|
|
62
|
+
"revision": "${CF_REVISION}",
|
|
63
|
+
"branch": "${CF_BRANCH}"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"name": "CodeShip",
|
|
68
|
+
"url": "${CI_BUILD_URL}",
|
|
69
|
+
"buildNumber": "${CI_BUILD_NUMBER}",
|
|
70
|
+
"git": {
|
|
71
|
+
"remote": "${CI_PULL_REQUEST/(.*)\\/pull\\/\\d+/\\1.git}",
|
|
72
|
+
"revision": "${CI_COMMIT_ID}",
|
|
73
|
+
"branch": "${CI_BRANCH}"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "GitHub Actions",
|
|
78
|
+
"url": "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}",
|
|
79
|
+
"buildNumber": "${GITHUB_RUN_ID}",
|
|
80
|
+
"git": {
|
|
81
|
+
"remote": "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git",
|
|
82
|
+
"revision": "${GITHUB_SHA}",
|
|
83
|
+
"branch": "${GITHUB_HEAD_REF}",
|
|
84
|
+
"tag": "${GITHUB_REF/refs\/tags\/(.*)/\\1}"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"name": "GitLab",
|
|
89
|
+
"url": "${CI_JOB_URL}",
|
|
90
|
+
"buildNumber": "${CI_JOB_ID}",
|
|
91
|
+
"git": {
|
|
92
|
+
"remote": "${CI_REPOSITORY_URL}",
|
|
93
|
+
"revision": "${CI_COMMIT_SHA}",
|
|
94
|
+
"branch": "${CI_COMMIT_BRANCH}",
|
|
95
|
+
"tag": "${CI_COMMIT_TAG}"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"name": "GoCD",
|
|
100
|
+
"url": "${GO_SERVER_URL}/pipelines/${GO_PIPELINE_NAME}/${GO_PIPELINE_COUNTER}/${GO_STAGE_NAME}/${GO_STAGE_COUNTER}",
|
|
101
|
+
"buildNumber": "${GO_PIPELINE_NAME}/${GO_PIPELINE_COUNTER}/${GO_STAGE_NAME}/${GO_STAGE_COUNTER}",
|
|
102
|
+
"git": {
|
|
103
|
+
"remote": "${GO_SCM_*_PR_URL/(.*)\\/pull\\/\\d+/\\1.git}",
|
|
104
|
+
"revision": "${GO_REVISION}",
|
|
105
|
+
"branch": "${GO_SCM_*_PR_BRANCH/.*:(.*)/\\1}"
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "Jenkins",
|
|
110
|
+
"url": "${BUILD_URL}",
|
|
111
|
+
"buildNumber": "${BUILD_NUMBER}",
|
|
112
|
+
"git": {
|
|
113
|
+
"remote": "${GIT_URL}",
|
|
114
|
+
"revision": "${GIT_COMMIT}",
|
|
115
|
+
"branch": "${GIT_LOCAL_BRANCH}"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"name": "JetBrains Space",
|
|
120
|
+
"url": "${JB_SPACE_EXECUTION_URL}",
|
|
121
|
+
"buildNumber": "${JB_SPACE_EXECUTION_NUMBER}",
|
|
122
|
+
"git": {
|
|
123
|
+
"remote": "https://${JB_SPACE_API_URL}/p/${JB_SPACE_PROJECT_KEY}/repositories/${JB_SPACE_GIT_REPOSITORY_NAME}",
|
|
124
|
+
"revision": "${JB_SPACE_GIT_REVISION}",
|
|
125
|
+
"branch": "${JB_SPACE_GIT_BRANCH}"
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"name": "Semaphore",
|
|
130
|
+
"url": "${SEMAPHORE_ORGANIZATION_URL}/jobs/${SEMAPHORE_JOB_ID}",
|
|
131
|
+
"buildNumber": "${SEMAPHORE_JOB_ID}",
|
|
132
|
+
"git": {
|
|
133
|
+
"remote": "${SEMAPHORE_GIT_URL}",
|
|
134
|
+
"revision": "${SEMAPHORE_GIT_SHA}",
|
|
135
|
+
"branch": "${SEMAPHORE_GIT_BRANCH}",
|
|
136
|
+
"tag": "${SEMAPHORE_GIT_TAG_NAME}"
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"name": "Travis CI",
|
|
141
|
+
"url": "${TRAVIS_BUILD_WEB_URL}",
|
|
142
|
+
"buildNumber": "${TRAVIS_JOB_NUMBER}",
|
|
143
|
+
"git": {
|
|
144
|
+
"remote": "https://github.com/${TRAVIS_REPO_SLUG}.git",
|
|
145
|
+
"revision": "${TRAVIS_COMMIT}",
|
|
146
|
+
"branch": "${TRAVIS_BRANCH}",
|
|
147
|
+
"tag": "${TRAVIS_TAG}"
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "Wercker",
|
|
152
|
+
"url": "${WERCKER_RUN_URL}",
|
|
153
|
+
"buildNumber": "${WERCKER_RUN_URL/.*\\/([^\\/]+)$/\\1}",
|
|
154
|
+
"git": {
|
|
155
|
+
"remote": "https://${WERCKER_GIT_DOMAIN}/${WERCKER_GIT_OWNER}/${WERCKER_GIT_REPOSITORY}.git",
|
|
156
|
+
"revision": "${WERCKER_GIT_COMMIT}",
|
|
157
|
+
"branch": "${WERCKER_GIT_BRANCH}"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
]
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from collections import namedtuple
|
|
2
|
+
from contextlib import suppress
|
|
3
|
+
from functools import partial, wraps
|
|
4
|
+
from itertools import filterfalse
|
|
5
|
+
from json import loads as loads_json
|
|
6
|
+
from operator import is_
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from pprint import pformat
|
|
9
|
+
from typing import Dict
|
|
10
|
+
from urllib.parse import urlparse
|
|
11
|
+
|
|
12
|
+
from importlib_resources import as_file, files
|
|
13
|
+
|
|
14
|
+
from ci_environment.variable_expression import evaluate
|
|
15
|
+
|
|
16
|
+
_key_value = namedtuple("_key_value", ["key", "value"])
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@wraps(dict)
|
|
20
|
+
def _opt_dict(*args, **kwargs) -> Dict:
|
|
21
|
+
return {k: v for k, v in dict(*args, **kwargs).items() if v is not None}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _flip(func):
|
|
25
|
+
def wrapped(*args, **kwargs):
|
|
26
|
+
if len(args) > 1:
|
|
27
|
+
first, *other, last = args
|
|
28
|
+
return func(last, *other, first, **kwargs)
|
|
29
|
+
else:
|
|
30
|
+
return func(*args, **kwargs)
|
|
31
|
+
|
|
32
|
+
return wrapped
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def detect_ci_environment(env: Dict[str, str]):
|
|
36
|
+
with as_file(files("ci_environment").joinpath("CiEnvironments.json")) as path:
|
|
37
|
+
ci_environments = loads_json(Path(path).read_text())
|
|
38
|
+
|
|
39
|
+
return next(filterfalse(partial(_flip(is_), None), map(partial(detect, env=env), ci_environments)), None)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def detect(ci_environment, env: Dict[str, str]):
|
|
43
|
+
if (url := evaluate(ci_environment["url"], env)) is not None:
|
|
44
|
+
return dict(
|
|
45
|
+
name=ci_environment["name"],
|
|
46
|
+
url=url,
|
|
47
|
+
buildNumber=evaluate(ci_environment["buildNumber"], env),
|
|
48
|
+
**_opt_dict(git=detect_git(ci_environment, env)),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def detect_git(ci_environment, env: Dict[str, str]):
|
|
53
|
+
if all(
|
|
54
|
+
[
|
|
55
|
+
(revision := detect_revision(ci_environment, env)) is not None,
|
|
56
|
+
(remote := evaluate(ci_environment["git"]["remote"], env)) is not None,
|
|
57
|
+
]
|
|
58
|
+
):
|
|
59
|
+
return dict(
|
|
60
|
+
remote=remove_userinfo_from_url(remote),
|
|
61
|
+
revision=revision,
|
|
62
|
+
**_opt_dict(
|
|
63
|
+
tag=evaluate(ci_environment.get("git", {}).get("tag"), env),
|
|
64
|
+
branch=evaluate(ci_environment.get("git", {}).get("branch"), env),
|
|
65
|
+
),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def detect_revision(ci_environment, env: Dict[str, str]):
|
|
70
|
+
if env.get("GITHUB_EVENT_NAME") == "pull_request":
|
|
71
|
+
try:
|
|
72
|
+
event = loads_json(Path(env["GITHUB_EVENT_PATH"]).read_text())
|
|
73
|
+
except KeyError as e:
|
|
74
|
+
raise ValueError from e
|
|
75
|
+
try:
|
|
76
|
+
revision = event["pull_request"]["head"]["sha"]
|
|
77
|
+
except KeyError as e:
|
|
78
|
+
raise ValueError(pformat(event)) from e
|
|
79
|
+
else:
|
|
80
|
+
return revision
|
|
81
|
+
else:
|
|
82
|
+
return evaluate(ci_environment["git"]["revision"], env)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def remove_userinfo_from_url(remote):
|
|
86
|
+
if remote is not None:
|
|
87
|
+
with suppress(Exception):
|
|
88
|
+
return (parsed_url := urlparse(remote))._replace(netloc=parsed_url.hostname).geturl()
|
|
89
|
+
return remote
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from contextlib import suppress
|
|
2
|
+
from re import compile as compile_re
|
|
3
|
+
from re import subn
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def evaluate(expression, env):
|
|
8
|
+
if expression is None:
|
|
9
|
+
return
|
|
10
|
+
with suppress(Exception):
|
|
11
|
+
re_pattern = compile_re(r"\$\{(.*?)(?:(?<!\\)/(.*)/(.*))?}")
|
|
12
|
+
|
|
13
|
+
def repl(match):
|
|
14
|
+
variable = match.group(1)
|
|
15
|
+
value = get_value(env, variable)
|
|
16
|
+
if value is None:
|
|
17
|
+
raise ValueError
|
|
18
|
+
pattern = match.group(2)
|
|
19
|
+
if pattern is None:
|
|
20
|
+
return value
|
|
21
|
+
regexp = compile_re(subn("\\/", "/", pattern)[0])
|
|
22
|
+
|
|
23
|
+
replacement = match.group(3)
|
|
24
|
+
if regexp.match(value):
|
|
25
|
+
return regexp.subn(replacement, value)[0]
|
|
26
|
+
else:
|
|
27
|
+
raise ValueError
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
result = re_pattern.subn(repl=repl, string=expression)[0]
|
|
31
|
+
return result
|
|
32
|
+
except ValueError:
|
|
33
|
+
...
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_value(env: Dict, variable: str):
|
|
37
|
+
if "*" in variable:
|
|
38
|
+
pattern = compile_re(variable.replace("*", ".*"))
|
|
39
|
+
for name, value in env.items():
|
|
40
|
+
if pattern.match(name):
|
|
41
|
+
return value
|
|
42
|
+
else:
|
|
43
|
+
return env.get(variable)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ci-environment
|
|
3
|
+
Version: 10.0.1
|
|
4
|
+
Summary: This library detects the CI environment based on environment variables defined by CI servers.
|
|
5
|
+
Author-email: Cucumber Limited <cukes@googlegroups.com>
|
|
6
|
+
Maintainer-email: Konstantin Goloveshko <kostya.goloveshko@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Repository, https://github.com/cucumber/ci-environment
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: POSIX
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
15
|
+
Classifier: Topic :: Utilities
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Requires-Dist: importlib_resources
|
|
24
|
+
Requires-Dist: python-dotenv
|
|
25
|
+
Provides-Extra: test
|
|
26
|
+
Requires-Dist: tox; extra == "test"
|
|
27
|
+
|
|
28
|
+
# CiEnvironment
|
|
29
|
+
|
|
30
|
+
Python implementation of https://github.com/cucumber/ci-environment
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
setup.cfg
|
|
4
|
+
src/ci_environment/CiEnvironments.json
|
|
5
|
+
src/ci_environment/__init__.py
|
|
6
|
+
src/ci_environment/ci_environment.py
|
|
7
|
+
src/ci_environment/variable_expression.py
|
|
8
|
+
src/ci_environment.egg-info/PKG-INFO
|
|
9
|
+
src/ci_environment.egg-info/SOURCES.txt
|
|
10
|
+
src/ci_environment.egg-info/dependency_links.txt
|
|
11
|
+
src/ci_environment.egg-info/requires.txt
|
|
12
|
+
src/ci_environment.egg-info/top_level.txt
|
|
13
|
+
tests/test_detect_ci_environment.py
|
|
14
|
+
tests/test_variable_expression.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ci_environment
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from json import loads
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from dotenv import dotenv_values
|
|
5
|
+
from pytest import mark
|
|
6
|
+
|
|
7
|
+
from ci_environment import detect_ci_environment
|
|
8
|
+
|
|
9
|
+
_data_path = Path(__file__) / ".." / ".." / ".." / "testdata"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@mark.parametrize("envfile", _data_path.glob("*.txt"))
|
|
13
|
+
def test_detect_ci_environment(envfile):
|
|
14
|
+
env = dotenv_values(envfile)
|
|
15
|
+
expected = loads((envfile.resolve().parent / f"{envfile.name}.json").read_text())
|
|
16
|
+
|
|
17
|
+
assert detect_ci_environment(env) == expected
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_detect_ci_environment_when_no_environment():
|
|
21
|
+
assert detect_ci_environment({}) is None
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from ci_environment.variable_expression import evaluate
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_evaluate_returns_undefined_when_a_variable_iws_undefined():
|
|
5
|
+
expression = "hello-${SOME_VAR}"
|
|
6
|
+
result = evaluate(expression, {})
|
|
7
|
+
assert result is None
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_evaluate_gets_a_value_without_replacement():
|
|
11
|
+
expression = "${SOME_VAR}"
|
|
12
|
+
result = evaluate(expression, {"SOME_VAR": "some_value"})
|
|
13
|
+
assert result == "some_value"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_evaluate_captures_a_group():
|
|
17
|
+
expression = "${SOME_REF/refs\\/heads\\/(.*)/\\1}"
|
|
18
|
+
result = evaluate(expression, {"SOME_REF": "refs/heads/main"})
|
|
19
|
+
assert result == "main"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_evaluate_works_with_star_wildcard_in_var():
|
|
23
|
+
expression = "${GO_SCM_*_PR_BRANCH/.*:(.*)/\\1}"
|
|
24
|
+
result = evaluate(
|
|
25
|
+
expression,
|
|
26
|
+
{
|
|
27
|
+
"GO_SCM_MY_MATERIAL_PR_BRANCH": "ashwankthkumar:feature-1",
|
|
28
|
+
},
|
|
29
|
+
)
|
|
30
|
+
assert result == "feature-1"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_evaluate_evaluates_a_complex_expression():
|
|
34
|
+
expression = "hello-${VAR1}-${VAR2/(.*) (.*)/\\2-\\1}-world"
|
|
35
|
+
result = evaluate(
|
|
36
|
+
expression,
|
|
37
|
+
{
|
|
38
|
+
"VAR1": "amazing",
|
|
39
|
+
"VAR2": "gorgeous beautiful",
|
|
40
|
+
},
|
|
41
|
+
)
|
|
42
|
+
assert result == "hello-amazing-beautiful-gorgeous-world"
|