Skip to content

Commit c69ef48

Browse files
committed
Refactor method attachment.py#get_unique_filename
1 parent 82ac006 commit c69ef48

2 files changed

Lines changed: 43 additions & 31 deletions

File tree

launchable/commands/record/attachment.py

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def attachment(
6767
continue
6868

6969
file_name = normalize_filename(zip_info.filename)
70-
file_name = get_unique_filename(file_name)
70+
file_name = get_unique_filename(file_name, used_filenames)
7171
status = post_attachment(
7272
client, session, file_content, file_name)
7373
summary_rows.append([file_name, status])
@@ -94,7 +94,7 @@ def attachment(
9494
continue
9595

9696
file_name = normalize_filename(tar_info.name)
97-
file_name = get_unique_filename(file_name)
97+
file_name = get_unique_filename(file_name, used_filenames)
9898
status = post_attachment(
9999
client, session, file_content, file_name)
100100
summary_rows.append([file_name, status])
@@ -109,7 +109,7 @@ def attachment(
109109
continue
110110

111111
file_name = normalize_filename(a)
112-
file_name = get_unique_filename(file_name)
112+
file_name = get_unique_filename(file_name, used_filenames)
113113
status = post_attachment(client, session, file_content, file_name)
114114
summary_rows.append([file_name, status])
115115

@@ -121,25 +121,37 @@ def attachment(
121121

122122
def get_unique_filename(filepath: str, used_filenames: Set[str]) -> str:
123123
"""
124-
Get a unique filename by extracting the basename and appending .1, .2, etc. if needed.
125-
Format: file.log, file.1.log, file.2.log
126-
Adds the final name to used_filenames set.
124+
Get a unique filename by extracting the basename and prepending parent folder if needed.
125+
Strategy:
126+
1. First occurrence: use basename (e.g., app.log)
127+
2. Duplicate: prepend parent folder (e.g., nested-app.log)
128+
3. Still duplicate: append .1, .2, etc. (e.g., nested-app.1.log)
127129
"""
128-
basename = os.path.basename(filepath)
130+
filename = os.path.basename(filepath)
129131

130132
# If basename is not used, return it
131-
if basename not in used_filenames:
132-
used_filenames.add(basename)
133-
return basename
134-
135-
# Otherwise find the next available numbered version
136-
name, ext = os.path.splitext(basename)
133+
if filename not in used_filenames:
134+
used_filenames.add(filename)
135+
return filename
136+
137+
# Try prepending the parent directory name
138+
parent_dir = os.path.basename(os.path.dirname(filepath))
139+
if parent_dir: # Has a parent directory
140+
name, ext = os.path.splitext(filename)
141+
filename = f"{parent_dir}-{name}{ext}"
142+
143+
if filename not in used_filenames:
144+
used_filenames.add(filename)
145+
return filename
146+
147+
# If still duplicate, append numbers
148+
name, ext = os.path.splitext(filename)
137149
counter = 1
138150
while True:
139-
new_name = f"{name}.{counter}{ext}"
140-
if new_name not in used_filenames:
141-
used_filenames.add(new_name)
142-
return new_name
151+
filename = f"{name}.{counter}{ext}"
152+
if filename not in used_filenames:
153+
used_filenames.add(filename)
154+
return filename
143155
counter += 1
144156

145157

tests/commands/record/test_attachment.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,15 @@ def test_attachment_zip_file(self):
9393
responses.POST,
9494
"{}/intake/organizations/{}/workspaces/{}/builds/{}/test_sessions/{}/attachment".format(
9595
get_base_url(), self.organization, self.workspace, self.build_name, self.session_id),
96-
match=[responses.matchers.header_matcher({"Content-Disposition": 'attachment;filename="nested/debug.log"'})],
96+
match=[responses.matchers.header_matcher({"Content-Disposition": 'attachment;filename="debug.log"'})],
9797
status=200)
9898

9999
expect = """
100-
| File | Status |
101-
|------------------|----------------------------------|
102-
| app.log | ⚠ Failed to record |
103-
| nested/debug.log | ✓ Recorded successfully |
104-
| binary.dat | ⚠ Skipped: not a valid text file |
100+
| File | Status |
101+
|------------|----------------------------------|
102+
| app.log | ⚠ Failed to record |
103+
| debug.log | ✓ Recorded successfully |
104+
| binary.dat | ⚠ Skipped: not a valid text file |
105105
"""
106106

107107
result = self.cli("record", "attachment", "--session", self.session, zip_path)
@@ -150,15 +150,15 @@ def test_attachment_with_include_filter(self):
150150
responses.POST,
151151
"{}/intake/organizations/{}/workspaces/{}/builds/{}/test_sessions/{}/attachment".format(
152152
get_base_url(), self.organization, self.workspace, self.build_name, self.session_id),
153-
match=[responses.matchers.header_matcher({"Content-Disposition": 'attachment;filename="nested/debug.log"'})],
153+
match=[responses.matchers.header_matcher({"Content-Disposition": 'attachment;filename="debug.log"'})],
154154
status=200)
155155

156156
result = self.cli("record", "attachment", "--session", self.session, "--include", "*.log", zip_path)
157157

158-
expect = """| File | Status |
159-
|------------------|-------------------------|
160-
| app.log | ✓ Recorded successfully |
161-
| nested/debug.log | ✓ Recorded successfully |
158+
expect = """| File | Status |
159+
|-----------|-------------------------|
160+
| app.log | ✓ Recorded successfully |
161+
| debug.log | ✓ Recorded successfully |
162162
"""
163163
self.assertEqual(expect, result.output)
164164

@@ -196,15 +196,15 @@ def test_attachment_with_identical_file_names(self):
196196
responses.POST,
197197
"{}/intake/organizations/{}/workspaces/{}/builds/{}/test_sessions/{}/attachment".format(
198198
get_base_url(), self.organization, self.workspace, self.build_name, self.session_id),
199-
match=[responses.matchers.header_matcher({"Content-Disposition": 'attachment;filename="app.1.log"'})],
199+
match=[responses.matchers.header_matcher({"Content-Disposition": 'attachment;filename="nested-app.log"'})],
200200
status=200)
201201

202202
result = self.cli("record", "attachment", "--session", self.session, zip_path)
203203

204204
expect = """| File | Status |
205205
|----------------|-------------------------|
206206
| app.log | ✓ Recorded successfully |
207-
| nested/app.log | ✓ Recorded successfully |
207+
| nested-app.log | ✓ Recorded successfully |
208208
"""
209209
self.assertEqual(expect, result.output)
210210

@@ -228,7 +228,7 @@ def test_attachment_with_whitespace_in_filename(self):
228228
"{}/intake/organizations/{}/workspaces/{}/builds/{}/test_sessions/{}/attachment".format(
229229
get_base_url(), self.organization, self.workspace, self.build_name, self.session_id),
230230
match=[responses.matchers.header_matcher(
231-
{"Content-Disposition": 'attachment;filename="{}"'.format(file_path.replace(' ', '-'))}
231+
{"Content-Disposition": 'attachment;filename="{}"'.format("app-log-file.txt")}
232232
)],
233233
status=200)
234234

0 commit comments

Comments
 (0)