ara-cli 0.1.9.50__py3-none-any.whl → 0.1.9.52__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.
@@ -1,8 +1,7 @@
1
1
  from ara_cli.file_classifier import FileClassifier
2
- from ara_cli.template_manager import DirectoryNavigator
3
2
  from ara_cli.artefact_reader import ArtefactReader
4
3
  from ara_cli.file_lister import list_files_in_directory
5
- from ara_cli.artefact import Artefact
4
+ from ara_cli.artefact_models.artefact_model import Artefact
6
5
  from ara_cli.list_filter import ListFilter, filter_list
7
6
  from ara_cli.artefact_fuzzy_search import suggest_close_name_matches
8
7
  import os
@@ -13,16 +12,26 @@ class ArtefactLister:
13
12
  self.file_system = file_system or os
14
13
 
15
14
  @staticmethod
16
- def artefact_content_retrieval(artefact):
17
- return artefact.content
15
+ def artefact_content_retrieval(artefact: Artefact):
16
+ content = artefact.serialize()
17
+ return content
18
18
 
19
19
  @staticmethod
20
- def artefact_path_retrieval(artefact):
20
+ def artefact_path_retrieval(artefact: Artefact):
21
21
  return artefact.file_path
22
22
 
23
23
  @staticmethod
24
- def artefact_tags_retrieval(artefact):
25
- return artefact.tags
24
+ def artefact_tags_retrieval(artefact: Artefact):
25
+ final_tags = []
26
+
27
+ if not artefact:
28
+ return []
29
+
30
+ final_tags.extend([f"user_{user}" for user in artefact.users])
31
+ final_tags.append(artefact.status)
32
+ final_tags.extend(artefact.tags)
33
+
34
+ return final_tags
26
35
 
27
36
  def filter_artefacts(self, classified_files: list, list_filter: ListFilter):
28
37
  filtered_list = filter_list(
@@ -40,17 +49,15 @@ class ArtefactLister:
40
49
  navigate_to_target=False,
41
50
  list_filter: ListFilter | None = None
42
51
  ):
43
- # make sure this function is always called from the ara top level directory
44
- navigator = DirectoryNavigator()
45
- if navigate_to_target:
46
- navigator.navigate_to_target()
52
+ artefact_list = ArtefactReader.read_artefacts(tags=tags)
53
+ artefact_list = self.filter_artefacts(artefact_list, list_filter)
47
54
 
55
+ filtered_artefact_list = {
56
+ key: [artefact for artefact in value if artefact is not None]
57
+ for key, value in artefact_list.items()
58
+ }
48
59
  file_classifier = FileClassifier(self.file_system)
49
- classified_files = file_classifier.classify_files(tags=tags)
50
-
51
- classified_files = self.filter_artefacts(classified_files, list_filter)
52
-
53
- file_classifier.print_classified_files(classified_files)
60
+ file_classifier.print_classified_files(filtered_artefact_list)
54
61
 
55
62
  def list_branch(
56
63
  self,
@@ -59,21 +66,23 @@ class ArtefactLister:
59
66
  list_filter: ListFilter | None = None
60
67
  ):
61
68
  file_classifier = FileClassifier(os)
62
-
63
69
  classified_artefacts = file_classifier.classify_files()
64
- all_artefact_names = [artefact.file_name for artefact in classified_artefacts.get(classifier, [])]
65
- if artefact_name not in all_artefact_names:
66
- suggest_close_name_matches(artefact_name, all_artefact_names)
67
- return
70
+ artefact_info = classified_artefacts.get(classifier, [])
71
+ matching_artefact_info = [p for p in artefact_info if p["title"] == artefact_name]
72
+
73
+ if not matching_artefact_info:
74
+ suggest_close_name_matches(
75
+ artefact_name,
76
+ [info["title"] for info in artefact_info]
77
+ )
68
78
 
69
79
  artefacts_by_classifier = {classifier: []}
70
80
  ArtefactReader.step_through_value_chain(
71
81
  artefact_name=artefact_name,
72
82
  classifier=classifier,
73
- artefacts_by_classifier=artefacts_by_classifier
83
+ artefacts_by_classifier=artefacts_by_classifier,
74
84
  )
75
85
  artefacts_by_classifier = self.filter_artefacts(artefacts_by_classifier, list_filter)
76
-
77
86
  file_classifier.print_classified_files(artefacts_by_classifier)
78
87
 
79
88
  def list_children(
@@ -83,22 +92,24 @@ class ArtefactLister:
83
92
  list_filter: ListFilter | None = None
84
93
  ):
85
94
  file_classifier = FileClassifier(os)
86
-
87
95
  classified_artefacts = file_classifier.classify_files()
88
- all_artefact_names = [artefact.file_name for artefact in classified_artefacts.get(classifier, [])]
89
- if artefact_name not in all_artefact_names:
90
- suggest_close_name_matches(artefact_name, all_artefact_names)
91
- return
96
+ artefact_info = classified_artefacts.get(classifier, [])
97
+ matching_artefact_info = [p for p in artefact_info if p["title"] == artefact_name]
98
+
99
+ if not matching_artefact_info:
100
+ suggest_close_name_matches(
101
+ artefact_name,
102
+ [info["title"] for info in artefact_info]
103
+ )
92
104
 
93
105
  child_artefacts = ArtefactReader.find_children(
94
- artefact_name=artefact_name,
95
- classifier=classifier
106
+ artefact_name=artefact_name,
107
+ classifier=classifier
96
108
  )
109
+
97
110
  child_artefacts = self.filter_artefacts(child_artefacts, list_filter)
98
111
 
99
- file_classifier.print_classified_files(
100
- files_by_classifier=child_artefacts
101
- )
112
+ file_classifier.print_classified_files(child_artefacts)
102
113
 
103
114
  def list_data(
104
115
  self,
@@ -107,21 +118,19 @@ class ArtefactLister:
107
118
  list_filter: ListFilter | None = None
108
119
  ):
109
120
  file_classifier = FileClassifier(os)
121
+ classified_artefact_info = file_classifier.classify_files()
122
+ artefact_info_dict = classified_artefact_info.get(classifier, [])
110
123
 
111
- classified_artefacts = file_classifier.classify_files()
112
- all_artefact_names = [artefact.file_name for artefact in classified_artefacts.get(classifier, [])]
113
- if artefact_name not in all_artefact_names:
114
- suggest_close_name_matches(artefact_name, all_artefact_names)
115
- return
116
-
117
- content, file_path = ArtefactReader.read_artefact(
118
- classifier=classifier,
119
- artefact_name=artefact_name
120
- )
124
+ matching_info = [info for info in artefact_info_dict if info["title"] == artefact_name]
121
125
 
122
- artefact = Artefact.from_content(content)
123
- file_path = next((classified_artefact.file_path for classified_artefact in classified_artefacts.get(classifier, []) if classified_artefact.name == artefact.name), artefact)
126
+ if not matching_info:
127
+ suggest_close_name_matches(
128
+ artefact_name,
129
+ [info["title"] for info in artefact_info_dict]
130
+ )
131
+ return
124
132
 
125
- file_path = os.path.splitext(file_path)[0] + '.data'
126
- if os.path.exists(file_path):
127
- list_files_in_directory(file_path, list_filter)
133
+ artefact_info = matching_info[0]
134
+ data_dir = os.path.splitext(artefact_info["file_path"])[0] + '.data'
135
+ if os.path.exists(data_dir):
136
+ list_files_in_directory(data_dir, list_filter)
@@ -11,6 +11,14 @@ import string
11
11
  ALLOWED_STATUS_VALUES = ("to-do", "in-progress", "review", "done", "closed")
12
12
 
13
13
 
14
+ def replace_space_with_underscore(input: string):
15
+ return input.replace(' ', '_')
16
+
17
+
18
+ def replace_underscore_with_space(input: string):
19
+ return input.replace('_', ' ')
20
+
21
+
14
22
  class ArtefactType(str, Enum):
15
23
  vision = "vision"
16
24
  businessgoal = "businessgoal"
@@ -44,6 +52,12 @@ class Contribution(BaseModel):
44
52
  classifier = self.classifier
45
53
  rule = self.rule
46
54
 
55
+ if artefact_name:
56
+ artefact_name = replace_space_with_underscore(artefact_name)
57
+ if artefact_name and classifier:
58
+ artefact_name = artefact_name.removesuffix(f"_{classifier}")
59
+ artefact_name = artefact_name.removesuffix(f"_{classifier.capitalize()}")
60
+ self.artefact_name = artefact_name
47
61
  if not artefact_name or not classifier:
48
62
  self.artefact_name = None
49
63
  self.classifier = None
@@ -60,7 +74,7 @@ class Contribution(BaseModel):
60
74
  return value
61
75
  if ' ' in value:
62
76
  warnings.warn(message="artefact_name can not contain spaces. Replacing spaces with '_'")
63
- value = value.replace(' ', '_')
77
+ value = replace_space_with_underscore(value)
64
78
  return value
65
79
 
66
80
  @field_validator('classifier', mode='after')
@@ -90,7 +104,7 @@ class Contribution(BaseModel):
90
104
  rule = rule_text
91
105
  parent_text_list = parent_text.split(' ')
92
106
  classifier = parent_text_list[-1].lower()
93
- artefact_name = '_'.join(parent_text_list[:-1])
107
+ artefact_name = '_'.join([s for s in parent_text_list if s][:-1])
94
108
 
95
109
  return cls(
96
110
  artefact_name=artefact_name,
@@ -102,7 +116,7 @@ class Contribution(BaseModel):
102
116
  if not self.classifier or not self.artefact_name:
103
117
  return ""
104
118
  artefact_type = Classifier.get_artefact_title(self.classifier)
105
- artefact_name = self.artefact_name.replace("_", " ")
119
+ artefact_name = replace_underscore_with_space(self.artefact_name)
106
120
  contribution = f"{artefact_name} {artefact_type}"
107
121
  if self.rule:
108
122
  contribution = f"{contribution} using rule {self.rule}"
@@ -136,6 +150,7 @@ class Artefact(BaseModel, ABC):
136
150
  "validate_assignment": True
137
151
  }
138
152
 
153
+ _file_path: Optional[str] = None
139
154
  artefact_type: ArtefactType = Field(
140
155
  ...,
141
156
  description=f"Artefact classifier (mandatory). Allowed classifiers are {', '.join(ArtefactType)}"
@@ -166,6 +181,13 @@ class Artefact(BaseModel, ABC):
166
181
  description="Optional further description to understand the artefact. It is strongly recommended to add a description to every artefact."
167
182
  )
168
183
 
184
+ @property
185
+ def file_path(self) -> str:
186
+ if self._file_path is not None:
187
+ return self._file_path
188
+ sub_dir = Classifier.get_sub_directory(self.artefact_type)
189
+ return f"{sub_dir}/{self.title}.{self.artefact_type}"
190
+
169
191
  @field_validator('artefact_type')
170
192
  def validate_artefact_type(cls, v):
171
193
  if not isinstance(v, ArtefactType):
@@ -199,9 +221,7 @@ class Artefact(BaseModel, ABC):
199
221
  def validate_title(cls, v):
200
222
  if not v.strip():
201
223
  raise ValueError("artefact_title must not be empty")
202
- if ' ' in v:
203
- warnings.warn(message="artefact_name can not contain spaces. Replacing spaces with '_'")
204
- v = v.replace(' ', '_')
224
+ v = replace_space_with_underscore(v)
205
225
 
206
226
  letters = list(string.ascii_letters)
207
227
  digits = list(string.digits)
@@ -230,12 +250,6 @@ class Artefact(BaseModel, ABC):
230
250
  def _artefact_type(cls) -> ArtefactType: # pragma: no cover
231
251
  pass
232
252
 
233
- def file_location(self) -> str:
234
- artefact_type = self.artefact_type
235
- sub_directory = Classifier.get_sub_directory(artefact_type)
236
- file_path = f"ara/{sub_directory}/{self.title}.{artefact_type}"
237
- return file_path
238
-
239
253
  @classmethod
240
254
  def _deserialize_tags(cls, lines) -> (Dict[str, str], List[str]):
241
255
  assert len(lines) > 0, "Empty lines given, can't extract tags"
@@ -279,7 +293,7 @@ class Artefact(BaseModel, ABC):
279
293
  raise ValueError(
280
294
  f"No title found in {cls._artefact_type()}. Expected '{title_prefix}' as start of the title in line '{title_line}'")
281
295
  title = title_line[len(title_prefix):].strip()
282
- title = title.replace(' ', '_')
296
+ title = replace_space_with_underscore(title)
283
297
  return title, lines
284
298
 
285
299
  @classmethod
@@ -349,7 +363,7 @@ class Artefact(BaseModel, ABC):
349
363
  pass
350
364
 
351
365
  def _serialize_title(self) -> str:
352
- title = self.title.replace('_', ' ')
366
+ title = replace_underscore_with_space(self.title)
353
367
  return f"{self._title_prefix()} {title}"
354
368
 
355
369
  def _serialize_tags(self) -> (Optional[str]):
@@ -85,7 +85,7 @@ class Example(BaseModel):
85
85
  def from_row(cls, headers: List[str], row: List[str]) -> 'Example':
86
86
  if len(row) != len(headers):
87
87
  raise ValueError(
88
- f"Row has {len(row)} cells, but expected {len(headers)}")
88
+ f"Row has {len(row)} cells, but expected {len(headers)}.\nFound row: {row}")
89
89
  values = {header: value.strip() for header, value in zip(headers, row)}
90
90
  return cls(values=values)
91
91
 
@@ -175,6 +175,7 @@ class ScenarioOutline(BaseModel):
175
175
  @classmethod
176
176
  def from_lines(cls, lines: List[str], start_idx: int) -> Tuple['ScenarioOutline', int]:
177
177
  """Parse a ScenarioOutline from a list of lines starting at start_idx."""
178
+
178
179
  if not lines[start_idx].startswith('Scenario Outline:'):
179
180
  raise ValueError("Expected 'Scenario Outline:' at start index")
180
181
  title = lines[start_idx][len('Scenario Outline:'):].strip()
@@ -190,6 +191,8 @@ class ScenarioOutline(BaseModel):
190
191
  headers = [h.strip() for h in lines[idx].split('|') if h.strip()]
191
192
  idx += 1
192
193
  while idx < len(lines) and lines[idx].strip():
194
+ if lines[idx].strip().startswith("Scenario:") or lines[idx].strip().startswith("Scenario Outline:"):
195
+ break
193
196
  row = [cell.strip()
194
197
  for cell in lines[idx].split('|') if cell.strip()]
195
198
  example = Example.from_row(headers, row)
@@ -1,8 +1,8 @@
1
- from ara_cli.directory_navigator import DirectoryNavigator
2
1
  from ara_cli.classifier import Classifier
3
2
  from ara_cli.file_classifier import FileClassifier
4
- from ara_cli.artefact import Artefact
5
- from ara_cli.artefact_fuzzy_search import suggest_close_name_matches, suggest_close_name_matches_for_parent
3
+ from ara_cli.artefact_models.artefact_model import Artefact
4
+ from ara_cli.artefact_fuzzy_search import suggest_close_name_matches_for_parent, suggest_close_name_matches
5
+ from typing import Dict, List
6
6
  import os
7
7
  import re
8
8
 
@@ -10,31 +10,29 @@ import re
10
10
  class ArtefactReader:
11
11
  @staticmethod
12
12
  def read_artefact(artefact_name, classifier):
13
- original_directory = os.getcwd()
14
- navigator = DirectoryNavigator()
15
- navigator.navigate_to_target()
16
-
17
13
  if not Classifier.is_valid_classifier(classifier):
18
14
  print("Invalid classifier provided. Please provide a valid classifier.")
19
- os.chdir(original_directory)
20
15
  return None, None
21
16
 
22
- sub_directory = Classifier.get_sub_directory(classifier)
23
- file_path = os.path.join(sub_directory, f"{artefact_name}.{classifier}")
24
-
25
- file_exists = os.path.exists(file_path)
26
-
27
- if not file_exists:
28
- print(f"File \"{file_path}\" not found")
29
- os.chdir(original_directory)
30
- return None, None
17
+ file_classifier = FileClassifier(os)
18
+ classified_file_info = file_classifier.classify_files()
19
+ artefact_info_of_classifier = classified_file_info.get(classifier, [])
31
20
 
32
- with open(file_path, 'r') as file:
33
- content = file.read()
21
+ for artefact_info in artefact_info_of_classifier:
22
+ file_path = artefact_info["file_path"]
23
+ artefact_title = artefact_info["title"]
24
+ if artefact_title == artefact_name:
25
+ with open(file_path, 'r') as file:
26
+ content = file.read()
27
+ return content, artefact_info
34
28
 
35
- os.chdir(original_directory)
29
+ all_artefact_names = [info["title"] for info in artefact_info_of_classifier]
30
+ suggest_close_name_matches(
31
+ artefact_name,
32
+ all_artefact_names
33
+ )
36
34
 
37
- return content, file_path
35
+ return None, None
38
36
 
39
37
  @staticmethod
40
38
  def extract_parent_tree(artefact_content):
@@ -53,41 +51,77 @@ class ArtefactReader:
53
51
  return parent_name, parent_type
54
52
 
55
53
  @staticmethod
56
- def find_children(artefact_name, classifier, artefacts_by_classifier={}, classified_artefacts=None):
54
+ def merge_dicts(dict1, dict2):
55
+ from collections import defaultdict
57
56
 
58
- def merge_dicts(dict1, dict2):
59
- from collections import defaultdict
57
+ merged = defaultdict(list)
58
+ for d in [dict1, dict2]:
59
+ for key, artefacts in d.items():
60
+ merged[key].extend(artefacts)
61
+ return dict(merged)
60
62
 
61
- merged_dict = defaultdict(list)
63
+ @staticmethod
64
+ def read_artefacts(classified_artefacts=None, file_system=os, tags=None) -> Dict[str, List[Artefact]]:
65
+ from ara_cli.artefact_models.artefact_load import artefact_from_content
62
66
 
63
- # Add items from the first dictionary
64
- for key, artefact_list in dict1.items():
65
- merged_dict[key].extend(artefact_list)
67
+ if classified_artefacts is None:
68
+ file_classifier = FileClassifier(file_system)
69
+ classified_artefacts = file_classifier.classify_files()
66
70
 
67
- # Add items from the second dictionary
68
- for key, artefact_list in dict2.items():
69
- merged_dict[key].extend(artefact_list)
71
+ artefacts = {artefact_type: []
72
+ for artefact_type in classified_artefacts.keys()}
73
+ for artefact_type, artefact_info_dicts in classified_artefacts.items():
74
+ for artefact_info in artefact_info_dicts:
75
+ try:
76
+ with open(artefact_info["file_path"], 'r') as file:
77
+ content = file.read()
78
+ artefact = artefact_from_content(content)
79
+ if not artefact:
80
+ continue
81
+ # Store the full file path in the artefact
82
+ artefact._file_path = artefact_info["file_path"]
83
+ artefacts[artefact_type].append(artefact)
84
+ # else:
85
+ # Include file path if deserialization fails
86
+ # FIXME: LOOK INTO IT
87
+ # artefacts[artefact_type].append(file_path)
88
+ except Exception:
89
+ # TODO: catch only specific exceptions
90
+ # TODO: implament error message for deserialization or "ara scan" or "ara autofix"
91
+ # print(f"Warning: Could not deserialize artefact at {artefact_info}: {e}")
92
+ # artefacts[artefact_type].append(file_path)
93
+ continue
94
+ return artefacts
70
95
 
71
- return dict(merged_dict)
96
+ @staticmethod
97
+ def find_children(artefact_name, classifier, artefacts_by_classifier={}, classified_artefacts=None):
98
+ artefacts_by_classifier = artefacts_by_classifier or {}
99
+ filtered_artefacts = {k: [] for k in artefacts_by_classifier.keys()}
72
100
 
73
101
  if classified_artefacts is None:
74
- file_classifier = FileClassifier(os)
75
- classified_artefacts = file_classifier.classify_files()
102
+ classified_artefacts = ArtefactReader.read_artefacts()
76
103
 
77
- filtered_artefacts = {}
78
- for key, artefact_list in classified_artefacts.items():
79
- filtered_list = [
80
- artefact for artefact in artefact_list
81
- if artefact.parent and
82
- artefact.parent.name == artefact_name and
83
- artefact.parent.classifier == classifier
84
- ]
85
- if filtered_list:
86
- filtered_artefacts[key] = filtered_list
104
+ for artefact_classifier, artefacts in classified_artefacts.items():
105
+ for artefact in artefacts:
106
+ if not isinstance(artefact, Artefact):
107
+ continue
87
108
 
88
- merged_dict = merge_dicts(artefacts_by_classifier, filtered_artefacts)
109
+ try:
110
+ contribution = artefact.contribution
111
+ if (contribution and
112
+ contribution.artefact_name == artefact_name and
113
+ contribution.classifier == classifier):
89
114
 
90
- return merged_dict
115
+ file_classifier = artefact._file_path.split('.')[-1]
116
+
117
+ if file_classifier not in filtered_artefacts:
118
+ filtered_artefacts[file_classifier] = []
119
+ filtered_artefacts[file_classifier].append(artefact)
120
+
121
+ except AttributeError as e:
122
+ continue
123
+
124
+ return ArtefactReader.merge_dicts(artefacts_by_classifier, filtered_artefacts)
91
125
 
92
126
  @staticmethod
93
127
  def step_through_value_chain(
@@ -95,34 +129,41 @@ class ArtefactReader:
95
129
  classifier,
96
130
  artefacts_by_classifier={},
97
131
  classified_artefacts: dict[str, list[Artefact]] | None = None
98
- ):
99
- if classified_artefacts is None:
100
- file_classifier = FileClassifier(os)
101
- classified_artefacts = file_classifier.classify_files()
102
-
103
- content, file_path = ArtefactReader.read_artefact(artefact_name, classifier)
104
-
105
- artefact = Artefact.from_content(content)
106
- artefact_path = next((classified_artefact.file_path for classified_artefact in classified_artefacts.get(classifier, []) if classified_artefact.name == artefact.name), artefact.file_path)
107
- artefact._file_path = artefact_path
132
+ ):
133
+ from ara_cli.artefact_models.artefact_load import artefact_from_content
108
134
 
135
+ if classified_artefacts is None:
136
+ classified_artefacts = ArtefactReader.read_artefacts()
109
137
 
110
138
  if classifier not in artefacts_by_classifier:
111
139
  artefacts_by_classifier[classifier] = []
112
140
 
113
- matching_artefacts = list(filter(lambda x: x.name == artefact.name, artefacts_by_classifier[classifier]))
114
- if len(matching_artefacts) != 0:
141
+ artefact = next(filter(
142
+ lambda x: x.title == artefact_name, classified_artefacts[classifier]
143
+ ))
144
+
145
+ if not artefact:
146
+ return
147
+ if artefact in artefacts_by_classifier[classifier]:
115
148
  return
116
149
 
117
150
  artefacts_by_classifier[classifier].append(artefact)
118
- parent = artefact.parent
119
- if parent:
120
- parent_name = parent.name
151
+
152
+ parent = artefact.contribution
153
+ if parent and parent.artefact_name and parent.classifier:
154
+ parent_name = parent.artefact_name
121
155
  parent_classifier = parent.classifier
122
156
 
123
- all_artefact_names = [artefact.file_name for artefact in classified_artefacts.get(parent_classifier, [])]
157
+ parent_classifier_artefacts = classified_artefacts[parent_classifier]
158
+ all_artefact_names = [x.title for x in parent_classifier_artefacts]
159
+
124
160
  if parent_name not in all_artefact_names:
125
- suggest_close_name_matches_for_parent(artefact_name, all_artefact_names, parent_name)
161
+ if parent_name is not None:
162
+ suggest_close_name_matches_for_parent(
163
+ artefact_name,
164
+ all_artefact_names,
165
+ parent_name
166
+ )
126
167
  print()
127
168
  return
128
169
 
@@ -12,16 +12,17 @@ class ArtefactRenamer:
12
12
  self.link_updater = ArtefactLinkUpdater()
13
13
 
14
14
  @lru_cache(maxsize=None)
15
- def navigate_to_target(self):
15
+ def navigate_to_target(self) -> str:
16
16
  navigator = DirectoryNavigator()
17
- navigator.navigate_to_target()
17
+ original_directory = navigator.navigate_to_target()
18
+ return original_directory
18
19
 
19
20
  @lru_cache(maxsize=None)
20
21
  def compile_pattern(self, pattern):
21
22
  return re.compile(pattern)
22
23
 
23
24
  def rename(self, old_name, new_name, classifier):
24
- self.navigate_to_target()
25
+ original_directory = self.navigate_to_target()
25
26
 
26
27
  if not new_name:
27
28
  raise ValueError("New name must be provided for renaming.")
@@ -50,13 +51,10 @@ class ArtefactRenamer:
50
51
 
51
52
  # Perform the renaming of the file and directory
52
53
  self.file_system.rename(old_file_path, new_file_path)
54
+ print(f"Renamed file: {old_file_path} to {new_file_path}")
53
55
  if old_dir_exists:
54
56
  self.file_system.rename(old_dir_path, new_dir_path)
55
- # TODO: we should be able to remove this next line once ara delete ignores non-existent data folders
56
- os.makedirs(new_dir_path, exist_ok=True)
57
-
58
- print(f"Renamed file: {old_file_path} to {new_file_path}")
59
- print(f"Renamed directory: {old_dir_path} to {new_dir_path}")
57
+ print(f"Renamed directory: {old_dir_path} to {new_dir_path}")
60
58
 
61
59
  # Update the title within the artefact file
62
60
  self._update_title_in_artefact(new_file_path, new_name, classifier)
@@ -64,6 +62,8 @@ class ArtefactRenamer:
64
62
  # Update links in related artefact files
65
63
  self.link_updater.update_links_in_related_artefacts(old_name, new_name)
66
64
 
65
+ os.chdir(original_directory)
66
+
67
67
  def _update_title_in_artefact(self, artefact_path, new_title, classifier):
68
68
  # Format the new title: replace underscores with spaces
69
69
  formatted_new_title = new_title.replace('_', ' ')
@@ -0,0 +1,46 @@
1
+ def check_file(file_path, artefact_class):
2
+ from pydantic import ValidationError
3
+ try:
4
+ with open(file_path, "r", encoding="utf-8") as f:
5
+ content = f.read()
6
+ except OSError as e:
7
+ return False, f"File error: {e}"
8
+ try:
9
+ artefact_class.deserialize(content)
10
+ return True, None
11
+ except (ValidationError, ValueError, AssertionError) as e:
12
+ return False, str(e)
13
+ except Exception as e:
14
+ return False, f"Unexpected error: {e!r}"
15
+
16
+
17
+ def find_invalid_files(classified_artefact_info, classifier):
18
+ from ara_cli.artefact_models.artefact_mapping import artefact_type_mapping
19
+
20
+ artefact_class = artefact_type_mapping[classifier]
21
+ invalid_files = []
22
+ for artefact_info in classified_artefact_info[classifier]:
23
+ if "templates/" in artefact_info["file_path"]:
24
+ continue
25
+ is_valid, reason = check_file(artefact_info["file_path"], artefact_class)
26
+ if not is_valid:
27
+ invalid_files.append((artefact_info["file_path"], reason))
28
+ return invalid_files
29
+
30
+
31
+ def show_results(invalid_artefacts):
32
+ has_issues = False
33
+ with open("incompatible_artefacts_report.md", "w") as report:
34
+ report.write("# Artefact Check Report\n\n")
35
+ for classifier, files in invalid_artefacts.items():
36
+ if files:
37
+ has_issues = True
38
+ print(f"\nIncompatible {classifier} Files:")
39
+ report.write(f"## {classifier}\n")
40
+ for file, reason in files:
41
+ print(f"\t- {file}")
42
+ report.write(f"- `{file}`: {reason}\n")
43
+ report.write("\n")
44
+ if not has_issues:
45
+ print("All files are good!")
46
+ report.write("No problems found.\n")