git-p4son 0.2.5__tar.gz → 0.2.7__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.
- {git_p4son-0.2.5 → git_p4son-0.2.7}/PKG-INFO +6 -6
- {git_p4son-0.2.5 → git_p4son-0.2.7}/README.md +5 -5
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/__init__.py +1 -1
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/alias.py +39 -45
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/cli.py +8 -8
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/complete.py +1 -1
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/perforce.py +29 -9
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son.egg-info/PKG-INFO +6 -6
- {git_p4son-0.2.5 → git_p4son-0.2.7}/pyproject.toml +1 -1
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_complete.py +11 -11
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_lib_edit.py +88 -13
- {git_p4son-0.2.5 → git_p4son-0.2.7}/LICENSE +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/__main__.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/changelist_store.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/common.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/completions/_git-p4son +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/completions/git-p4son.bash +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/completions/git-p4son.ps1 +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/config.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/git.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/init.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/lib.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/list_changes.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/log.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/new.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/review.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/sync.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son/update.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son.egg-info/SOURCES.txt +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son.egg-info/dependency_links.txt +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son.egg-info/entry_points.txt +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/git_p4son.egg-info/top_level.txt +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/setup.cfg +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_cli.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_common.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_config.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_init.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_lib_changelist.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_lib_review.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_list_changes.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_log.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_perforce.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_review.py +0 -0
- {git_p4son-0.2.5 → git_p4son-0.2.7}/tests/test_sync.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-p4son
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Utility for keeping a Perforce workspace and local git repo in sync
|
|
5
5
|
Author-email: Andreas Andersson <andreas@neoboid.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -418,12 +418,12 @@ git p4son alias list
|
|
|
418
418
|
git p4son alias list
|
|
419
419
|
```
|
|
420
420
|
|
|
421
|
-
#### alias
|
|
421
|
+
#### alias new
|
|
422
422
|
|
|
423
423
|
Save a changelist number under a named alias:
|
|
424
424
|
|
|
425
425
|
```sh
|
|
426
|
-
git p4son alias
|
|
426
|
+
git p4son alias new <changelist> [alias] [--force]
|
|
427
427
|
```
|
|
428
428
|
|
|
429
429
|
**Arguments:**
|
|
@@ -435,9 +435,9 @@ git p4son alias set <changelist> [alias] [--force]
|
|
|
435
435
|
|
|
436
436
|
**Examples:**
|
|
437
437
|
```sh
|
|
438
|
-
git p4son alias
|
|
439
|
-
git p4son alias
|
|
440
|
-
git p4son alias
|
|
438
|
+
git p4son alias new 12345 # alias defaults to branch name
|
|
439
|
+
git p4son alias new 12345 myfeature
|
|
440
|
+
git p4son alias new 67890 myfeature -f
|
|
441
441
|
```
|
|
442
442
|
|
|
443
443
|
#### alias delete
|
|
@@ -395,12 +395,12 @@ git p4son alias list
|
|
|
395
395
|
git p4son alias list
|
|
396
396
|
```
|
|
397
397
|
|
|
398
|
-
#### alias
|
|
398
|
+
#### alias new
|
|
399
399
|
|
|
400
400
|
Save a changelist number under a named alias:
|
|
401
401
|
|
|
402
402
|
```sh
|
|
403
|
-
git p4son alias
|
|
403
|
+
git p4son alias new <changelist> [alias] [--force]
|
|
404
404
|
```
|
|
405
405
|
|
|
406
406
|
**Arguments:**
|
|
@@ -412,9 +412,9 @@ git p4son alias set <changelist> [alias] [--force]
|
|
|
412
412
|
|
|
413
413
|
**Examples:**
|
|
414
414
|
```sh
|
|
415
|
-
git p4son alias
|
|
416
|
-
git p4son alias
|
|
417
|
-
git p4son alias
|
|
415
|
+
git p4son alias new 12345 # alias defaults to branch name
|
|
416
|
+
git p4son alias new 12345 myfeature
|
|
417
|
+
git p4son alias new 67890 myfeature -f
|
|
418
418
|
```
|
|
419
419
|
|
|
420
420
|
#### alias delete
|
|
@@ -19,17 +19,16 @@ def alias_list_command(args: argparse.Namespace) -> int:
|
|
|
19
19
|
if not aliases:
|
|
20
20
|
log.info('No aliases defined')
|
|
21
21
|
return 0
|
|
22
|
+
log.info(f'Found {len(aliases)}')
|
|
22
23
|
|
|
23
24
|
for name, changelist in aliases:
|
|
24
25
|
log.info(f'{name} -> {changelist}')
|
|
25
26
|
|
|
26
|
-
log.success(f'{len(aliases)} listed')
|
|
27
|
-
|
|
28
27
|
return 0
|
|
29
28
|
|
|
30
29
|
|
|
31
|
-
def
|
|
32
|
-
"""Execute the 'alias
|
|
30
|
+
def alias_new_command(args: argparse.Namespace) -> int:
|
|
31
|
+
"""Execute the 'alias new' command."""
|
|
33
32
|
workspace_dir = args.workspace_dir
|
|
34
33
|
|
|
35
34
|
if not args.changelist.isdigit():
|
|
@@ -55,6 +54,27 @@ def alias_delete_command(args: argparse.Namespace) -> int:
|
|
|
55
54
|
return 0
|
|
56
55
|
|
|
57
56
|
|
|
57
|
+
def _prompt_delete(prompt: str) -> str | None:
|
|
58
|
+
"""Prompt until a valid y/n/a/q response is given. Returns None on EOF."""
|
|
59
|
+
while True:
|
|
60
|
+
try:
|
|
61
|
+
response = input(prompt).strip().lower()
|
|
62
|
+
except EOFError:
|
|
63
|
+
print()
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
if response in ('y', 'yes'):
|
|
67
|
+
return 'yes'
|
|
68
|
+
elif response in ('n', 'no'):
|
|
69
|
+
return 'no'
|
|
70
|
+
elif response in ('a', 'all'):
|
|
71
|
+
return 'all'
|
|
72
|
+
elif response in ('q', 'quit'):
|
|
73
|
+
return 'quit'
|
|
74
|
+
else:
|
|
75
|
+
print('Please enter y, n, a, or q')
|
|
76
|
+
|
|
77
|
+
|
|
58
78
|
def alias_clean_command(args: argparse.Namespace) -> int:
|
|
59
79
|
"""Execute the 'alias clean' command with interactive prompts."""
|
|
60
80
|
workspace_dir = args.workspace_dir
|
|
@@ -64,50 +84,24 @@ def alias_clean_command(args: argparse.Namespace) -> int:
|
|
|
64
84
|
log.success('No changelist aliases to clean')
|
|
65
85
|
return 0
|
|
66
86
|
|
|
67
|
-
|
|
68
|
-
deleted_count = 0
|
|
69
|
-
|
|
87
|
+
response = None
|
|
70
88
|
for name, changelist in aliases:
|
|
71
|
-
|
|
72
|
-
print(f'{name} -> {changelist}')
|
|
89
|
+
log.heading(f'{name} -> CL {changelist}')
|
|
73
90
|
|
|
74
|
-
if
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
log.info(' Deleted')
|
|
78
|
-
continue
|
|
91
|
+
if response != 'all':
|
|
92
|
+
response = _prompt_delete(
|
|
93
|
+
'Delete? [y]es / [n]o / [a]ll / [q]uit: ')
|
|
79
94
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
try:
|
|
83
|
-
response = input(
|
|
84
|
-
'Delete? [y]es / [n]o / [a]ll / [q]uit: ').strip().lower()
|
|
85
|
-
except EOFError:
|
|
86
|
-
print()
|
|
87
|
-
return 0
|
|
88
|
-
|
|
89
|
-
if response in ('y', 'yes'):
|
|
90
|
-
delete_changelist_alias(name, workspace_dir)
|
|
91
|
-
deleted_count += 1
|
|
92
|
-
log.info(' Deleted')
|
|
93
|
-
break
|
|
94
|
-
elif response in ('n', 'no'):
|
|
95
|
-
break
|
|
96
|
-
elif response in ('a', 'all'):
|
|
97
|
-
delete_all = True
|
|
98
|
-
delete_changelist_alias(name, workspace_dir)
|
|
99
|
-
deleted_count += 1
|
|
100
|
-
log.info(' Deleted')
|
|
101
|
-
break
|
|
102
|
-
elif response in ('q', 'quit'):
|
|
103
|
-
quit = True
|
|
104
|
-
break
|
|
105
|
-
else:
|
|
106
|
-
print('Please enter y, n, a, or q')
|
|
107
|
-
if quit:
|
|
95
|
+
if response is None or response == 'quit':
|
|
96
|
+
log.info('Aborting')
|
|
108
97
|
break
|
|
98
|
+
elif response == 'no':
|
|
99
|
+
log.info('Skipped')
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
if delete_changelist_alias(name, workspace_dir):
|
|
103
|
+
log.success('Deleted')
|
|
109
104
|
|
|
110
|
-
log.success(f'Deleted {deleted_count} alias(es)')
|
|
111
105
|
return 0
|
|
112
106
|
|
|
113
107
|
|
|
@@ -115,8 +109,8 @@ def alias_command(args: argparse.Namespace) -> int:
|
|
|
115
109
|
"""Dispatch alias subcommands."""
|
|
116
110
|
if args.alias_action == 'list':
|
|
117
111
|
return alias_list_command(args)
|
|
118
|
-
elif args.alias_action == '
|
|
119
|
-
return
|
|
112
|
+
elif args.alias_action == 'new':
|
|
113
|
+
return alias_new_command(args)
|
|
120
114
|
elif args.alias_action == 'delete':
|
|
121
115
|
return alias_delete_command(args)
|
|
122
116
|
elif args.alias_action == 'clean':
|
|
@@ -227,25 +227,25 @@ Examples:
|
|
|
227
227
|
description='List all changelist aliases stored in .git-p4son/changelists/'
|
|
228
228
|
)
|
|
229
229
|
|
|
230
|
-
# alias
|
|
231
|
-
|
|
232
|
-
'
|
|
230
|
+
# alias new
|
|
231
|
+
alias_new_parser = alias_subparsers.add_parser(
|
|
232
|
+
'new',
|
|
233
233
|
help='Save a changelist number under a named alias',
|
|
234
234
|
description='Save a changelist number under a named alias in '
|
|
235
235
|
'.git-p4son/changelists/<alias>'
|
|
236
236
|
)
|
|
237
|
-
|
|
237
|
+
alias_new_parser.add_argument(
|
|
238
238
|
'changelist',
|
|
239
239
|
help='Changelist number to save'
|
|
240
240
|
)
|
|
241
|
-
|
|
241
|
+
alias_new_parser.add_argument(
|
|
242
242
|
'alias',
|
|
243
243
|
nargs='?',
|
|
244
244
|
default='branch',
|
|
245
245
|
help='Alias name to save the changelist number under. '
|
|
246
246
|
'Defaults to the current branch name'
|
|
247
247
|
)
|
|
248
|
-
|
|
248
|
+
alias_new_parser.add_argument(
|
|
249
249
|
'-f', '--force',
|
|
250
250
|
action='store_true',
|
|
251
251
|
help='Overwrite an existing alias file'
|
|
@@ -396,7 +396,7 @@ def run_command(args: argparse.Namespace) -> int:
|
|
|
396
396
|
elif args.command == 'update' and args.changelist == 'branch':
|
|
397
397
|
branch_attr = 'changelist'
|
|
398
398
|
elif (args.command == 'alias'
|
|
399
|
-
and args.alias_action in ('
|
|
399
|
+
and args.alias_action in ('new', 'delete')
|
|
400
400
|
and args.alias == 'branch'):
|
|
401
401
|
branch_attr = 'alias'
|
|
402
402
|
|
|
@@ -468,7 +468,7 @@ def main() -> int:
|
|
|
468
468
|
seconds = int(args.sleep)
|
|
469
469
|
log.heading(f'Sleeping for {seconds} seconds')
|
|
470
470
|
time.sleep(seconds)
|
|
471
|
-
log.
|
|
471
|
+
log.success('awake again')
|
|
472
472
|
|
|
473
473
|
return exit_code
|
|
474
474
|
except KeyboardInterrupt:
|
|
@@ -128,7 +128,7 @@ def _complete_positional(command, subcommand, positional_count,
|
|
|
128
128
|
branch_candidates = _get_branch_candidates(prefix, workspace_dir)
|
|
129
129
|
return branch_candidates + _filter(aliases, prefix)
|
|
130
130
|
|
|
131
|
-
if subcommand == '
|
|
131
|
+
if subcommand == 'new' and positional_count == 1:
|
|
132
132
|
branch_candidates = _get_branch_candidates(prefix, workspace_dir)
|
|
133
133
|
return branch_candidates + _filter(aliases, prefix)
|
|
134
134
|
|
|
@@ -177,26 +177,46 @@ def get_latest_changelist(depot_root: str, workspace_dir: str) -> int:
|
|
|
177
177
|
|
|
178
178
|
# --- file operations ---
|
|
179
179
|
|
|
180
|
-
def get_changelist_for_file(filename: str, workspace_dir: str) -> str | None:
|
|
181
|
-
"""Return
|
|
180
|
+
def get_changelist_for_file(filename: str, workspace_dir: str) -> tuple[str, str] | None:
|
|
181
|
+
"""Return (changelist, action) for an opened file, or None if not opened."""
|
|
182
182
|
res = run(['p4', '-ztag', 'opened', filename], cwd=workspace_dir)
|
|
183
183
|
fields = parse_ztag_output(res.stdout)
|
|
184
|
-
|
|
184
|
+
change = fields.get('change')
|
|
185
|
+
if change is None:
|
|
186
|
+
return None
|
|
187
|
+
return (change, fields.get('action', ''))
|
|
185
188
|
|
|
186
189
|
|
|
187
190
|
def _ensure_in_changelist(filename: str, p4_action: str, changelist: str,
|
|
188
191
|
workspace_dir: str, dry_run: bool) -> None:
|
|
189
|
-
"""Ensure a file is opened in the given changelist.
|
|
192
|
+
"""Ensure a file is opened with the correct action in the given changelist.
|
|
190
193
|
|
|
191
194
|
If the file is not yet opened, run the specified p4 action (add, edit, delete).
|
|
192
|
-
If it's already opened
|
|
193
|
-
If it's already
|
|
195
|
+
If it's already opened with a different action, revert and reopen.
|
|
196
|
+
If it's already opened with the correct action in a different changelist, reopen it.
|
|
197
|
+
If it's already in the correct changelist with the correct action, do nothing.
|
|
194
198
|
"""
|
|
195
|
-
|
|
196
|
-
if
|
|
199
|
+
result = get_changelist_for_file(filename, workspace_dir)
|
|
200
|
+
if result is None:
|
|
201
|
+
run(['p4', p4_action, '-c', changelist, filename],
|
|
202
|
+
cwd=workspace_dir, dry_run=dry_run)
|
|
203
|
+
return
|
|
204
|
+
|
|
205
|
+
current_cl, current_action = result
|
|
206
|
+
if current_action != p4_action:
|
|
207
|
+
# Action mismatch - revert first, then reopen with correct action.
|
|
208
|
+
# p4 revert overwrites the file on disk with the depot version,
|
|
209
|
+
# so we need git restore afterwards to get the git content back.
|
|
210
|
+
run(['p4', 'revert', filename], cwd=workspace_dir, dry_run=dry_run)
|
|
211
|
+
# For add -> delete: the file never existed in the depot, so just revert.
|
|
212
|
+
if current_action == 'add' and p4_action == 'delete':
|
|
213
|
+
return
|
|
197
214
|
run(['p4', p4_action, '-c', changelist, filename],
|
|
198
215
|
cwd=workspace_dir, dry_run=dry_run)
|
|
199
|
-
|
|
216
|
+
if p4_action != 'delete':
|
|
217
|
+
run(['git', 'restore', filename],
|
|
218
|
+
cwd=workspace_dir, dry_run=dry_run)
|
|
219
|
+
elif current_cl != changelist:
|
|
200
220
|
run(['p4', 'reopen', '-c', changelist, filename],
|
|
201
221
|
cwd=workspace_dir, dry_run=dry_run)
|
|
202
222
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-p4son
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Utility for keeping a Perforce workspace and local git repo in sync
|
|
5
5
|
Author-email: Andreas Andersson <andreas@neoboid.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -418,12 +418,12 @@ git p4son alias list
|
|
|
418
418
|
git p4son alias list
|
|
419
419
|
```
|
|
420
420
|
|
|
421
|
-
#### alias
|
|
421
|
+
#### alias new
|
|
422
422
|
|
|
423
423
|
Save a changelist number under a named alias:
|
|
424
424
|
|
|
425
425
|
```sh
|
|
426
|
-
git p4son alias
|
|
426
|
+
git p4son alias new <changelist> [alias] [--force]
|
|
427
427
|
```
|
|
428
428
|
|
|
429
429
|
**Arguments:**
|
|
@@ -435,9 +435,9 @@ git p4son alias set <changelist> [alias] [--force]
|
|
|
435
435
|
|
|
436
436
|
**Examples:**
|
|
437
437
|
```sh
|
|
438
|
-
git p4son alias
|
|
439
|
-
git p4son alias
|
|
440
|
-
git p4son alias
|
|
438
|
+
git p4son alias new 12345 # alias defaults to branch name
|
|
439
|
+
git p4son alias new 12345 myfeature
|
|
440
|
+
git p4son alias new 67890 myfeature -f
|
|
441
441
|
```
|
|
442
442
|
|
|
443
443
|
#### alias delete
|
|
@@ -198,7 +198,7 @@ class TestComplete(unittest.TestCase):
|
|
|
198
198
|
result = _complete(self.parser, ['alias', ''], workspace_dir='/ws')
|
|
199
199
|
names = self._names(result)
|
|
200
200
|
self.assertIn('list', names)
|
|
201
|
-
self.assertIn('
|
|
201
|
+
self.assertIn('new', names)
|
|
202
202
|
self.assertIn('delete', names)
|
|
203
203
|
self.assertIn('clean', names)
|
|
204
204
|
|
|
@@ -208,14 +208,14 @@ class TestComplete(unittest.TestCase):
|
|
|
208
208
|
names = self._names(result)
|
|
209
209
|
self.assertEqual(names, ['myalias'])
|
|
210
210
|
|
|
211
|
-
def
|
|
212
|
-
result = _complete(self.parser, ['alias', '
|
|
211
|
+
def test_alias_new_second_positional(self, _ws, _aliases):
|
|
212
|
+
result = _complete(self.parser, ['alias', 'new', '123', ''],
|
|
213
213
|
workspace_dir='/ws')
|
|
214
214
|
names = self._names(result)
|
|
215
215
|
self.assertEqual(names, ['myalias'])
|
|
216
216
|
|
|
217
|
-
def
|
|
218
|
-
result = _complete(self.parser, ['alias', '
|
|
217
|
+
def test_alias_new_flags(self, _ws, _aliases):
|
|
218
|
+
result = _complete(self.parser, ['alias', 'new', '-'],
|
|
219
219
|
workspace_dir='/ws')
|
|
220
220
|
names = self._names(result)
|
|
221
221
|
self.assertIn('-f', names)
|
|
@@ -283,20 +283,20 @@ class TestCompleteBranchAlias(unittest.TestCase):
|
|
|
283
283
|
self.assertIn('branch', names)
|
|
284
284
|
self.assertIn('myalias', names)
|
|
285
285
|
|
|
286
|
-
def
|
|
287
|
-
result = _complete(self.parser, ['alias', '
|
|
286
|
+
def test_alias_new_branch_keyword(self, _ws, _aliases, _branch):
|
|
287
|
+
result = _complete(self.parser, ['alias', 'new', '123', 'b'],
|
|
288
288
|
workspace_dir='/ws')
|
|
289
289
|
names = self._names(result)
|
|
290
290
|
self.assertIn('branch', names)
|
|
291
291
|
|
|
292
|
-
def
|
|
293
|
-
result = _complete(self.parser, ['alias', '
|
|
292
|
+
def test_alias_new_br_prefix(self, _ws, _aliases, _branch):
|
|
293
|
+
result = _complete(self.parser, ['alias', 'new', '123', 'br'],
|
|
294
294
|
workspace_dir='/ws')
|
|
295
295
|
names = self._names(result)
|
|
296
296
|
self.assertIn('branch', names)
|
|
297
297
|
|
|
298
|
-
def
|
|
299
|
-
result = _complete(self.parser, ['alias', '
|
|
298
|
+
def test_alias_new_branch_expand(self, _ws, _aliases, _branch):
|
|
299
|
+
result = _complete(self.parser, ['alias', 'new', '123', 'branch'],
|
|
300
300
|
workspace_dir='/ws')
|
|
301
301
|
names = self._names(result)
|
|
302
302
|
self.assertIn('feat-cool', names)
|
|
@@ -33,7 +33,7 @@ class TestGetChangelistForFile(unittest.TestCase):
|
|
|
33
33
|
'... type text',
|
|
34
34
|
])
|
|
35
35
|
result = get_changelist_for_file('foo.txt', '/ws')
|
|
36
|
-
self.assertEqual(result, 'default')
|
|
36
|
+
self.assertEqual(result, ('default', 'edit'))
|
|
37
37
|
|
|
38
38
|
@mock.patch('git_p4son.perforce.run')
|
|
39
39
|
def test_file_in_numbered_changelist(self, mock_run):
|
|
@@ -44,7 +44,7 @@ class TestGetChangelistForFile(unittest.TestCase):
|
|
|
44
44
|
'... type text',
|
|
45
45
|
])
|
|
46
46
|
result = get_changelist_for_file('foo.txt', '/ws')
|
|
47
|
-
self.assertEqual(result, '12345')
|
|
47
|
+
self.assertEqual(result, ('12345', 'edit'))
|
|
48
48
|
|
|
49
49
|
@mock.patch('git_p4son.perforce.run')
|
|
50
50
|
def test_file_opened_for_add(self, mock_run):
|
|
@@ -54,7 +54,7 @@ class TestGetChangelistForFile(unittest.TestCase):
|
|
|
54
54
|
'... change 12345',
|
|
55
55
|
])
|
|
56
56
|
result = get_changelist_for_file('foo.txt', '/ws')
|
|
57
|
-
self.assertEqual(result, '12345')
|
|
57
|
+
self.assertEqual(result, ('12345', 'add'))
|
|
58
58
|
|
|
59
59
|
@mock.patch('git_p4son.perforce.run')
|
|
60
60
|
def test_file_opened_for_delete(self, mock_run):
|
|
@@ -64,7 +64,7 @@ class TestGetChangelistForFile(unittest.TestCase):
|
|
|
64
64
|
'... change 12345',
|
|
65
65
|
])
|
|
66
66
|
result = get_changelist_for_file('foo.txt', '/ws')
|
|
67
|
-
self.assertEqual(result, '12345')
|
|
67
|
+
self.assertEqual(result, ('12345', 'delete'))
|
|
68
68
|
|
|
69
69
|
@mock.patch('git_p4son.perforce.run')
|
|
70
70
|
def test_file_opened_for_move_add(self, mock_run):
|
|
@@ -74,7 +74,7 @@ class TestGetChangelistForFile(unittest.TestCase):
|
|
|
74
74
|
'... change 12345',
|
|
75
75
|
])
|
|
76
76
|
result = get_changelist_for_file('foo.txt', '/ws')
|
|
77
|
-
self.assertEqual(result, '12345')
|
|
77
|
+
self.assertEqual(result, ('12345', 'move/add'))
|
|
78
78
|
|
|
79
79
|
@mock.patch('git_p4son.perforce.run')
|
|
80
80
|
def test_add_in_default_changelist(self, mock_run):
|
|
@@ -84,7 +84,7 @@ class TestGetChangelistForFile(unittest.TestCase):
|
|
|
84
84
|
'... change default',
|
|
85
85
|
])
|
|
86
86
|
result = get_changelist_for_file('foo.txt', '/ws')
|
|
87
|
-
self.assertEqual(result, 'default')
|
|
87
|
+
self.assertEqual(result, ('default', 'add'))
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
class TestFindCommonAncestor(unittest.TestCase):
|
|
@@ -157,7 +157,7 @@ class TestIncludeChangesInChangelist(unittest.TestCase):
|
|
|
157
157
|
cwd='/ws', dry_run=False,
|
|
158
158
|
)
|
|
159
159
|
|
|
160
|
-
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value='200')
|
|
160
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value=('200', 'add'))
|
|
161
161
|
@mock.patch('git_p4son.perforce.run')
|
|
162
162
|
def test_reopens_added_file_in_different_changelist(self, mock_run, mock_check):
|
|
163
163
|
mock_run.return_value = make_run_result()
|
|
@@ -169,7 +169,7 @@ class TestIncludeChangesInChangelist(unittest.TestCase):
|
|
|
169
169
|
cwd='/ws', dry_run=False,
|
|
170
170
|
)
|
|
171
171
|
|
|
172
|
-
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value='100')
|
|
172
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value=('100', 'add'))
|
|
173
173
|
@mock.patch('git_p4son.perforce.run')
|
|
174
174
|
def test_skips_added_file_already_in_correct_changelist(self, mock_run, mock_check):
|
|
175
175
|
mock_run.return_value = make_run_result()
|
|
@@ -191,7 +191,7 @@ class TestIncludeChangesInChangelist(unittest.TestCase):
|
|
|
191
191
|
cwd='/ws', dry_run=False,
|
|
192
192
|
)
|
|
193
193
|
|
|
194
|
-
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value='200')
|
|
194
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value=('200', 'edit'))
|
|
195
195
|
@mock.patch('git_p4son.perforce.run')
|
|
196
196
|
def test_reopens_file_in_different_changelist(self, mock_run, mock_check):
|
|
197
197
|
mock_run.return_value = make_run_result()
|
|
@@ -203,7 +203,7 @@ class TestIncludeChangesInChangelist(unittest.TestCase):
|
|
|
203
203
|
cwd='/ws', dry_run=False,
|
|
204
204
|
)
|
|
205
205
|
|
|
206
|
-
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value='100')
|
|
206
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value=('100', 'edit'))
|
|
207
207
|
@mock.patch('git_p4son.perforce.run')
|
|
208
208
|
def test_skips_file_already_in_correct_changelist(self, mock_run, mock_check):
|
|
209
209
|
mock_run.return_value = make_run_result()
|
|
@@ -225,7 +225,7 @@ class TestIncludeChangesInChangelist(unittest.TestCase):
|
|
|
225
225
|
cwd='/ws', dry_run=False,
|
|
226
226
|
)
|
|
227
227
|
|
|
228
|
-
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value='200')
|
|
228
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value=('200', 'delete'))
|
|
229
229
|
@mock.patch('git_p4son.perforce.run')
|
|
230
230
|
def test_reopens_deleted_file_in_different_changelist(self, mock_run, mock_check):
|
|
231
231
|
mock_run.return_value = make_run_result()
|
|
@@ -237,7 +237,7 @@ class TestIncludeChangesInChangelist(unittest.TestCase):
|
|
|
237
237
|
cwd='/ws', dry_run=False,
|
|
238
238
|
)
|
|
239
239
|
|
|
240
|
-
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value='100')
|
|
240
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value=('100', 'delete'))
|
|
241
241
|
@mock.patch('git_p4son.perforce.run')
|
|
242
242
|
def test_skips_deleted_file_already_in_correct_changelist(self, mock_run, mock_check):
|
|
243
243
|
mock_run.return_value = make_run_result()
|
|
@@ -260,7 +260,8 @@ class TestIncludeChangesInChangelist(unittest.TestCase):
|
|
|
260
260
|
'p4', 'delete', '-c', '100', 'old.txt'])
|
|
261
261
|
self.assertEqual(calls[1][0][0], ['p4', 'add', '-c', '100', 'new.txt'])
|
|
262
262
|
|
|
263
|
-
@mock.patch('git_p4son.perforce.get_changelist_for_file',
|
|
263
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file',
|
|
264
|
+
side_effect=[('200', 'delete'), ('200', 'add')])
|
|
264
265
|
@mock.patch('git_p4son.perforce.run')
|
|
265
266
|
def test_reopens_moved_files_in_different_changelist(self, mock_run, mock_check):
|
|
266
267
|
mock_run.return_value = make_run_result()
|
|
@@ -288,6 +289,80 @@ class TestIncludeChangesInChangelist(unittest.TestCase):
|
|
|
288
289
|
)
|
|
289
290
|
|
|
290
291
|
|
|
292
|
+
class TestActionMismatch(unittest.TestCase):
|
|
293
|
+
"""Tests for reopening files when the p4 action doesn't match the desired action."""
|
|
294
|
+
|
|
295
|
+
# --- edit -> delete ---
|
|
296
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value=('100', 'edit'))
|
|
297
|
+
@mock.patch('git_p4son.perforce.run')
|
|
298
|
+
def test_edit_to_delete_same_cl(self, mock_run, mock_check):
|
|
299
|
+
mock_run.return_value = make_run_result()
|
|
300
|
+
changes = LocalChanges()
|
|
301
|
+
changes.dels = ['file.txt']
|
|
302
|
+
include_changes_in_changelist(changes, '100', '/ws')
|
|
303
|
+
calls = mock_run.call_args_list
|
|
304
|
+
self.assertEqual(len(calls), 2)
|
|
305
|
+
self.assertEqual(calls[0][0][0], ['p4', 'revert', 'file.txt'])
|
|
306
|
+
self.assertEqual(calls[1][0][0],
|
|
307
|
+
['p4', 'delete', '-c', '100', 'file.txt'])
|
|
308
|
+
|
|
309
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value=('200', 'edit'))
|
|
310
|
+
@mock.patch('git_p4son.perforce.run')
|
|
311
|
+
def test_edit_to_delete_different_cl(self, mock_run, mock_check):
|
|
312
|
+
mock_run.return_value = make_run_result()
|
|
313
|
+
changes = LocalChanges()
|
|
314
|
+
changes.dels = ['file.txt']
|
|
315
|
+
include_changes_in_changelist(changes, '100', '/ws')
|
|
316
|
+
calls = mock_run.call_args_list
|
|
317
|
+
self.assertEqual(len(calls), 2)
|
|
318
|
+
self.assertEqual(calls[0][0][0], ['p4', 'revert', 'file.txt'])
|
|
319
|
+
self.assertEqual(calls[1][0][0],
|
|
320
|
+
['p4', 'delete', '-c', '100', 'file.txt'])
|
|
321
|
+
|
|
322
|
+
# --- delete -> edit ---
|
|
323
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value=('100', 'delete'))
|
|
324
|
+
@mock.patch('git_p4son.perforce.run')
|
|
325
|
+
def test_delete_to_edit_same_cl(self, mock_run, mock_check):
|
|
326
|
+
mock_run.return_value = make_run_result()
|
|
327
|
+
changes = LocalChanges()
|
|
328
|
+
changes.mods = ['file.txt']
|
|
329
|
+
include_changes_in_changelist(changes, '100', '/ws')
|
|
330
|
+
calls = mock_run.call_args_list
|
|
331
|
+
self.assertEqual(len(calls), 3)
|
|
332
|
+
self.assertEqual(calls[0][0][0], ['p4', 'revert', 'file.txt'])
|
|
333
|
+
self.assertEqual(calls[1][0][0],
|
|
334
|
+
['p4', 'edit', '-c', '100', 'file.txt'])
|
|
335
|
+
self.assertEqual(calls[2][0][0],
|
|
336
|
+
['git', 'restore', 'file.txt'])
|
|
337
|
+
|
|
338
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value=('200', 'delete'))
|
|
339
|
+
@mock.patch('git_p4son.perforce.run')
|
|
340
|
+
def test_delete_to_edit_different_cl(self, mock_run, mock_check):
|
|
341
|
+
mock_run.return_value = make_run_result()
|
|
342
|
+
changes = LocalChanges()
|
|
343
|
+
changes.mods = ['file.txt']
|
|
344
|
+
include_changes_in_changelist(changes, '100', '/ws')
|
|
345
|
+
calls = mock_run.call_args_list
|
|
346
|
+
self.assertEqual(len(calls), 3)
|
|
347
|
+
self.assertEqual(calls[0][0][0], ['p4', 'revert', 'file.txt'])
|
|
348
|
+
self.assertEqual(calls[1][0][0],
|
|
349
|
+
['p4', 'edit', '-c', '100', 'file.txt'])
|
|
350
|
+
self.assertEqual(calls[2][0][0],
|
|
351
|
+
['git', 'restore', 'file.txt'])
|
|
352
|
+
|
|
353
|
+
# --- add -> delete (revert only, no reopen) ---
|
|
354
|
+
@mock.patch('git_p4son.perforce.get_changelist_for_file', return_value=('100', 'add'))
|
|
355
|
+
@mock.patch('git_p4son.perforce.run')
|
|
356
|
+
def test_add_to_delete_reverts_only(self, mock_run, mock_check):
|
|
357
|
+
mock_run.return_value = make_run_result()
|
|
358
|
+
changes = LocalChanges()
|
|
359
|
+
changes.dels = ['file.txt']
|
|
360
|
+
include_changes_in_changelist(changes, '100', '/ws')
|
|
361
|
+
calls = mock_run.call_args_list
|
|
362
|
+
self.assertEqual(len(calls), 1)
|
|
363
|
+
self.assertEqual(calls[0][0][0], ['p4', 'revert', 'file.txt'])
|
|
364
|
+
|
|
365
|
+
|
|
291
366
|
class TestOpenChangesForEdit(unittest.TestCase):
|
|
292
367
|
@mock.patch('git_p4son.lib.include_changes_in_changelist')
|
|
293
368
|
@mock.patch('git_p4son.lib.get_local_changes')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|