ara-cli 0.1.9.63__py3-none-any.whl → 0.1.9.65__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.
Potentially problematic release.
This version of ara-cli might be problematic. Click here for more details.
- ara_cli/ara_command_action.py +42 -12
- ara_cli/ara_command_parser.py +7 -0
- ara_cli/artefact_autofix.py +2 -3
- ara_cli/artefact_creator.py +3 -2
- ara_cli/artefact_fuzzy_search.py +21 -2
- ara_cli/artefact_models/artefact_model.py +3 -2
- ara_cli/artefact_models/feature_artefact_model.py +64 -1
- ara_cli/artefact_reader.py +23 -1
- ara_cli/prompt_extractor.py +7 -3
- ara_cli/prompt_handler.py +20 -7
- ara_cli/tag_extractor.py +20 -9
- ara_cli/tests/test_ara_command_action.py +6 -2
- ara_cli/tests/test_tag_extractor.py +52 -23
- ara_cli/version.py +1 -1
- {ara_cli-0.1.9.63.dist-info → ara_cli-0.1.9.65.dist-info}/METADATA +1 -1
- {ara_cli-0.1.9.63.dist-info → ara_cli-0.1.9.65.dist-info}/RECORD +19 -19
- {ara_cli-0.1.9.63.dist-info → ara_cli-0.1.9.65.dist-info}/WHEEL +0 -0
- {ara_cli-0.1.9.63.dist-info → ara_cli-0.1.9.65.dist-info}/entry_points.txt +0 -0
- {ara_cli-0.1.9.63.dist-info → ara_cli-0.1.9.65.dist-info}/top_level.txt +0 -0
ara_cli/ara_command_action.py
CHANGED
|
@@ -18,6 +18,8 @@ def create_action(args):
|
|
|
18
18
|
from ara_cli.classifier import Classifier
|
|
19
19
|
from ara_cli.filename_validator import is_valid_filename
|
|
20
20
|
from ara_cli.template_manager import SpecificationBreakdownAspects
|
|
21
|
+
from ara_cli.artefact_reader import ArtefactReader
|
|
22
|
+
from ara_cli.artefact_fuzzy_search import find_closest_rule
|
|
21
23
|
|
|
22
24
|
check_validity(Classifier.is_valid_classifier(args.classifier), "Invalid classifier provided. Please provide a valid classifier.")
|
|
23
25
|
check_validity(is_valid_filename(args.parameter), "Invalid filename provided. Please provide a valid filename.")
|
|
@@ -25,11 +27,20 @@ def create_action(args):
|
|
|
25
27
|
def handle_parent_arguments(args):
|
|
26
28
|
parent_classifier = args.parent_classifier if hasattr(args, "parent_classifier") else None
|
|
27
29
|
parent_name = args.parent_name if hasattr(args, "parent_name") else None
|
|
30
|
+
rule = args.rule if hasattr(args, 'rule') else None
|
|
31
|
+
invalid_classifier_message = "Invalid parent classifier provided. Please provide a valid classifier"
|
|
32
|
+
invalid_name_message = "Invalid filename provided for parent. Please provide a valid filename."
|
|
33
|
+
if parent_classifier and parent_name and rule:
|
|
34
|
+
check_validity(Classifier.is_valid_classifier(parent_classifier), invalid_classifier_message)
|
|
35
|
+
check_validity(is_valid_filename(parent_name), invalid_name_message)
|
|
36
|
+
parent_artefact = ArtefactReader.read_single_artefact(artefact_name=parent_name, classifier=parent_classifier)
|
|
37
|
+
rule = find_closest_rule(parent_artefact, rule)
|
|
38
|
+
return parent_classifier, parent_name, rule
|
|
28
39
|
if parent_classifier and parent_name:
|
|
29
|
-
check_validity(Classifier.is_valid_classifier(parent_classifier),
|
|
30
|
-
check_validity(is_valid_filename(parent_name),
|
|
31
|
-
return parent_classifier, parent_name
|
|
32
|
-
return None, None
|
|
40
|
+
check_validity(Classifier.is_valid_classifier(parent_classifier), invalid_classifier_message)
|
|
41
|
+
check_validity(is_valid_filename(parent_name), invalid_name_message)
|
|
42
|
+
return parent_classifier, parent_name, rule
|
|
43
|
+
return None, None, None
|
|
33
44
|
|
|
34
45
|
def handle_aspect_creation(args):
|
|
35
46
|
aspect = args.aspect if hasattr(args, "aspect") else None
|
|
@@ -43,12 +54,12 @@ def create_action(args):
|
|
|
43
54
|
sys.exit(1)
|
|
44
55
|
return False
|
|
45
56
|
|
|
46
|
-
parent_classifier, parent_name = handle_parent_arguments(args)
|
|
57
|
+
parent_classifier, parent_name, rule = handle_parent_arguments(args)
|
|
47
58
|
if handle_aspect_creation(args):
|
|
48
59
|
return
|
|
49
60
|
|
|
50
61
|
artefact_creator = ArtefactCreator()
|
|
51
|
-
artefact_creator.run(args.parameter, args.classifier, parent_classifier, parent_name)
|
|
62
|
+
artefact_creator.run(args.parameter, args.classifier, parent_classifier, parent_name, rule)
|
|
52
63
|
|
|
53
64
|
|
|
54
65
|
def delete_action(args):
|
|
@@ -122,15 +133,17 @@ def list_action(args):
|
|
|
122
133
|
|
|
123
134
|
def list_tags_action(args):
|
|
124
135
|
from ara_cli.tag_extractor import TagExtractor
|
|
136
|
+
from ara_cli.list_filter import ListFilter
|
|
125
137
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
138
|
+
list_filter = ListFilter(
|
|
139
|
+
include_extension=args.include_classifier,
|
|
140
|
+
exclude_extension=args.exclude_classifier,
|
|
141
|
+
)
|
|
129
142
|
|
|
130
143
|
tag_extractor = TagExtractor()
|
|
131
144
|
tags = tag_extractor.extract_tags(
|
|
132
|
-
|
|
133
|
-
|
|
145
|
+
filtered_extra_column=getattr(args, "filtered_extra_column", False),
|
|
146
|
+
list_filter=list_filter
|
|
134
147
|
)
|
|
135
148
|
|
|
136
149
|
if args.json:
|
|
@@ -334,14 +347,18 @@ def reconnect_action(args):
|
|
|
334
347
|
from ara_cli.artefact_models.artefact_load import artefact_from_content
|
|
335
348
|
from ara_cli.artefact_models.artefact_model import Contribution
|
|
336
349
|
from ara_cli.artefact_reader import ArtefactReader
|
|
350
|
+
from ara_cli.artefact_fuzzy_search import find_closest_rule
|
|
337
351
|
|
|
338
352
|
classifier = args.classifier
|
|
339
353
|
artefact_name = args.parameter
|
|
340
354
|
parent_classifier = args.parent_classifier
|
|
341
355
|
parent_name = args.parent_name
|
|
356
|
+
rule = args.rule if hasattr(args, 'rule') else None
|
|
342
357
|
|
|
343
358
|
read_error_message = f"Could not connect {classifier} '{artefact_name}' to {parent_classifier} '{parent_name}'"
|
|
344
359
|
|
|
360
|
+
feedback_message = f"Updated contribution of {classifier} '{artefact_name}' to {parent_classifier} '{parent_name}'"
|
|
361
|
+
|
|
345
362
|
content, artefact_info = ArtefactReader.read_artefact(
|
|
346
363
|
artefact_name=artefact_name,
|
|
347
364
|
classifier=classifier
|
|
@@ -367,14 +384,27 @@ def reconnect_action(args):
|
|
|
367
384
|
content=parent_content
|
|
368
385
|
)
|
|
369
386
|
|
|
370
|
-
|
|
387
|
+
contribution = Contribution(
|
|
371
388
|
artefact_name=parent.title,
|
|
372
389
|
classifier=parent.artefact_type
|
|
373
390
|
)
|
|
391
|
+
|
|
392
|
+
if rule:
|
|
393
|
+
try:
|
|
394
|
+
closest_rule = find_closest_rule(parent, rule)
|
|
395
|
+
contribution.rule = closest_rule
|
|
396
|
+
feedback_message += f" using rule '{closest_rule}'"
|
|
397
|
+
except TypeError as e:
|
|
398
|
+
print(f"{type(e).__name__}:", e)
|
|
399
|
+
exit(1)
|
|
400
|
+
|
|
401
|
+
artefact.contribution = contribution
|
|
374
402
|
with open(artefact.file_path, 'w') as file:
|
|
375
403
|
artefact_content = artefact.serialize()
|
|
376
404
|
file.write(artefact_content)
|
|
377
405
|
|
|
406
|
+
print(feedback_message + ".")
|
|
407
|
+
|
|
378
408
|
|
|
379
409
|
def read_status_action(args):
|
|
380
410
|
from ara_cli.file_classifier import FileClassifier
|
ara_cli/ara_command_parser.py
CHANGED
|
@@ -18,6 +18,7 @@ def create_parser(subparsers):
|
|
|
18
18
|
contribution_parser = option_parser.add_parser("contributes-to")
|
|
19
19
|
contribution_parser.add_argument("parent_classifier", choices=classifiers, help="Classifier of the parent")
|
|
20
20
|
contribution_parser.add_argument("parent_name", help="Name of a parent artefact").completer = ParentNameCompleter()
|
|
21
|
+
contribution_parser.add_argument("-r", "--rule", dest="rule", action="store")
|
|
21
22
|
|
|
22
23
|
aspect_parser = option_parser.add_parser("aspect")
|
|
23
24
|
aspect_parser.add_argument("aspect", choices=aspects, help="Adds additional specification breakdown aspects in data directory.")
|
|
@@ -70,12 +71,16 @@ def add_filter_flags(parser):
|
|
|
70
71
|
extension_group.add_argument(
|
|
71
72
|
"-i",
|
|
72
73
|
"--include-extension",
|
|
74
|
+
"--include-classifier",
|
|
75
|
+
dest="include_extension",
|
|
73
76
|
nargs='+',
|
|
74
77
|
help='list of extensions to include in listing'
|
|
75
78
|
)
|
|
76
79
|
extension_group.add_argument(
|
|
77
80
|
"-e",
|
|
78
81
|
"--exclude-extension",
|
|
82
|
+
"--exclude-classifier",
|
|
83
|
+
dest="exclude_extension",
|
|
79
84
|
nargs='+',
|
|
80
85
|
help='list of extensions to exclude from listing'
|
|
81
86
|
)
|
|
@@ -121,6 +126,7 @@ def list_tags_parser(subparsers):
|
|
|
121
126
|
tags_parser = subparsers.add_parser("list-tags", help="Show tags")
|
|
122
127
|
tags_parser.add_argument("--json", "-j", help="Output tags as JSON", action=argparse.BooleanOptionalAction)
|
|
123
128
|
tags_parser.add_argument("--include-classifier", choices=classifiers, help="Show tags for an artefact type")
|
|
129
|
+
tags_parser.add_argument("--exclude_classifier", choices=classifiers, help="Show tags for an artefact type")
|
|
124
130
|
tags_parser.add_argument("--filtered-extra-column", action="store_true", help="Filter tags for extra column")
|
|
125
131
|
|
|
126
132
|
|
|
@@ -184,6 +190,7 @@ def reconnect_parser(subparsers):
|
|
|
184
190
|
reconnect_parser.add_argument("parameter", help="Filename of artefact").completer = ArtefactCompleter()
|
|
185
191
|
reconnect_parser.add_argument("parent_classifier", choices=classifiers, help="Classifier of the parent artefact type")
|
|
186
192
|
reconnect_parser.add_argument("parent_name", help="Filename of parent artefact").completer = ParentNameCompleter()
|
|
193
|
+
reconnect_parser.add_argument("-r", "--rule", dest="rule", action="store")
|
|
187
194
|
|
|
188
195
|
|
|
189
196
|
def read_status_parser(subparsers):
|
ara_cli/artefact_autofix.py
CHANGED
|
@@ -83,9 +83,8 @@ def construct_prompt(artefact_type, reason, file_path, artefact_text):
|
|
|
83
83
|
|
|
84
84
|
prompt = (
|
|
85
85
|
f"Correct the following {artefact_type} artefact to fix the issue: {reason}. "
|
|
86
|
-
"Provide the
|
|
86
|
+
"Provide the corrected artefact. Do not reformulate the artefact, "
|
|
87
87
|
"just fix the pydantic model errors, use correct grammar. "
|
|
88
|
-
"Do not remove comments. "
|
|
89
88
|
"You should follow the name of the file "
|
|
90
89
|
f"from its path {file_path} for naming the arteafact's title. "
|
|
91
90
|
"You are not allowed to use file extention in the artefact title. "
|
|
@@ -114,7 +113,7 @@ def run_agent(prompt, artefact_class):
|
|
|
114
113
|
from pydantic_ai import Agent
|
|
115
114
|
# gpt-4o
|
|
116
115
|
# anthropic:claude-3-7-sonnet-20250219
|
|
117
|
-
agent = Agent(model="
|
|
116
|
+
agent = Agent(model="anthropic:claude-3-7-sonnet-20250219",
|
|
118
117
|
result_type=artefact_class, instrument=True)
|
|
119
118
|
result = agent.run_sync(prompt)
|
|
120
119
|
return result.data
|
ara_cli/artefact_creator.py
CHANGED
|
@@ -87,7 +87,7 @@ class ArtefactCreator:
|
|
|
87
87
|
artefact._parent = matching_artefacts[0]
|
|
88
88
|
return artefact
|
|
89
89
|
|
|
90
|
-
def run(self, filename, classifier, parent_classifier=None, parent_name=None):
|
|
90
|
+
def run(self, filename, classifier, parent_classifier=None, parent_name=None, rule=None):
|
|
91
91
|
# make sure this function is always called from the ara top level directory
|
|
92
92
|
original_directory = os.getcwd()
|
|
93
93
|
navigator = DirectoryNavigator()
|
|
@@ -111,7 +111,8 @@ class ArtefactCreator:
|
|
|
111
111
|
if parent_classifier and parent_name:
|
|
112
112
|
artefact.set_contribution(
|
|
113
113
|
artefact_name=parent_name,
|
|
114
|
-
classifier=parent_classifier
|
|
114
|
+
classifier=parent_classifier,
|
|
115
|
+
rule=rule
|
|
115
116
|
)
|
|
116
117
|
|
|
117
118
|
artefact_content = artefact.serialize()
|
ara_cli/artefact_fuzzy_search.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import difflib
|
|
2
|
+
from textwrap import indent
|
|
2
3
|
from typing import Optional
|
|
3
4
|
|
|
4
5
|
|
|
5
|
-
def suggest_close_names(artefact_name: str, all_artefact_names: list[str], message: str):
|
|
6
|
-
closest_matches = difflib.get_close_matches(artefact_name, all_artefact_names, cutoff=
|
|
6
|
+
def suggest_close_names(artefact_name: str, all_artefact_names: list[str], message: str, cutoff=0.5):
|
|
7
|
+
closest_matches = difflib.get_close_matches(artefact_name, all_artefact_names, cutoff=cutoff)
|
|
7
8
|
print(message)
|
|
8
9
|
if not closest_matches:
|
|
9
10
|
return
|
|
@@ -38,3 +39,21 @@ def find_closest_name_match(artefact_name: str, all_artefact_names: list[str]) -
|
|
|
38
39
|
return None
|
|
39
40
|
closest_match = closest_matches[0]
|
|
40
41
|
return closest_match
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def find_closest_rule(parent_artefact: 'Artefact', rule: str):
|
|
45
|
+
parent_classifier = parent_artefact.artefact_type.value
|
|
46
|
+
parent_title = parent_artefact.title
|
|
47
|
+
if not hasattr(parent_artefact, 'rules'):
|
|
48
|
+
raise TypeError(f"{parent_classifier.capitalize()} artefact '{parent_title}' can not possess rules. Only userstories and epics have rules.")
|
|
49
|
+
rules = parent_artefact.rules
|
|
50
|
+
if rule in rules:
|
|
51
|
+
return rule
|
|
52
|
+
print(f"Rule '{rule}' does not match existing rules in {parent_classifier} artefact '{parent_title}'. Attempting to find closest match among existing rules.")
|
|
53
|
+
closest_matches = difflib.get_close_matches(rule, rules, cutoff=0.5)
|
|
54
|
+
rules_list_string = indent('\n'.join(rules), prefix='\t- ')
|
|
55
|
+
if not closest_matches:
|
|
56
|
+
raise ValueError(f"Can not determine a match for rule '{rule}' in {parent_classifier} artefact '{parent_title}'. Found rules:\n{rules_list_string}")
|
|
57
|
+
closest_match = closest_matches[0]
|
|
58
|
+
print(f"Found closest matching rule of '{closest_match}'")
|
|
59
|
+
return closest_match
|
|
@@ -401,9 +401,10 @@ class Artefact(BaseModel, ABC):
|
|
|
401
401
|
return description
|
|
402
402
|
return f"{description}{self.description}"
|
|
403
403
|
|
|
404
|
-
def set_contribution(self, artefact_name, classifier):
|
|
404
|
+
def set_contribution(self, artefact_name, classifier, rule=None):
|
|
405
405
|
contribution = Contribution(
|
|
406
406
|
artefact_name=artefact_name,
|
|
407
|
-
classifier=classifier
|
|
407
|
+
classifier=classifier,
|
|
408
|
+
rule=rule
|
|
408
409
|
)
|
|
409
410
|
self.contribution = contribution
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pydantic import BaseModel, field_validator, model_validator, Field
|
|
2
|
-
from typing import List, Dict, Tuple, Union
|
|
2
|
+
from typing import List, Dict, Tuple, Union, Optional
|
|
3
3
|
from ara_cli.artefact_models.artefact_model import Artefact, ArtefactType, Intent
|
|
4
4
|
import re
|
|
5
5
|
|
|
@@ -98,6 +98,35 @@ class Example(BaseModel):
|
|
|
98
98
|
return cls(values=values)
|
|
99
99
|
|
|
100
100
|
|
|
101
|
+
class Background(BaseModel):
|
|
102
|
+
steps: List[str] = Field(
|
|
103
|
+
description="A list of Gherkin 'Given' type steps that describe what the background does."
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
@field_validator('steps', mode='before')
|
|
107
|
+
def validate_steps(cls, v: List[str]) -> List[str]:
|
|
108
|
+
"""Ensure steps are non-empty and stripped."""
|
|
109
|
+
steps = [step.strip() for step in v if step.strip()]
|
|
110
|
+
if not steps:
|
|
111
|
+
raise ValueError("steps list must not be empty")
|
|
112
|
+
return steps
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def from_lines(cls, lines: List[str], start_idx: int) -> Tuple['Background', int]:
|
|
116
|
+
"""Parse a Background from a list of lines starting at start_idx."""
|
|
117
|
+
if not lines[start_idx].startswith('Background:'):
|
|
118
|
+
raise ValueError("Expected 'Background:' at start index")
|
|
119
|
+
|
|
120
|
+
steps = []
|
|
121
|
+
idx = start_idx + 1
|
|
122
|
+
while idx < len(lines) and not lines[idx].startswith('Background:'):
|
|
123
|
+
step = lines[idx].strip()
|
|
124
|
+
if step:
|
|
125
|
+
steps.append(step)
|
|
126
|
+
idx += 1
|
|
127
|
+
return cls(steps=steps), idx
|
|
128
|
+
|
|
129
|
+
|
|
101
130
|
class Scenario(BaseModel):
|
|
102
131
|
title: str = Field(
|
|
103
132
|
description="The name of the scenario, giving a short summary of the test case. It comes from the 'Scenario:' line in the feature file."
|
|
@@ -213,6 +242,8 @@ class FeatureArtefact(Artefact):
|
|
|
213
242
|
artefact_type: ArtefactType = ArtefactType.feature
|
|
214
243
|
intent: FeatureIntent
|
|
215
244
|
scenarios: List[Union[Scenario, ScenarioOutline]] = Field(default=None)
|
|
245
|
+
background: Optional[Background] = Field(
|
|
246
|
+
default=None, description="Highly optional background Gherkin steps for Feature Artefacts. This steps apply for all scenarios and scenario outlines in this feature file.")
|
|
216
247
|
|
|
217
248
|
@field_validator('artefact_type')
|
|
218
249
|
def validate_artefact_type(cls, v):
|
|
@@ -229,6 +260,16 @@ class FeatureArtefact(Artefact):
|
|
|
229
260
|
def _artefact_type(cls) -> ArtefactType:
|
|
230
261
|
return ArtefactType.feature
|
|
231
262
|
|
|
263
|
+
def _serialize_background(self) -> str:
|
|
264
|
+
"""Helper method to dispatch background serialization."""
|
|
265
|
+
if not self.background:
|
|
266
|
+
return ""
|
|
267
|
+
lines = []
|
|
268
|
+
lines.append(" Background:")
|
|
269
|
+
for step in self.background.steps:
|
|
270
|
+
lines.append(f" {step}")
|
|
271
|
+
return "\n".join(lines)
|
|
272
|
+
|
|
232
273
|
def _serialize_scenario(self, scenario: Union[Scenario, ScenarioOutline]) -> str:
|
|
233
274
|
"""Helper method to dispatch scenario serialization."""
|
|
234
275
|
if isinstance(scenario, Scenario):
|
|
@@ -309,6 +350,10 @@ class FeatureArtefact(Artefact):
|
|
|
309
350
|
lines.append(description)
|
|
310
351
|
lines.append("")
|
|
311
352
|
|
|
353
|
+
if self.background:
|
|
354
|
+
lines.append(self._serialize_background())
|
|
355
|
+
lines.append("")
|
|
356
|
+
|
|
312
357
|
if self.scenarios:
|
|
313
358
|
for scenario in self.scenarios:
|
|
314
359
|
lines.append(self._serialize_scenario(scenario))
|
|
@@ -321,9 +366,11 @@ class FeatureArtefact(Artefact):
|
|
|
321
366
|
fields = super()._parse_common_fields(text)
|
|
322
367
|
|
|
323
368
|
intent = FeatureIntent.deserialize(text)
|
|
369
|
+
background = cls.deserialize_background(text)
|
|
324
370
|
scenarios = cls.deserialize_scenarios(text)
|
|
325
371
|
|
|
326
372
|
fields['scenarios'] = scenarios
|
|
373
|
+
fields['background'] = background
|
|
327
374
|
fields['intent'] = intent
|
|
328
375
|
|
|
329
376
|
return cls(**fields)
|
|
@@ -348,3 +395,19 @@ class FeatureArtefact(Artefact):
|
|
|
348
395
|
else:
|
|
349
396
|
idx += 1
|
|
350
397
|
return scenarios
|
|
398
|
+
|
|
399
|
+
@classmethod
|
|
400
|
+
def deserialize_background(cls, text):
|
|
401
|
+
lines = [line.strip()
|
|
402
|
+
for line in text.strip().splitlines() if line.strip()]
|
|
403
|
+
|
|
404
|
+
background = None
|
|
405
|
+
idx = 0
|
|
406
|
+
while idx < len(lines):
|
|
407
|
+
line = lines[idx].strip()
|
|
408
|
+
if line.startswith('Background:'):
|
|
409
|
+
background, next_idx = Background.from_lines(lines, idx)
|
|
410
|
+
break
|
|
411
|
+
else:
|
|
412
|
+
idx += 1
|
|
413
|
+
return background
|
ara_cli/artefact_reader.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from ara_cli.classifier import Classifier
|
|
2
2
|
from ara_cli.file_classifier import FileClassifier
|
|
3
3
|
from ara_cli.artefact_models.artefact_model import Artefact
|
|
4
|
+
from ara_cli.artefact_models.artefact_load import artefact_from_content
|
|
4
5
|
from ara_cli.artefact_fuzzy_search import suggest_close_name_matches_for_parent, suggest_close_name_matches
|
|
5
6
|
from typing import Dict, List
|
|
6
7
|
import os
|
|
@@ -9,7 +10,7 @@ import re
|
|
|
9
10
|
|
|
10
11
|
class ArtefactReader:
|
|
11
12
|
@staticmethod
|
|
12
|
-
def read_artefact(artefact_name, classifier):
|
|
13
|
+
def read_artefact(artefact_name, classifier) -> tuple[str, dict[str, str]]:
|
|
13
14
|
if not Classifier.is_valid_classifier(classifier):
|
|
14
15
|
print("Invalid classifier provided. Please provide a valid classifier.")
|
|
15
16
|
return None, None
|
|
@@ -34,6 +35,27 @@ class ArtefactReader:
|
|
|
34
35
|
|
|
35
36
|
return None, None
|
|
36
37
|
|
|
38
|
+
@staticmethod
|
|
39
|
+
def read_single_artefact(artefact_name, classifier, classified_file_info=None) -> Artefact:
|
|
40
|
+
if not Classifier.is_valid_classifier(classifier):
|
|
41
|
+
print("Invalid classifier provided. Please provide a valid classifier.")
|
|
42
|
+
return None
|
|
43
|
+
if not classified_file_info:
|
|
44
|
+
file_classifier = FileClassifier(os)
|
|
45
|
+
classified_file_info = file_classifier.classify_files()
|
|
46
|
+
artefact_info_of_classifier = classified_file_info.get(classifier, [])
|
|
47
|
+
|
|
48
|
+
for artefact_info in artefact_info_of_classifier:
|
|
49
|
+
file_path = artefact_info["file_path"]
|
|
50
|
+
artefact_title = artefact_info["title"]
|
|
51
|
+
if artefact_title == artefact_name:
|
|
52
|
+
with open(file_path, 'r') as file:
|
|
53
|
+
content = file.read()
|
|
54
|
+
artefact = artefact_from_content(content)
|
|
55
|
+
artefact._file_path = file_path
|
|
56
|
+
return artefact
|
|
57
|
+
return None
|
|
58
|
+
|
|
37
59
|
@staticmethod
|
|
38
60
|
def extract_parent_tree(artefact_content):
|
|
39
61
|
artefact_titles = Classifier.artefact_titles()
|
ara_cli/prompt_extractor.py
CHANGED
|
@@ -184,10 +184,14 @@ def handle_existing_file(filename, block_content):
|
|
|
184
184
|
create_file_if_not_exist(filename, block_content)
|
|
185
185
|
else:
|
|
186
186
|
print(f"File {filename} exists, creating modification prompt")
|
|
187
|
-
|
|
187
|
+
prompt_text = create_prompt_for_file_modification(block_content, filename)
|
|
188
|
+
messages = [{"role": "user", "content": prompt_text}]
|
|
188
189
|
response = ""
|
|
189
|
-
|
|
190
|
-
|
|
190
|
+
|
|
191
|
+
for chunk in send_prompt(messages):
|
|
192
|
+
content = chunk.choices[0].delta.content
|
|
193
|
+
if content:
|
|
194
|
+
response += content
|
|
191
195
|
modify_and_save_file(response, filename)
|
|
192
196
|
|
|
193
197
|
|
ara_cli/prompt_handler.py
CHANGED
|
@@ -355,8 +355,12 @@ def prepend_system_prompt(message_list):
|
|
|
355
355
|
|
|
356
356
|
|
|
357
357
|
def append_images_to_message(message, image_data_list):
|
|
358
|
-
|
|
359
|
-
|
|
358
|
+
if not image_data_list:
|
|
359
|
+
return message
|
|
360
|
+
new_content_list = [{"type": "text", "text": message}]
|
|
361
|
+
new_content_list.extend(image_data_list)
|
|
362
|
+
|
|
363
|
+
message["content"] = new_content_list
|
|
360
364
|
|
|
361
365
|
return message
|
|
362
366
|
|
|
@@ -376,14 +380,23 @@ def create_and_send_custom_prompt(classifier, parameter):
|
|
|
376
380
|
append_headings(classifier, parameter, "prompt")
|
|
377
381
|
write_prompt_result(classifier, parameter, prompt)
|
|
378
382
|
|
|
379
|
-
|
|
380
|
-
|
|
383
|
+
base_message = {
|
|
384
|
+
"role": "user",
|
|
385
|
+
"content": combined_content_markdown
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
final_message = append_images_to_message(base_message, image_data_list)
|
|
381
389
|
|
|
390
|
+
message_list_to_send = [final_message]
|
|
391
|
+
|
|
392
|
+
append_headings(classifier, parameter, "result")
|
|
382
393
|
artefact_data_path = f"ara/{sub_directory}/{parameter}.data/{classifier}.prompt_log.md"
|
|
383
394
|
with open(artefact_data_path, 'a') as file:
|
|
384
|
-
for chunk in send_prompt(
|
|
385
|
-
|
|
386
|
-
|
|
395
|
+
for chunk in send_prompt(message_list_to_send):
|
|
396
|
+
content = chunk.choices[0].delta.content
|
|
397
|
+
if content:
|
|
398
|
+
file.write(content)
|
|
399
|
+
file.flush()
|
|
387
400
|
# write_prompt_result(classifier, parameter, response)
|
|
388
401
|
|
|
389
402
|
|
ara_cli/tag_extractor.py
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from ara_cli.
|
|
2
|
+
from ara_cli.list_filter import ListFilter, filter_list
|
|
3
|
+
from ara_cli.artefact_lister import ArtefactLister
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
class TagExtractor:
|
|
6
7
|
def __init__(self, file_system=None):
|
|
7
8
|
self.file_system = file_system or os
|
|
8
9
|
|
|
9
|
-
def extract_tags(
|
|
10
|
+
def extract_tags(
|
|
11
|
+
self,
|
|
12
|
+
navigate_to_target=False,
|
|
13
|
+
filtered_extra_column=False,
|
|
14
|
+
list_filter: ListFilter | None = None
|
|
15
|
+
):
|
|
10
16
|
from ara_cli.template_manager import DirectoryNavigator
|
|
11
17
|
from ara_cli.artefact_reader import ArtefactReader
|
|
12
18
|
|
|
@@ -16,24 +22,29 @@ class TagExtractor:
|
|
|
16
22
|
|
|
17
23
|
artefacts = ArtefactReader.read_artefacts()
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
filtered_artefacts = filter_list(
|
|
26
|
+
list_to_filter=artefacts,
|
|
27
|
+
list_filter=list_filter,
|
|
28
|
+
content_retrieval_strategy=ArtefactLister.artefact_content_retrieval,
|
|
29
|
+
file_path_retrieval=ArtefactLister.artefact_path_retrieval,
|
|
30
|
+
tag_retrieval=ArtefactLister.artefact_tags_retrieval
|
|
31
|
+
)
|
|
21
32
|
|
|
22
33
|
unique_tags = set()
|
|
23
34
|
|
|
24
35
|
if filtered_extra_column:
|
|
25
36
|
status_tags = {"to-do", "in-progress", "review", "done", "closed"}
|
|
26
|
-
|
|
37
|
+
artefacts_to_process = []
|
|
27
38
|
|
|
28
|
-
for artefact_list in
|
|
39
|
+
for artefact_list in filtered_artefacts.values():
|
|
29
40
|
for artefact in artefact_list:
|
|
30
41
|
tags = artefact.tags + \
|
|
31
42
|
[artefact.status] if artefact.status else artefact.tags
|
|
32
43
|
tag_set = set(tag for tag in tags if tag is not None)
|
|
33
44
|
if not tag_set & status_tags:
|
|
34
|
-
|
|
45
|
+
artefacts_to_process.append(artefact)
|
|
35
46
|
|
|
36
|
-
for artefact in
|
|
47
|
+
for artefact in artefacts_to_process:
|
|
37
48
|
tags = [tag for tag in (
|
|
38
49
|
artefact.tags + [artefact.status]) if tag is not None]
|
|
39
50
|
for tag in tags:
|
|
@@ -46,7 +57,7 @@ class TagExtractor:
|
|
|
46
57
|
unique_tags.add(tag)
|
|
47
58
|
|
|
48
59
|
else:
|
|
49
|
-
for artefact_list in
|
|
60
|
+
for artefact_list in filtered_artefacts.values():
|
|
50
61
|
for artefact in artefact_list:
|
|
51
62
|
user_tags = [f"user_{tag}" for tag in artefact.users]
|
|
52
63
|
tags = [tag for tag in (artefact.tags + [artefact.status] + user_tags) if tag is not None]
|
|
@@ -26,8 +26,10 @@ def mock_dependencies():
|
|
|
26
26
|
"ara_cli.filename_validator.is_valid_filename"
|
|
27
27
|
) as mock_is_valid_filename, patch(
|
|
28
28
|
"ara_cli.template_manager.SpecificationBreakdownAspects"
|
|
29
|
-
) as MockSpecificationBreakdownAspects
|
|
30
|
-
|
|
29
|
+
) as MockSpecificationBreakdownAspects, patch(
|
|
30
|
+
"ara_cli.artefact_fuzzy_search.find_closest_rule"
|
|
31
|
+
) as mock_find_closest_rule:
|
|
32
|
+
yield MockArtefactCreator, MockClassifier, mock_is_valid_filename, MockSpecificationBreakdownAspects, mock_find_closest_rule
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
@pytest.fixture
|
|
@@ -129,9 +131,11 @@ def test_create_action_validity_checks(
|
|
|
129
131
|
MockClassifier,
|
|
130
132
|
mock_is_valid_filename,
|
|
131
133
|
MockSpecificationBreakdownAspects,
|
|
134
|
+
mock_find_closest_rule,
|
|
132
135
|
) = mock_dependencies
|
|
133
136
|
MockClassifier.is_valid_classifier.return_value = classifier_valid
|
|
134
137
|
mock_is_valid_filename.return_value = filename_valid
|
|
138
|
+
mock_find_closest_rule.return_value = None
|
|
135
139
|
|
|
136
140
|
args = MagicMock()
|
|
137
141
|
args.classifier = "test_classifier"
|
|
@@ -1,54 +1,83 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
from unittest.mock import MagicMock, patch
|
|
3
3
|
from ara_cli.tag_extractor import TagExtractor
|
|
4
|
+
from ara_cli.list_filter import ListFilter
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
@pytest.fixture
|
|
7
8
|
def artefact():
|
|
8
9
|
"""Fixture to create a mock artefact object."""
|
|
9
10
|
class Artefact:
|
|
10
|
-
def __init__(self, tags, status, users):
|
|
11
|
+
def __init__(self, tags, status, users, path="dummy.md", content=""):
|
|
11
12
|
self.tags = tags
|
|
12
13
|
self.status = status
|
|
13
14
|
self.users = users
|
|
15
|
+
self.path = path
|
|
16
|
+
self.content = content
|
|
14
17
|
return Artefact
|
|
15
18
|
|
|
16
19
|
|
|
17
|
-
@pytest.mark.parametrize("navigate_to_target,
|
|
18
|
-
(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
@pytest.mark.parametrize("navigate_to_target, filtered_extra_column, list_filter, artefact_data, expected_tags", [
|
|
21
|
+
(
|
|
22
|
+
False, False, None,
|
|
23
|
+
{'artefacts': [
|
|
24
|
+
(['tag1', 'tag2'], 'in-progress', ['user1']),
|
|
25
|
+
(['tag3'], 'done', ['user2'])
|
|
26
|
+
]},
|
|
27
|
+
['done', 'in-progress', 'tag1', 'tag2', 'tag3', 'user_user1', 'user_user2']
|
|
28
|
+
),
|
|
29
|
+
(
|
|
30
|
+
False, True, None,
|
|
31
|
+
{'artefacts': [
|
|
32
|
+
(['project_a', 'priority_high'], None, ['user1']),
|
|
33
|
+
(['feature_x'], 'done', ['user2'])
|
|
34
|
+
]},
|
|
35
|
+
['project_a']
|
|
36
|
+
),
|
|
37
|
+
(
|
|
38
|
+
False, False, ListFilter(include_tags=['@kritik']),
|
|
39
|
+
{'artefacts': [
|
|
40
|
+
(['release', 'kritik'], 'review', ['dev1']),
|
|
41
|
+
(['bugfix'], 'to-do', ['dev2'])
|
|
42
|
+
]},
|
|
43
|
+
['kritik', 'release', 'review', 'user_dev1']
|
|
44
|
+
),
|
|
45
|
+
(
|
|
46
|
+
True, False, None,
|
|
47
|
+
{'artefacts': [
|
|
48
|
+
(['tag3'], 'status2', ['user3'])
|
|
49
|
+
]},
|
|
50
|
+
['status2', 'tag3', 'user_user3']
|
|
51
|
+
),
|
|
52
|
+
(
|
|
53
|
+
False, False, None,
|
|
54
|
+
{'artefacts': []},
|
|
55
|
+
[]
|
|
56
|
+
),
|
|
30
57
|
])
|
|
31
|
-
@patch('ara_cli.template_manager.DirectoryNavigator')
|
|
32
58
|
@patch('ara_cli.artefact_reader.ArtefactReader')
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
59
|
+
@patch('ara_cli.template_manager.DirectoryNavigator')
|
|
60
|
+
def test_extract_tags(mock_directory_navigator, mock_artefact_reader, artefact, navigate_to_target, filtered_extra_column, list_filter, artefact_data, expected_tags):
|
|
61
|
+
mock_artefacts = {key: [artefact(
|
|
36
62
|
*data) for data in artefact_list] for key, artefact_list in artefact_data.items()}
|
|
63
|
+
mock_artefact_reader.read_artefacts.return_value = mock_artefacts
|
|
37
64
|
|
|
38
|
-
# Mock the directory navigator
|
|
39
65
|
mock_navigator_instance = mock_directory_navigator.return_value
|
|
40
66
|
mock_navigator_instance.navigate_to_target = MagicMock()
|
|
41
67
|
|
|
42
68
|
tag_extractor = TagExtractor()
|
|
43
69
|
|
|
44
|
-
# Run the extract_tags method with include_classifier
|
|
45
70
|
result = tag_extractor.extract_tags(
|
|
46
|
-
navigate_to_target=navigate_to_target,
|
|
71
|
+
navigate_to_target=navigate_to_target,
|
|
72
|
+
filtered_extra_column=filtered_extra_column,
|
|
73
|
+
list_filter=list_filter
|
|
74
|
+
)
|
|
47
75
|
|
|
48
|
-
# Assertions
|
|
49
76
|
if navigate_to_target:
|
|
50
77
|
mock_navigator_instance.navigate_to_target.assert_called_once()
|
|
51
78
|
else:
|
|
52
79
|
mock_navigator_instance.navigate_to_target.assert_not_called()
|
|
53
80
|
|
|
54
|
-
|
|
81
|
+
mock_artefact_reader.read_artefacts.assert_called_once()
|
|
82
|
+
|
|
83
|
+
assert sorted(result) == sorted(expected_tags)
|
ara_cli/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# version.py
|
|
2
|
-
__version__ = "0.1.9.
|
|
2
|
+
__version__ = "0.1.9.65" # fith parameter like .0 for local install test purposes only. official numbers should be 4 digit numbers
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
ara_cli/__init__.py,sha256=0zl7IegxTid26EBGLav_fXZ4CCIV3H5TfAoFQiOHjvg,148
|
|
2
2
|
ara_cli/__main__.py,sha256=Z6XYWRLceIoZPvfC-X9EXouSZdtFOOe84kKVWJGA4r4,1861
|
|
3
|
-
ara_cli/ara_command_action.py,sha256=
|
|
4
|
-
ara_cli/ara_command_parser.py,sha256=
|
|
3
|
+
ara_cli/ara_command_action.py,sha256=NN1DrmTEbLAUUHIFINDaLyp8gmKZA9cFw4cED0CFe9U,21177
|
|
4
|
+
ara_cli/ara_command_parser.py,sha256=HHPHLYzvn2bGVjwZ7fhdKgwiHHJDbERRdLcTe8G9B1Q,17588
|
|
5
5
|
ara_cli/ara_config.py,sha256=_Arkr-b9XnrNHbBlFKb9tAo3OmdP4ZZiWvbY9m6Sbo0,4178
|
|
6
|
-
ara_cli/artefact_autofix.py,sha256=
|
|
7
|
-
ara_cli/artefact_creator.py,sha256=
|
|
6
|
+
ara_cli/artefact_autofix.py,sha256=T0TJ6vBxveMoOKm6c22c6D-iMuBHlCksvNLil_O6xaM,4885
|
|
7
|
+
ara_cli/artefact_creator.py,sha256=tUNCNvfFYMheyF_viyrQhm2-43AkbHFoQaHui9ntvws,6002
|
|
8
8
|
ara_cli/artefact_deleter.py,sha256=Co4wwCH3yW8H9NrOq7_2p5571EeHr0TsfE-H8KqoOfY,1900
|
|
9
|
-
ara_cli/artefact_fuzzy_search.py,sha256=
|
|
9
|
+
ara_cli/artefact_fuzzy_search.py,sha256=BBDe-IP75sWZjG6nTNFtVljjL01JlQUy5ccJBZ6Trow,2429
|
|
10
10
|
ara_cli/artefact_link_updater.py,sha256=itMS_Z64jE8bBly9WA01z8PqkBeNW6ntTO7ryMeCTRg,3703
|
|
11
11
|
ara_cli/artefact_lister.py,sha256=jhk4n4eqp7hDIq07q43QzS7-36BM3OfZ4EABxCeOGcw,4764
|
|
12
|
-
ara_cli/artefact_reader.py,sha256=
|
|
12
|
+
ara_cli/artefact_reader.py,sha256=_RqBY1f1DWH2DThXETYuHeTB2ip0wgYuGvHYI_D6EJ4,8062
|
|
13
13
|
ara_cli/artefact_renamer.py,sha256=loIn1DF9kVnjhH7wP1v5qUvt3s0uKeWXuQPrHXenQGE,4025
|
|
14
14
|
ara_cli/artefact_scan.py,sha256=7PH7TE2B2Py7wGQxl7EYM3r6Fr9kVLAFtNErP0QRoXM,1950
|
|
15
15
|
ara_cli/chat.py,sha256=7xTtPEDk052_wmIzoti7GavEJ1vpRxe5c084WQ1C7dg,28617
|
|
@@ -24,23 +24,23 @@ ara_cli/filename_validator.py,sha256=Aw9PL8d5-Ymhp3EY6lDrUBk3cudaNqo1Uw5RzPpI1jA
|
|
|
24
24
|
ara_cli/list_filter.py,sha256=Not17hIngI37gZsLtIKxopB-BmyWoOGlBzSqBwh-Zpc,5273
|
|
25
25
|
ara_cli/output_suppressor.py,sha256=ZByUwLH2DxOb-eJ31KQbtIziBKdykoyxvwxZ0tSammA,371
|
|
26
26
|
ara_cli/prompt_chat.py,sha256=kd_OINDQFit6jN04bb7mzgY259JBbRaTaNp9F-webkc,1346
|
|
27
|
-
ara_cli/prompt_extractor.py,sha256=
|
|
28
|
-
ara_cli/prompt_handler.py,sha256=
|
|
27
|
+
ara_cli/prompt_extractor.py,sha256=a8LwPj6U8sG_v3SqDXQyPvDZQds4kHnYSO8eGissYJA,7503
|
|
28
|
+
ara_cli/prompt_handler.py,sha256=1gz2VkK7zl0RAzit1UmxplNNd2Zu6J_7eHocgKiw_hQ,17473
|
|
29
29
|
ara_cli/prompt_rag.py,sha256=vmlt4-rSboWibwgO_KUF79TK99YXT5KXjmbD9FeWdZY,7449
|
|
30
30
|
ara_cli/run_file_lister.py,sha256=XbrrDTJXp1LFGx9Lv91SNsEHZPP-PyEMBF_P4btjbDA,2360
|
|
31
|
-
ara_cli/tag_extractor.py,sha256=
|
|
31
|
+
ara_cli/tag_extractor.py,sha256=4krQyvmLR2ffhe7N7lWC7QjaxXcb90HaQdmjnBiD8ak,2523
|
|
32
32
|
ara_cli/template_manager.py,sha256=YXPj2jGNDb-diIHFEK_vGJ-ZucodnXSGAPofKTnOofI,6633
|
|
33
33
|
ara_cli/update_config_prompt.py,sha256=PZgNIN3dTw6p80GyX8Sp5apkAhSoykwnkEbHo3IOkUo,4571
|
|
34
|
-
ara_cli/version.py,sha256=
|
|
34
|
+
ara_cli/version.py,sha256=1Z37icnDfTLV_xa6229A5btyIc1fDW2rl72E31bdi5s,146
|
|
35
35
|
ara_cli/artefact_models/artefact_load.py,sha256=dNcwZDW2Dk0bts9YnPZ0ESmWD2NbsLIvl4Z-qQeGmTQ,401
|
|
36
36
|
ara_cli/artefact_models/artefact_mapping.py,sha256=8aD0spBjkJ8toMAmFawc6UTUxB6-tEEViZXv2I-r88Q,1874
|
|
37
|
-
ara_cli/artefact_models/artefact_model.py,sha256=
|
|
37
|
+
ara_cli/artefact_models/artefact_model.py,sha256=SRVfeHVKCMJ8L9lqPzAr_MgI4m7mGdcYx0SE2ja-NEI,14949
|
|
38
38
|
ara_cli/artefact_models/artefact_templates.py,sha256=Vd7SwoRVKNGKZmxBKS6f9FE1ThUOCqZLScu0ClPfIu8,8321
|
|
39
39
|
ara_cli/artefact_models/businessgoal_artefact_model.py,sha256=jqYFMXjWle0YW9RvcFLDBAwy61bdT5VuDT_6lTOFzMw,4853
|
|
40
40
|
ara_cli/artefact_models/capability_artefact_model.py,sha256=SZqHx4O2mj4urn77Stnj4_Jxtlq3-LgBBU9SMkByppI,3079
|
|
41
41
|
ara_cli/artefact_models/epic_artefact_model.py,sha256=IadQWs6SWNcLgwvtOQWmYDyV9xLr3WwAsx-YMFan5fA,5765
|
|
42
42
|
ara_cli/artefact_models/example_artefact_model.py,sha256=UXrKbaPotg1jwcrVSdCeo-XH4tTD_-U1e3giaBn5_xg,1384
|
|
43
|
-
ara_cli/artefact_models/feature_artefact_model.py,sha256=
|
|
43
|
+
ara_cli/artefact_models/feature_artefact_model.py,sha256=BeLsq9ZinzIDwss8nurIbxJZQ2qPgyRKRHrRlrl-zHA,15583
|
|
44
44
|
ara_cli/artefact_models/issue_artefact_model.py,sha256=v6CpKnkqiUh6Wch2kkEmyyW49c8ysdy1qz8l1Ft9uJA,2552
|
|
45
45
|
ara_cli/artefact_models/keyfeature_artefact_model.py,sha256=a3MyAiePN9n_GTN6QkTvamdsaorwVUff6w-9CdRZSlo,4243
|
|
46
46
|
ara_cli/artefact_models/serialize_helper.py,sha256=0XCruO70-fyfLfTn7pnt8NrSQe79eYNUAjuQaV8K6_8,586
|
|
@@ -132,7 +132,7 @@ ara_cli/templates/specification_breakdown_files/template.technology.exploration.
|
|
|
132
132
|
ara_cli/templates/specification_breakdown_files/template.technology.md,sha256=bySiksz-8xtq0Nnj4svqe2MgUftWrVkbK9AcrDUE3KY,952
|
|
133
133
|
ara_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
134
134
|
ara_cli/tests/test_ara_autofix.py,sha256=8AaSuherD2dvo2wMFafgHnkLhSnMs6ZW6RtX-5VKsls,4248
|
|
135
|
-
ara_cli/tests/test_ara_command_action.py,sha256=
|
|
135
|
+
ara_cli/tests/test_ara_command_action.py,sha256=Y5MrG6VjXgebliKfdFaCaS8i3GoZCGSLpj3AWCbL5Lk,25695
|
|
136
136
|
ara_cli/tests/test_ara_config.py,sha256=1LWby_iSestTIIqK-1clggL8kmbGGbtlYfsxAHaMMF8,2232
|
|
137
137
|
ara_cli/tests/test_artefact_fuzzy_search.py,sha256=5Sh3_l9QK8-WHn6JpGPU1b6h4QEnl2JoMq1Tdp2cj1U,1261
|
|
138
138
|
ara_cli/tests/test_artefact_link_updater.py,sha256=gN5KFF1uY7OoBh8Mr5jWpqXp02YCU5OSIpSU76Rm4Gs,2137
|
|
@@ -147,11 +147,11 @@ ara_cli/tests/test_file_classifier.py,sha256=hbGp0-_A_LgQ0pGv1jWDEIyCgvDyfChcvvV
|
|
|
147
147
|
ara_cli/tests/test_file_creator.py,sha256=G257M1duenDrgLCSql3wVWNuzcxyQqLQDybfbxiGYN0,2100
|
|
148
148
|
ara_cli/tests/test_file_lister.py,sha256=f6B_vIv-wAulKH2ZGgNg4SG79XqGGbfwoIvZlbEnYyM,4306
|
|
149
149
|
ara_cli/tests/test_list_filter.py,sha256=gSRKirTtFuhRS3QlFHqWl89WvCvAdVEnFsCWTYmgB2o,7928
|
|
150
|
-
ara_cli/tests/test_tag_extractor.py,sha256=
|
|
150
|
+
ara_cli/tests/test_tag_extractor.py,sha256=nSiAYlTKZ7TLAOtcJpwK5zTWHhFYU0tI5xKnivLc1dU,2712
|
|
151
151
|
ara_cli/tests/test_template_manager.py,sha256=bRxka6cxHsCAOvXjfG8MrVO8qSZXhxW01tnph80UtNk,3143
|
|
152
152
|
ara_cli/tests/test_update_config_prompt.py,sha256=vSsLvc18HZdVjVM93qXWVbJt752xTLL6VGjSVCrPufk,6729
|
|
153
|
-
ara_cli-0.1.9.
|
|
154
|
-
ara_cli-0.1.9.
|
|
155
|
-
ara_cli-0.1.9.
|
|
156
|
-
ara_cli-0.1.9.
|
|
157
|
-
ara_cli-0.1.9.
|
|
153
|
+
ara_cli-0.1.9.65.dist-info/METADATA,sha256=nVFr74izr8-FxmQELehwrjkkIUwOQHDkAfwXeeMAFmQ,415
|
|
154
|
+
ara_cli-0.1.9.65.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
155
|
+
ara_cli-0.1.9.65.dist-info/entry_points.txt,sha256=v4h7MzysTgSIDYfEo3oj4Kz_8lzsRa3hq-KJHEcLVX8,45
|
|
156
|
+
ara_cli-0.1.9.65.dist-info/top_level.txt,sha256=zzee_PwFmKqfBi9XgIunP6xy2S4TIt593CLLxenNaAE,8
|
|
157
|
+
ara_cli-0.1.9.65.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|