cici-tools 0.19.0__py3-none-any.whl → 0.19.2__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.
cici/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.19.0'
32
- __version_tuple__ = version_tuple = (0, 19, 0)
31
+ __version__ = version = '0.19.2'
32
+ __version_tuple__ = version_tuple = (0, 19, 2)
33
33
 
34
- __commit_id__ = commit_id = 'g2f00c2fa8'
34
+ __commit_id__ = commit_id = 'g5f755c70a'
@@ -85,7 +85,7 @@ class IDToken(msgspec.Struct, omit_defaults=True, frozen=True, kw_only=True):
85
85
  aud: Union[str, list[str]] = field(default_factory=list)
86
86
 
87
87
 
88
- class Image(msgspec.Struct, omit_defaults=True, frozen=True, kw_only=True, tag="image"):
88
+ class Image(msgspec.Struct, omit_defaults=True, frozen=True, kw_only=True, tag=False):
89
89
  name: str
90
90
  entrypoint: Union[str, list[str]] = field(default_factory=list)
91
91
  pull_policy: Union[str, list[str]] = field(default_factory=list)
@@ -3,7 +3,9 @@
3
3
 
4
4
  from typing import Any, Union
5
5
 
6
- from ruamel.yaml.scalarstring import ScalarString
6
+ from ruamel.yaml.scalarstring import FoldedScalarString, ScalarString
7
+
8
+ FOLDED_SCALAR_FOLD_POINTS = {}
7
9
 
8
10
 
9
11
  # Recursivley convert ruamel ScalarStrng objects into plain str """
@@ -11,7 +13,15 @@ from ruamel.yaml.scalarstring import ScalarString
11
13
  # they will be turned into plain "foo" which msgspec can handle
12
14
  # test this frst, test for each of the ifs and make sure the nesting is right.
13
15
  # do simplest tests first, so one that is empty etc. Need to verify.
16
+ #
17
+ # Keep fold_pos for folded scalar strings, if strings aren't changed
18
+ # then re-use fold_pos instead of trying to find best fold positions
14
19
  def normalize_scalars(obj):
20
+ if isinstance(obj, FoldedScalarString):
21
+ full_str = str(obj)
22
+ if hasattr(obj, "fold_pos"):
23
+ FOLDED_SCALAR_FOLD_POINTS[full_str] = obj.fold_pos
24
+ return full_str
15
25
  if isinstance(obj, ScalarString):
16
26
  return str(obj)
17
27
  elif isinstance(obj, dict):
@@ -24,13 +34,6 @@ def normalize_scalars(obj):
24
34
  return obj
25
35
 
26
36
 
27
- # bridge between raw YAML and ruamels quirky Python objects
28
- # and the strict Job/File models
29
- def normalize_all(data: dict) -> dict:
30
- # Apply all normalizations for comparisons
31
- return normalize_variables(normalize_jobs_in_data(data))
32
-
33
-
34
37
  def normalize_variables(data: dict, *, inside_job: bool = False) -> dict:
35
38
  # Normalize variables: keep top-level structured, flatten job-level
36
39
  # inside_job is going to tell me if i am currently in a job definition or not
@@ -10,26 +10,30 @@ from ruamel.yaml.scalarstring import (
10
10
  PreservedScalarString,
11
11
  )
12
12
 
13
+ from .normalizers import FOLDED_SCALAR_FOLD_POINTS
14
+
13
15
 
14
16
  # to force ruamel.yml to always emit double quoted strings """" and not single "''"
15
17
  def always_double_quoted(dumper, data):
16
18
  return dumper.represent_scalar("tag:yaml.org,2002:str", data, style='"')
17
19
 
18
20
 
19
- def wrap_if_long(s: str, width: int = 120) -> str:
20
- # Wrap long strings into multiple lines for YAML folding.
21
- if len(s) <= width:
22
- return s
23
- # break on spaces without splitting words
24
- parts = []
25
- while len(s) > width:
26
- split_at = s.rfind(" ", 0, width)
27
- if split_at == -1:
28
- split_at = width
29
- parts.append(s[:split_at].rstrip())
30
- s = s[split_at:].lstrip()
31
- parts.append(s)
32
- return "\n".join(parts)
21
+ # Return indexes of spaces where a long string should fold into multiple lines.
22
+ # fold_pos is highest index of a space < width, if no space then lowest index > width
23
+ def get_fold_positions(s: str, width: int = 120) -> list[int]:
24
+ all_pos = []
25
+ start_pos = 0
26
+ while start_pos + width < len(s):
27
+ end_pos = start_pos + width
28
+ fold_pos = s.rfind(" ", start_pos, end_pos)
29
+ if fold_pos == -1:
30
+ fold_pos = s.find(" ", end_pos)
31
+ if fold_pos > -1:
32
+ all_pos.append(fold_pos)
33
+ start_pos = fold_pos + 1
34
+ else:
35
+ start_pos = len(s)
36
+ return all_pos
33
37
 
34
38
 
35
39
  # handling string literals
@@ -44,6 +48,13 @@ def make_scalar_string(line: str, quote: bool = False):
44
48
  if "\n" in unindented:
45
49
  return PreservedScalarString(line)
46
50
 
51
+ # if it was a folded scalar string before, make it one again
52
+ # and re-use fold_pos instead of trying to find good breakpoints
53
+ if unindented in FOLDED_SCALAR_FOLD_POINTS:
54
+ folded = FoldedScalarString(unindented)
55
+ folded.fold_pos = FOLDED_SCALAR_FOLD_POINTS[unindented] # type: ignore[attr-defined]
56
+ return folded
57
+
47
58
  # fix extra - >- between lines accidentally created with echo commands
48
59
  if unindented.startswith("echo "):
49
60
  stripped = unindented.strip()
@@ -77,7 +88,9 @@ def make_scalar_string(line: str, quote: bool = False):
77
88
 
78
89
  # Multi-command sequences get folded
79
90
  if any(sym in unindented for sym in ("&&", ";", "\\")):
80
- return FoldedScalarString(wrap_if_long(unindented))
91
+ folded = FoldedScalarString(unindented)
92
+ folded.fold_pos = get_fold_positions(unindented) # type: ignore[attr-defined]
93
+ return folded
81
94
 
82
95
  # Long assignments get folded
83
96
  if (
@@ -85,7 +98,9 @@ def make_scalar_string(line: str, quote: bool = False):
85
98
  and not unindented.startswith(("export ", "set ", "$"))
86
99
  and len(unindented) > 100
87
100
  ):
88
- return FoldedScalarString(wrap_if_long(unindented))
101
+ folded = FoldedScalarString(unindented)
102
+ folded.fold_pos = get_fold_positions(unindented) # type: ignore[attr-defined]
103
+ return folded
89
104
 
90
105
  # Explicit quoting when requested
91
106
  if quote:
@@ -114,7 +129,6 @@ def style_scalars(
114
129
  styled: dict[str, Any] = {}
115
130
 
116
131
  for k, v in list(obj.items()):
117
- v = obj[k]
118
132
  # 1. keep GitLab workflow 'if' rules unquoted
119
133
  if k == "if" and isinstance(v, str):
120
134
  styled[k] = v
@@ -283,7 +297,6 @@ def style_scalars(
283
297
  # 9. everything else, recurse normally
284
298
  else:
285
299
  styled[k] = style_scalars(v, quote_keys=quote_keys, parent_key=k)
286
-
287
300
  # reinsert any keys skipped during iteration ie dependencies
288
301
  for k, v in obj.items():
289
302
  if k not in styled:
@@ -308,7 +321,7 @@ def style_scalars(
308
321
  elif parent_key in {"script", "before_script", "after_script"}:
309
322
  stripped_item = item.strip()
310
323
 
311
- # keep raw shell assignements in plain text (avoid escaping inside quotes)
324
+ # keep raw shell assignments in plain text (avoid escaping inside quotes)
312
325
  if "=" in stripped_item.split()[0] and not stripped_item.startswith(
313
326
  "$"
314
327
  ):
cici/utils.py CHANGED
@@ -1,7 +1,6 @@
1
1
  # SPDX-FileCopyrightText: UL Research Institutes
2
2
  # SPDX-License-Identifier: Apache-2.0
3
3
 
4
- from typing import Any, Union
5
4
 
6
5
  from ruamel.yaml.scalarstring import (
7
6
  DoubleQuotedScalarString,
@@ -31,10 +30,6 @@ def merge_dict(orig: dict, new: dict) -> dict:
31
30
  return final
32
31
 
33
32
 
34
- def make_multiline_string(line):
35
- return PreservedScalarString(line)
36
-
37
-
38
33
  def make_scalar_string(line, quote=False):
39
34
  if "\n" in line.strip():
40
35
  return PreservedScalarString(line)
@@ -43,25 +38,3 @@ def make_scalar_string(line, quote=False):
43
38
  elif quote:
44
39
  return DoubleQuotedScalarString(line)
45
40
  return line
46
-
47
-
48
- def make_quoted_string(line):
49
- return make_scalar_string(line, quote=True)
50
-
51
-
52
- def make_scalar_list(value: list[str]) -> list[Any]:
53
- return [make_scalar_string(line) for line in value]
54
-
55
-
56
- def make_quoted_list(value: list[str]) -> list[Any]:
57
- return [make_scalar_string(line, quote=True) for line in value]
58
-
59
-
60
- def make_quoted_list_or_string(object: Union[str, list[str]]) -> list[Any]:
61
- if isinstance(object, str):
62
- return make_quoted_string(object)
63
- return make_quoted_list(object)
64
-
65
-
66
- def make_quoted_dict(object):
67
- return {key: make_quoted_string(value) for key, value in object.items()}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cici-tools
3
- Version: 0.19.0
3
+ Version: 0.19.2
4
4
  Summary: Continuous Integration Catalog Interface
5
5
  Author-email: Digital Safety Research Institute <contact@dsri.org>
6
6
  License: Apache-2.0
@@ -1,12 +1,12 @@
1
1
  cici/__init__.py,sha256=wdYYpZKxK2omc_mRJgPj86Ec-QwoB4noZzlk71sBjnk,87
2
2
  cici/__main__.py,sha256=TWDBrcS5vXSclLWLm0Iu3uUXOkDw0PzcJ8a0zd7_ClU,150
3
- cici/_version.py,sha256=fXMYtlutAlpJJae3Kc3ZnzTnLJVgEZVNeMetlhpSclY,714
3
+ cici/_version.py,sha256=wysr5h4NZ2DOzX3llE1w4f1vytIkeVD-cG6j7-DuaMI,714
4
4
  cici/constants.py,sha256=ydShHTAbuanWWXeg9tJZ5GLm65M41AKmIibUheKV5nw,913
5
5
  cici/exceptions.py,sha256=JMpcD5YjYwKdn65D0iOEchXiAgIVsKApAyngCTwVgI4,139
6
6
  cici/main.py,sha256=ceH9s7i2XdB-mpUtDWuzLVn9TZHiwmsq-daZOgB9oRI,748
7
7
  cici/paths.py,sha256=R-zBlX70uUJKR-ttGmZ7gI8iIKdxz9hLN1bP1pSXZxI,1103
8
8
  cici/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- cici/utils.py,sha256=E6GrD6qCvsFqaR-fhsuBf8qotxyUO2ZdOoKj2vRUUHs,1917
9
+ cici/utils.py,sha256=sC5GdaRlzgyxZg5HnB-HYtSF0tQQt3NQJMQZZphzowU,1202
10
10
  cici/cli/__init__.py,sha256=wdYYpZKxK2omc_mRJgPj86Ec-QwoB4noZzlk71sBjnk,87
11
11
  cici/cli/bundle.py,sha256=sTcbWiNz_k5OgJVC7XAG5KaHGQZmWLi1Fqdg3JENHDg,3929
12
12
  cici/cli/readme.py,sha256=w2-Pi2aDxWGcLMnVEUmejItAneMIqHj0QiR4foFcHYs,2475
@@ -20,11 +20,11 @@ cici/config/project/serializers.py,sha256=O3uj4Mmno7xsOQqFb78rtyMM3-66DEE1B0mTOU
20
20
  cici/providers/__init__.py,sha256=wdYYpZKxK2omc_mRJgPj86Ec-QwoB4noZzlk71sBjnk,87
21
21
  cici/providers/gitlab/__init__.py,sha256=8ej6k3hd25UFOGFhHymLa2mvz9hEwMjdxyu66hnJwOQ,259
22
22
  cici/providers/gitlab/constants.py,sha256=nA36aqGvwBBood8lTFJueEY8lKEsOVjkp6ciMjAeKJA,1786
23
- cici/providers/gitlab/models.py,sha256=Hyy1V1Hg_pmFKu3C8KvcP6wGXGOPHqWpvt70BhZAaMk,7368
24
- cici/providers/gitlab/normalizers.py,sha256=EFQiJzRDkoahes0zwIMahuVC3DOy9A97eZDhMXdamno,4762
23
+ cici/providers/gitlab/models.py,sha256=MEQYYWeHtMpdSS1zjpxcBC3jXrZdmant98HakeNKXKc,7366
24
+ cici/providers/gitlab/normalizers.py,sha256=MDiWydumkxQyOGd215g-PRa5FGZgIaO5Hj-35-E5FhI,4908
25
25
  cici/providers/gitlab/serializers.py,sha256=heczGlwcmKesugYX8PhwIhVIw8kExsfXKsC52sAwLrc,11533
26
26
  cici/providers/gitlab/utils.py,sha256=NUZ25rAosSWQyWh7m3xhiHRotqVl1krckZL58yR0LKQ,651
27
- cici/providers/gitlab/yaml_style.py,sha256=emgrHqjhMmAWhlgtYJ8NgIYRntSaXQC8T5QDehSbOCM,14101
27
+ cici/providers/gitlab/yaml_style.py,sha256=9Pa_5CUCbWkAp6fWTfWcBBadQzwe4NbK8ETF_IgqY-w,14829
28
28
  cici/schema/LICENSE.gitlab,sha256=0N7FHuinuoGBqZE6aUlD84yw3CGylx8lyfzertgmtY0,2001
29
29
  cici/schema/__init__.py,sha256=wdYYpZKxK2omc_mRJgPj86Ec-QwoB4noZzlk71sBjnk,87
30
30
  cici/schema/gitlab-ci.json,sha256=BCymn2i9JOrUGS2SsvpoXCH8JcofQz9Rhux46zEnS_8,70638
@@ -39,10 +39,10 @@ cici/templates/target-table.md.j2,sha256=NYspLbP3ap1706WnehZRtu6a2uxL_mKf7zfm3y0
39
39
  cici/templates/targets.md.j2,sha256=k-lkfReFJMCu9t2SjuD5YJ-Q_KECJxdY7v-0TWDTaCM,116
40
40
  cici/templates/variable-list.md.j2,sha256=M9r3j7d8H171okQNj8j4pc92kMdeWSRoeZQ5QB3NUTQ,613
41
41
  cici/templates/variables.md.j2,sha256=2DquXagNupqBkD95_3ZI4guJOK-eG_igaaMdRIUDrcE,84
42
- cici_tools-0.19.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
43
- cici_tools-0.19.0.dist-info/licenses/NOTICE,sha256=dIBr-7sfvnoYXYvgHIozlRJTLD4EHORRtRJtIe4znW8,55
44
- cici_tools-0.19.0.dist-info/METADATA,sha256=qNrVT7Qsebx70jcmMAgsN0xx-Sq94u3TOJBRwha1Y7o,4361
45
- cici_tools-0.19.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
46
- cici_tools-0.19.0.dist-info/entry_points.txt,sha256=CuBAwYG3z7qOKm4IYARjZzdX5fytMLKyr59HLLJx_Is,44
47
- cici_tools-0.19.0.dist-info/top_level.txt,sha256=sv8xIjFuuqtyBMoyzueczNvZo_--q12r64Zc0lGKKF8,5
48
- cici_tools-0.19.0.dist-info/RECORD,,
42
+ cici_tools-0.19.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
43
+ cici_tools-0.19.2.dist-info/licenses/NOTICE,sha256=dIBr-7sfvnoYXYvgHIozlRJTLD4EHORRtRJtIe4znW8,55
44
+ cici_tools-0.19.2.dist-info/METADATA,sha256=T-fTeUCiST4nLf2OyBTYWWQ3vNRA2Z2UOXkMswXyxzc,4361
45
+ cici_tools-0.19.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
46
+ cici_tools-0.19.2.dist-info/entry_points.txt,sha256=CuBAwYG3z7qOKm4IYARjZzdX5fytMLKyr59HLLJx_Is,44
47
+ cici_tools-0.19.2.dist-info/top_level.txt,sha256=sv8xIjFuuqtyBMoyzueczNvZo_--q12r64Zc0lGKKF8,5
48
+ cici_tools-0.19.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5