git-p4son 0.7.0__tar.gz → 0.8.0__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.
Files changed (88) hide show
  1. {git_p4son-0.7.0 → git_p4son-0.8.0}/PKG-INFO +110 -36
  2. {git_p4son-0.7.0 → git_p4son-0.8.0}/README.md +108 -34
  3. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/__init__.py +1 -1
  4. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/alias.py +65 -49
  5. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/changelist_store.py +41 -11
  6. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/cli.py +26 -9
  7. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/common.py +13 -0
  8. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/complete.py +8 -0
  9. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/hooks.py +3 -54
  10. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/log.py +4 -0
  11. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/new.py +36 -8
  12. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/per_commit.py +1 -3
  13. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/perforce.py +26 -0
  14. git_p4son-0.8.0/git_p4son/review_tools.py +168 -0
  15. git_p4son-0.8.0/git_p4son/scripts.py +64 -0
  16. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/skill/git-p4son.md +11 -9
  17. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/update.py +23 -9
  18. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son.egg-info/PKG-INFO +110 -36
  19. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son.egg-info/SOURCES.txt +4 -0
  20. {git_p4son-0.7.0 → git_p4son-0.8.0}/pyproject.toml +2 -2
  21. git_p4son-0.8.0/tests/test_alias.py +286 -0
  22. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_changelist_store.py +49 -0
  23. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_common.py +22 -0
  24. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_complete.py +15 -1
  25. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_hooks.py +9 -76
  26. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_jj.py +8 -0
  27. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_log.py +16 -0
  28. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_new.py +181 -0
  29. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_perforce.py +29 -0
  30. git_p4son-0.8.0/tests/test_review_tools.py +216 -0
  31. git_p4son-0.8.0/tests/test_scripts.py +89 -0
  32. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_sync.py +1 -1
  33. git_p4son-0.7.0/tests/test_alias.py +0 -237
  34. {git_p4son-0.7.0 → git_p4son-0.8.0}/LICENSE +0 -0
  35. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/__main__.py +0 -0
  36. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/backend.py +0 -0
  37. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/completions/_git-p4son +0 -0
  38. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/completions/git-p4son-jj.bash +0 -0
  39. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/completions/git-p4son-jj.ps1 +0 -0
  40. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/completions/git-p4son-jj.zsh +0 -0
  41. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/completions/git-p4son.bash +0 -0
  42. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/completions/git-p4son.ps1 +0 -0
  43. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/config.py +0 -0
  44. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/depot.py +0 -0
  45. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/description.py +0 -0
  46. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/git.py +0 -0
  47. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/git_backend.py +0 -0
  48. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/included.py +0 -0
  49. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/init.py +0 -0
  50. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/jj.py +0 -0
  51. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/jj_backend.py +0 -0
  52. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/jj_lock.py +0 -0
  53. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/lib.py +0 -0
  54. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/list_changes.py +0 -0
  55. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/processes.py +0 -0
  56. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/skill/SKILL.md +0 -0
  57. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/skill.py +0 -0
  58. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/sync.py +0 -0
  59. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/sync_branch.py +0 -0
  60. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/sync_merge.py +0 -0
  61. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/sync_split_users.py +0 -0
  62. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/toml_writer.py +0 -0
  63. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/words.py +0 -0
  64. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son/writable.py +0 -0
  65. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son.egg-info/dependency_links.txt +0 -0
  66. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son.egg-info/entry_points.txt +0 -0
  67. {git_p4son-0.7.0 → git_p4son-0.8.0}/git_p4son.egg-info/top_level.txt +0 -0
  68. {git_p4son-0.7.0 → git_p4son-0.8.0}/setup.cfg +0 -0
  69. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_catch_up.py +0 -0
  70. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_cli.py +0 -0
  71. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_completion_scripts.py +0 -0
  72. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_config.py +0 -0
  73. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_depot.py +0 -0
  74. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_description.py +0 -0
  75. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_git.py +0 -0
  76. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_git_backend.py +0 -0
  77. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_init.py +0 -0
  78. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_isolation.py +0 -0
  79. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_lib.py +0 -0
  80. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_list_changes.py +0 -0
  81. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_per_commit.py +0 -0
  82. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_processes.py +0 -0
  83. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_skill.py +0 -0
  84. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_sync_merge.py +0 -0
  85. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_sync_split_users.py +0 -0
  86. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_toml_writer.py +0 -0
  87. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_update.py +0 -0
  88. {git_p4son-0.7.0 → git_p4son-0.8.0}/tests/test_writable.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: git-p4son
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: Utility for keeping a Perforce workspace and local git or jj repo in sync
5
5
  Author-email: Andreas Andersson <andreas@neoboid.com>
6
6
  License-Expression: MIT
@@ -8,7 +8,7 @@ Project-URL: Homepage, https://github.com/neoboid/git-p4son
8
8
  Project-URL: Repository, https://github.com/neoboid/git-p4son
9
9
  Project-URL: Issues, https://github.com/neoboid/git-p4son/issues
10
10
  Project-URL: Changelog, https://github.com/neoboid/git-p4son/blob/main/CHANGELOG.md
11
- Keywords: perforce,git,version-control,sync
11
+ Keywords: perforce,git,jj,jujutsu,version-control,sync
12
12
  Classifier: Development Status :: 4 - Beta
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: Programming Language :: Python :: 3
@@ -297,8 +297,12 @@ write most of them; the rest you edit by hand.
297
297
  `$(user)` stands for you. See [Split users](#split-users)
298
298
  - `[sync] blocking-processes` (list of strings, default empty): processes that stop a sync while they run. See
299
299
  [Blocking processes](#blocking-processes)
300
- - `[hooks.extension-associations]` (table, Windows only): the command that runs a hook script, by file extension.
301
- See [Hooks](#hooks)
300
+ - `[review-tool] default` (string, default `"swarm"`): the [review tool](#review-tools) `new --review` and `review`
301
+ push to without `--review-tool`
302
+ - `[review-tool.<name>]` (table): a [review tool](#review-tools)'s `command`, and its `new` and `update` arguments
303
+ - `[core.script-runners]` (table, Windows only): the command that runs a hook script, by file extension.
304
+ See [Hooks](#hooks). The old `[hooks.extension-associations]` is still read, and `core.script-runners` wins where
305
+ both name an extension
302
306
 
303
307
  For example:
304
308
 
@@ -532,7 +536,7 @@ bash, zsh and PowerShell run `$(user)` as a command substitution.
532
536
  ### New Command
533
537
 
534
538
  Create a new Perforce changelist and add changed files to it. Description will contain an enumerated list of git commits
535
- since the base branch. Optionally creates a Swarm review.
539
+ since the base branch. Optionally creates a review, in Swarm or another [review tool](#review-tools).
536
540
 
537
541
  Opening files requires a clean git workspace, untracked files included; `new` refuses to run otherwise. The check
538
542
  is skipped with `--no-edit`. After opening files, unchanged ones are reverted (see
@@ -540,7 +544,7 @@ is skipped with `--no-edit`. After opening files, unchanged ones are reverted (s
540
544
 
541
545
  ```sh
542
546
  git p4son new -b BASE_BRANCH [-m <message> | -F <file>] [alias] [--force] [--dry-run] [--no-edit]
543
- [--no-alias] [--no-commit-list] [--shelve] [--review] [--per-commit]
547
+ [--no-alias] [--no-commit-list] [--shelve] [--review] [--review-tool NAME] [--per-commit]
544
548
  ```
545
549
 
546
550
  **Arguments:**
@@ -561,16 +565,20 @@ git p4son new -b BASE_BRANCH [-m <message> | -F <file>] [alias] [--force] [--dry
561
565
  - `--no-edit`: Skip opening changed files for edit in Perforce
562
566
  - `--no-alias`: Skip saving a changelist alias
563
567
  - `--shelve`: Shelve the changelist after creating it
564
- - `--review`: Add `#review` keyword and shelve to create a Swarm review
568
+ - `--review`: Shelve and create a review with the default [review tool](#review-tools), Swarm unless
569
+ `[review-tool] default` names another. For Swarm, adds the `#review` keyword
570
+ - `--review-tool NAME`: Push the review to this review tool instead of the default one: `swarm`, or a
571
+ `[review-tool.NAME]` in `.git-p4son/config.toml`. Implies `--review`. The alias records the tool, which
572
+ `update --shelve` then runs
565
573
  - `--per-commit`: Create the changelist on the first commit since the base branch, then update it once per later
566
574
  commit, as described below. Refuses `--no-edit` and `--no-alias`
567
575
 
568
576
  With `--per-commit`, `new` checks out the first commit since the base branch and runs `git p4son new` on it, then
569
577
  checks out each later commit and runs `git p4son update` on it, and finally returns to where you started. With
570
- `--shelve` or `--review`, every step shelves, so each commit shows up as its own patch in the Swarm review, and every
571
- step but the last sleeps 5 seconds to give Perforce/Swarm time to process the shelf. It needs a clean git
572
- workspace even with `--dry-run`. [`review`](#review-command) is `new --review --per-commit`, and describes the steps,
573
- the dry run and resuming after a failed step.
578
+ `--shelve` or `--review`, every step shelves, so each commit shows up as its own patch in the review. With Swarm,
579
+ every step but the last sleeps 5 seconds to give Perforce/Swarm time to process the shelf; another review tool runs
580
+ once per step instead. It needs a clean git workspace even with `--dry-run`. [`review`](#review-command) is
581
+ `new --review --per-commit`, and describes the steps, the dry run and resuming after a failed step.
574
582
 
575
583
  **Examples:**
576
584
  ```sh
@@ -658,10 +666,12 @@ git p4son update [changelist] [-m <message> | -F <file>] [--base-branch BASE_BRA
658
666
  touched at all
659
667
  - `--no-edit`: Skip opening changed files for edit in Perforce. With a record, the new commits are then neither
660
668
  appended nor counted, so the next update that opens files includes them
661
- - `--shelve`: Re-shelve the changelist after updating
669
+ - `--shelve`: Re-shelve the changelist after updating. For a review in a [review tool](#review-tools) other than
670
+ Swarm, as the alias records it, the tool then runs for the new shelf
662
671
  - `--per-commit`: Update the changelist once per commit it doesn't include yet, or since the base branch without
663
672
  a record, oldest first, with each commit checked out in turn. With `--shelve`, steps sleep 5 seconds between them
664
- to give Perforce/Swarm time to process each shelf. `--dry-run` prints the steps, one per commit
673
+ to give Perforce/Swarm time to process each shelf, unless another review tool has the changelist. `--dry-run`
674
+ prints the steps, one per commit
665
675
 
666
676
  **Examples:**
667
677
  ```sh
@@ -697,16 +707,18 @@ are left out of it.
697
707
 
698
708
  ### Review Command
699
709
 
700
- Create a Swarm review with one shelf per commit. `review` is short for `git p4son new --review --per-commit`, taking the
710
+ Create a review with one shelf per commit. `review` is short for `git p4son new --review --per-commit`, taking the
701
711
  same arguments apart from `--review`, `--per-commit`, `--shelve`, `--no-edit` and `--no-alias`. It checks out the first
702
712
  commit since the base branch and runs `git p4son new --review` on it, then checks out each later commit and runs
703
- `git p4son update --shelve`, and finally returns to where you started. Every step but the last sleeps 5 seconds to give
704
- Perforce/Swarm time to process the shelf. The commits are reviewed where they are: to review them on top of the latest
713
+ `git p4son update --shelve`, and finally returns to where you started. With Swarm, every step but the last sleeps 5
714
+ seconds to give Perforce/Swarm time to process the shelf. Another [review tool](#review-tools) runs once per step
715
+ instead, with no sleep. The commits are reviewed where they are: to review them on top of the latest
705
716
  `main`, rebase first. Like `new`, it needs a clean git workspace, untracked files included, and checks it even with
706
717
  `--dry-run`.
707
718
 
708
719
  ```sh
709
720
  git p4son review -b BASE_BRANCH [alias] [-m <message> | -F <file>] [--force] [--dry-run] [--no-commit-list]
721
+ [--review-tool NAME]
710
722
  ```
711
723
 
712
724
  **Arguments:**
@@ -852,8 +864,9 @@ git p4son alias delete [alias | --all]
852
864
  - `alias` (optional): Alias name to delete. Defaults to the current branch name.
853
865
 
854
866
  **Options:**
855
- - `--all`: Delete all aliases without prompting. Unlike `alias clean`, it does not ask first, which suits scripts
856
- and AI agents
867
+ - `--all`: Delete all aliases without prompting, whether their changelists are pending or not. To delete only those
868
+ that are not, use `alias clean`. An alias that can't be deleted is reported and skipped, and the command then exits
869
+ with 1
857
870
 
858
871
  **Examples:**
859
872
  ```sh
@@ -864,27 +877,37 @@ git p4son alias delete --all
864
877
 
865
878
  #### alias clean
866
879
 
867
- Clean up changelist aliases:
880
+ Delete the aliases whose changelist is no longer pending, as it was submitted or deleted:
868
881
 
869
882
  ```sh
870
- git p4son alias clean
883
+ git p4son alias clean [-n] [--porcelain]
871
884
  ```
872
885
 
873
- It first moves any aliases still in `.git-p4son/changelists/` to `.git-p4son/aliases/`, then lists all aliases and
874
- asks how to proceed:
875
- - `a` (all): Delete all aliases
876
- - `i` (interactive): Review each alias one by one
877
- - `q` (quit): Exit without deleting anything
886
+ It first moves any aliases still in `.git-p4son/changelists/` to `.git-p4son/aliases/`, then goes through the aliases
887
+ in name order, each under a heading of its own: it looks up the alias's changelist in Perforce and deletes the alias
888
+ if the changelist was submitted or doesn't exist. If p4 answers neither that nor pending for a changelist, it stops
889
+ there, leaving that alias and the ones after it. A submit that renumbers the changelist leaves its old number behind,
890
+ which counts as gone too. With the jj backend, an alias whose [jj change](#jujutsu-jj) is gone but whose changelist
891
+ is still pending is kept; `alias list` marks it `(gone)`, and `alias delete` removes it.
892
+
893
+ It ends under an `Alias clean done` heading with how many aliases it deleted and kept. If any couldn't be deleted,
894
+ that line is a warning with how many failed, followed by an error, and the command exits with 1.
895
+
896
+ To delete specific aliases, use `alias list` and `alias delete`.
878
897
 
879
- In interactive mode, each alias is displayed in turn with a prompt:
880
- - `y` (yes): Delete this alias
881
- - `n` (no): Keep this alias
882
- - `a` (all): Delete this and all remaining aliases (handy for keeping the first few and sweeping the rest)
883
- - `q` (quit): Stop and keep remaining aliases
898
+ **Options:**
899
+ - `-n, --dry-run`: List the aliases that would be deleted, without deleting or moving any. Ends with
900
+ `Dry run, nothing changed`
901
+ - `--porcelain`: Print only one `<action> <alias> <CL>` line per alias, for scripts and agents. The action is `kept`,
902
+ `deleted`, or `failed` when the alias couldn't be deleted; with `-n` it is `would-keep` or `would-delete`. Errors
903
+ still go to stderr. A `failed` alias makes the exit code 1, after the lines for all aliases; a stop exits with 1,
904
+ with no line for the alias it stopped at or those after it.
884
905
 
885
906
  **Examples:**
886
907
  ```sh
908
+ git p4son alias clean -n # see which aliases would go
887
909
  git p4son alias clean
910
+ git p4son alias clean --porcelain # e.g. "deleted feature-login 12345"
888
911
  ```
889
912
 
890
913
  ### Writable Command
@@ -957,6 +980,57 @@ Most commands that accept an alias or changelist argument default to the current
957
980
  The keyword cannot be used in a detached HEAD state. Use `--no-alias` (on `new`) or supply an explicit
958
981
  alias name instead.
959
982
 
983
+ ## Review Tools
984
+
985
+ `new --review` and `review` create a review in Swarm by default: the description gets a `#review` keyword, and Swarm
986
+ picks up each shelf. A team that reviews with another tool, one that has to be run to post each shelf, configures the
987
+ tool's command line under a name of its choosing in `.git-p4son/config.toml`:
988
+
989
+ ```toml
990
+ [review-tool]
991
+ default = "my-tool"
992
+
993
+ [review-tool.my-tool]
994
+ command = ["python", "tools/my-review.py", "--p4port", "$(p4port)", "--changelist", "$(changelist)"]
995
+ new = ["create"]
996
+ update = ["update"]
997
+ ```
998
+
999
+ `--review-tool my-tool` pushes a review to it, and `default` makes it the default, so `--review-tool swarm` picks
1000
+ Swarm again. The alias records the changelist's tool, so `update --shelve` runs it again without naming it; to move a
1001
+ change to another tool, delete the changelist and its alias and create the review again. `--no-alias` is refused with
1002
+ any tool but Swarm.
1003
+
1004
+ With a review tool other than Swarm, there is no `#review` keyword, and after each shelve of the review git-p4son runs
1005
+ `command` from the workspace root, once per commit with `review`. On the shelve of `new`, the `new` arguments are
1006
+ added to it, to create the review, and on the shelves of `update` the `update` ones, to add the new shelf as a
1007
+ revision of it. If the first run fails, the `update --shelve` that reruns it still gets the `new` arguments, as the
1008
+ review doesn't exist yet. Both are optional; without one, `command` runs as it is.
1009
+
1010
+ `command`, `new` and `update` are lists, one string per argument; a single string is refused. No shell runs them,
1011
+ so they work the same on every platform and never need quoting. A program named by a relative path, such as
1012
+ `tools/review.exe`, is found from the workspace root, and a bare name, such as `python`, on `PATH`. A `.cmd` or `.ps1`
1013
+ script on Windows needs its interpreter named, such as `["pwsh", "-File", "tools/my-review.ps1"]`. `$(name)` in an
1014
+ argument is replaced:
1015
+
1016
+ - `$(changelist)`: the pending changelist number
1017
+ - `$(workspace)`: the Perforce client workspace name
1018
+ - `$(user)`: the Perforce user
1019
+ - `$(p4port)`: the server address, as `p4 set P4PORT` gives it
1020
+ - any other name: the environment variable of that name, which on Windows ignores case. A name that is neither fails
1021
+ the command before anything runs
1022
+
1023
+ A replaced value stays within its argument, spaces and all. The command is echoed with the values in, so it can be
1024
+ rerun by hand; that also shows any token passed through an environment variable. Anything more, such as settings
1025
+ files or a sign-in, goes in a wrapper script of your own that the command runs.
1026
+
1027
+ The first run can sign in or open a browser; later ones run once per shelve, often as the steps of a per-commit run,
1028
+ so keep them non-interactive. A tool that exits with a non-zero code fails the command. `review` then stops at that
1029
+ commit with the command that resumes it, which shelves the commit again and reruns the tool, and `new` names the
1030
+ `update <alias> --shelve` that reruns it once the tool works. `--dry-run` says which tool would run. The tool runs on
1031
+ the terminal, so its output shows as it is written and it can prompt. Like a hook, it runs under git-p4son's
1032
+ [jj lock](#locking-and-the-git-workflow), so it must not run jj commands that snapshot.
1033
+
960
1034
  ## Hooks
961
1035
 
962
1036
  Hooks work similarly to git hooks. They are executables (unix)/scripts (windows) that you place in
@@ -968,17 +1042,17 @@ The hook process CWD is the directory where git-p4son was invoked, and `GIT_P4SO
968
1042
  set to the git-p4son repository root. `GIT_P4SON_BACKEND` is `git` or `jj`, the [backend](#choosing-the-backend)
969
1043
  the command runs with.
970
1044
 
971
- On Windows, `.ps1`, `.nu`, `.sh`, and `.py` files are run with
972
- `powershell.exe -NoProfile -ExecutionPolicy Bypass -File`, `nu.exe`, `bash.exe`, and `python.exe` respectively.
973
- Customize or add Windows script associations in `.git-p4son/config.toml`:
1045
+ On Windows, `.ps1`, `.sh`, and `.py` files are run with
1046
+ `powershell.exe -NoProfile -ExecutionPolicy Bypass -File`, `bash.exe`, and `python.exe` respectively.
1047
+ Customize or add Windows script runners in `.git-p4son/config.toml`:
974
1048
 
975
1049
  ```toml
976
- [hooks.extension-associations]
1050
+ [core.script-runners]
977
1051
  ".ps1" = ["pwsh.exe", "-NoProfile", "-File"]
978
- ".py" = "python.exe"
1052
+ ".nu" = "nu.exe"
979
1053
  ```
980
1054
 
981
- Non-executable or unrecognized hook files, and invalid association entries, are skipped with a warning.
1055
+ Non-executable or unrecognized hook files, and invalid runner entries, are skipped with a warning.
982
1056
 
983
1057
  ### pre-sync hook
984
1058
 
@@ -274,8 +274,12 @@ write most of them; the rest you edit by hand.
274
274
  `$(user)` stands for you. See [Split users](#split-users)
275
275
  - `[sync] blocking-processes` (list of strings, default empty): processes that stop a sync while they run. See
276
276
  [Blocking processes](#blocking-processes)
277
- - `[hooks.extension-associations]` (table, Windows only): the command that runs a hook script, by file extension.
278
- See [Hooks](#hooks)
277
+ - `[review-tool] default` (string, default `"swarm"`): the [review tool](#review-tools) `new --review` and `review`
278
+ push to without `--review-tool`
279
+ - `[review-tool.<name>]` (table): a [review tool](#review-tools)'s `command`, and its `new` and `update` arguments
280
+ - `[core.script-runners]` (table, Windows only): the command that runs a hook script, by file extension.
281
+ See [Hooks](#hooks). The old `[hooks.extension-associations]` is still read, and `core.script-runners` wins where
282
+ both name an extension
279
283
 
280
284
  For example:
281
285
 
@@ -509,7 +513,7 @@ bash, zsh and PowerShell run `$(user)` as a command substitution.
509
513
  ### New Command
510
514
 
511
515
  Create a new Perforce changelist and add changed files to it. Description will contain an enumerated list of git commits
512
- since the base branch. Optionally creates a Swarm review.
516
+ since the base branch. Optionally creates a review, in Swarm or another [review tool](#review-tools).
513
517
 
514
518
  Opening files requires a clean git workspace, untracked files included; `new` refuses to run otherwise. The check
515
519
  is skipped with `--no-edit`. After opening files, unchanged ones are reverted (see
@@ -517,7 +521,7 @@ is skipped with `--no-edit`. After opening files, unchanged ones are reverted (s
517
521
 
518
522
  ```sh
519
523
  git p4son new -b BASE_BRANCH [-m <message> | -F <file>] [alias] [--force] [--dry-run] [--no-edit]
520
- [--no-alias] [--no-commit-list] [--shelve] [--review] [--per-commit]
524
+ [--no-alias] [--no-commit-list] [--shelve] [--review] [--review-tool NAME] [--per-commit]
521
525
  ```
522
526
 
523
527
  **Arguments:**
@@ -538,16 +542,20 @@ git p4son new -b BASE_BRANCH [-m <message> | -F <file>] [alias] [--force] [--dry
538
542
  - `--no-edit`: Skip opening changed files for edit in Perforce
539
543
  - `--no-alias`: Skip saving a changelist alias
540
544
  - `--shelve`: Shelve the changelist after creating it
541
- - `--review`: Add `#review` keyword and shelve to create a Swarm review
545
+ - `--review`: Shelve and create a review with the default [review tool](#review-tools), Swarm unless
546
+ `[review-tool] default` names another. For Swarm, adds the `#review` keyword
547
+ - `--review-tool NAME`: Push the review to this review tool instead of the default one: `swarm`, or a
548
+ `[review-tool.NAME]` in `.git-p4son/config.toml`. Implies `--review`. The alias records the tool, which
549
+ `update --shelve` then runs
542
550
  - `--per-commit`: Create the changelist on the first commit since the base branch, then update it once per later
543
551
  commit, as described below. Refuses `--no-edit` and `--no-alias`
544
552
 
545
553
  With `--per-commit`, `new` checks out the first commit since the base branch and runs `git p4son new` on it, then
546
554
  checks out each later commit and runs `git p4son update` on it, and finally returns to where you started. With
547
- `--shelve` or `--review`, every step shelves, so each commit shows up as its own patch in the Swarm review, and every
548
- step but the last sleeps 5 seconds to give Perforce/Swarm time to process the shelf. It needs a clean git
549
- workspace even with `--dry-run`. [`review`](#review-command) is `new --review --per-commit`, and describes the steps,
550
- the dry run and resuming after a failed step.
555
+ `--shelve` or `--review`, every step shelves, so each commit shows up as its own patch in the review. With Swarm,
556
+ every step but the last sleeps 5 seconds to give Perforce/Swarm time to process the shelf; another review tool runs
557
+ once per step instead. It needs a clean git workspace even with `--dry-run`. [`review`](#review-command) is
558
+ `new --review --per-commit`, and describes the steps, the dry run and resuming after a failed step.
551
559
 
552
560
  **Examples:**
553
561
  ```sh
@@ -635,10 +643,12 @@ git p4son update [changelist] [-m <message> | -F <file>] [--base-branch BASE_BRA
635
643
  touched at all
636
644
  - `--no-edit`: Skip opening changed files for edit in Perforce. With a record, the new commits are then neither
637
645
  appended nor counted, so the next update that opens files includes them
638
- - `--shelve`: Re-shelve the changelist after updating
646
+ - `--shelve`: Re-shelve the changelist after updating. For a review in a [review tool](#review-tools) other than
647
+ Swarm, as the alias records it, the tool then runs for the new shelf
639
648
  - `--per-commit`: Update the changelist once per commit it doesn't include yet, or since the base branch without
640
649
  a record, oldest first, with each commit checked out in turn. With `--shelve`, steps sleep 5 seconds between them
641
- to give Perforce/Swarm time to process each shelf. `--dry-run` prints the steps, one per commit
650
+ to give Perforce/Swarm time to process each shelf, unless another review tool has the changelist. `--dry-run`
651
+ prints the steps, one per commit
642
652
 
643
653
  **Examples:**
644
654
  ```sh
@@ -674,16 +684,18 @@ are left out of it.
674
684
 
675
685
  ### Review Command
676
686
 
677
- Create a Swarm review with one shelf per commit. `review` is short for `git p4son new --review --per-commit`, taking the
687
+ Create a review with one shelf per commit. `review` is short for `git p4son new --review --per-commit`, taking the
678
688
  same arguments apart from `--review`, `--per-commit`, `--shelve`, `--no-edit` and `--no-alias`. It checks out the first
679
689
  commit since the base branch and runs `git p4son new --review` on it, then checks out each later commit and runs
680
- `git p4son update --shelve`, and finally returns to where you started. Every step but the last sleeps 5 seconds to give
681
- Perforce/Swarm time to process the shelf. The commits are reviewed where they are: to review them on top of the latest
690
+ `git p4son update --shelve`, and finally returns to where you started. With Swarm, every step but the last sleeps 5
691
+ seconds to give Perforce/Swarm time to process the shelf. Another [review tool](#review-tools) runs once per step
692
+ instead, with no sleep. The commits are reviewed where they are: to review them on top of the latest
682
693
  `main`, rebase first. Like `new`, it needs a clean git workspace, untracked files included, and checks it even with
683
694
  `--dry-run`.
684
695
 
685
696
  ```sh
686
697
  git p4son review -b BASE_BRANCH [alias] [-m <message> | -F <file>] [--force] [--dry-run] [--no-commit-list]
698
+ [--review-tool NAME]
687
699
  ```
688
700
 
689
701
  **Arguments:**
@@ -829,8 +841,9 @@ git p4son alias delete [alias | --all]
829
841
  - `alias` (optional): Alias name to delete. Defaults to the current branch name.
830
842
 
831
843
  **Options:**
832
- - `--all`: Delete all aliases without prompting. Unlike `alias clean`, it does not ask first, which suits scripts
833
- and AI agents
844
+ - `--all`: Delete all aliases without prompting, whether their changelists are pending or not. To delete only those
845
+ that are not, use `alias clean`. An alias that can't be deleted is reported and skipped, and the command then exits
846
+ with 1
834
847
 
835
848
  **Examples:**
836
849
  ```sh
@@ -841,27 +854,37 @@ git p4son alias delete --all
841
854
 
842
855
  #### alias clean
843
856
 
844
- Clean up changelist aliases:
857
+ Delete the aliases whose changelist is no longer pending, as it was submitted or deleted:
845
858
 
846
859
  ```sh
847
- git p4son alias clean
860
+ git p4son alias clean [-n] [--porcelain]
848
861
  ```
849
862
 
850
- It first moves any aliases still in `.git-p4son/changelists/` to `.git-p4son/aliases/`, then lists all aliases and
851
- asks how to proceed:
852
- - `a` (all): Delete all aliases
853
- - `i` (interactive): Review each alias one by one
854
- - `q` (quit): Exit without deleting anything
863
+ It first moves any aliases still in `.git-p4son/changelists/` to `.git-p4son/aliases/`, then goes through the aliases
864
+ in name order, each under a heading of its own: it looks up the alias's changelist in Perforce and deletes the alias
865
+ if the changelist was submitted or doesn't exist. If p4 answers neither that nor pending for a changelist, it stops
866
+ there, leaving that alias and the ones after it. A submit that renumbers the changelist leaves its old number behind,
867
+ which counts as gone too. With the jj backend, an alias whose [jj change](#jujutsu-jj) is gone but whose changelist
868
+ is still pending is kept; `alias list` marks it `(gone)`, and `alias delete` removes it.
869
+
870
+ It ends under an `Alias clean done` heading with how many aliases it deleted and kept. If any couldn't be deleted,
871
+ that line is a warning with how many failed, followed by an error, and the command exits with 1.
872
+
873
+ To delete specific aliases, use `alias list` and `alias delete`.
855
874
 
856
- In interactive mode, each alias is displayed in turn with a prompt:
857
- - `y` (yes): Delete this alias
858
- - `n` (no): Keep this alias
859
- - `a` (all): Delete this and all remaining aliases (handy for keeping the first few and sweeping the rest)
860
- - `q` (quit): Stop and keep remaining aliases
875
+ **Options:**
876
+ - `-n, --dry-run`: List the aliases that would be deleted, without deleting or moving any. Ends with
877
+ `Dry run, nothing changed`
878
+ - `--porcelain`: Print only one `<action> <alias> <CL>` line per alias, for scripts and agents. The action is `kept`,
879
+ `deleted`, or `failed` when the alias couldn't be deleted; with `-n` it is `would-keep` or `would-delete`. Errors
880
+ still go to stderr. A `failed` alias makes the exit code 1, after the lines for all aliases; a stop exits with 1,
881
+ with no line for the alias it stopped at or those after it.
861
882
 
862
883
  **Examples:**
863
884
  ```sh
885
+ git p4son alias clean -n # see which aliases would go
864
886
  git p4son alias clean
887
+ git p4son alias clean --porcelain # e.g. "deleted feature-login 12345"
865
888
  ```
866
889
 
867
890
  ### Writable Command
@@ -934,6 +957,57 @@ Most commands that accept an alias or changelist argument default to the current
934
957
  The keyword cannot be used in a detached HEAD state. Use `--no-alias` (on `new`) or supply an explicit
935
958
  alias name instead.
936
959
 
960
+ ## Review Tools
961
+
962
+ `new --review` and `review` create a review in Swarm by default: the description gets a `#review` keyword, and Swarm
963
+ picks up each shelf. A team that reviews with another tool, one that has to be run to post each shelf, configures the
964
+ tool's command line under a name of its choosing in `.git-p4son/config.toml`:
965
+
966
+ ```toml
967
+ [review-tool]
968
+ default = "my-tool"
969
+
970
+ [review-tool.my-tool]
971
+ command = ["python", "tools/my-review.py", "--p4port", "$(p4port)", "--changelist", "$(changelist)"]
972
+ new = ["create"]
973
+ update = ["update"]
974
+ ```
975
+
976
+ `--review-tool my-tool` pushes a review to it, and `default` makes it the default, so `--review-tool swarm` picks
977
+ Swarm again. The alias records the changelist's tool, so `update --shelve` runs it again without naming it; to move a
978
+ change to another tool, delete the changelist and its alias and create the review again. `--no-alias` is refused with
979
+ any tool but Swarm.
980
+
981
+ With a review tool other than Swarm, there is no `#review` keyword, and after each shelve of the review git-p4son runs
982
+ `command` from the workspace root, once per commit with `review`. On the shelve of `new`, the `new` arguments are
983
+ added to it, to create the review, and on the shelves of `update` the `update` ones, to add the new shelf as a
984
+ revision of it. If the first run fails, the `update --shelve` that reruns it still gets the `new` arguments, as the
985
+ review doesn't exist yet. Both are optional; without one, `command` runs as it is.
986
+
987
+ `command`, `new` and `update` are lists, one string per argument; a single string is refused. No shell runs them,
988
+ so they work the same on every platform and never need quoting. A program named by a relative path, such as
989
+ `tools/review.exe`, is found from the workspace root, and a bare name, such as `python`, on `PATH`. A `.cmd` or `.ps1`
990
+ script on Windows needs its interpreter named, such as `["pwsh", "-File", "tools/my-review.ps1"]`. `$(name)` in an
991
+ argument is replaced:
992
+
993
+ - `$(changelist)`: the pending changelist number
994
+ - `$(workspace)`: the Perforce client workspace name
995
+ - `$(user)`: the Perforce user
996
+ - `$(p4port)`: the server address, as `p4 set P4PORT` gives it
997
+ - any other name: the environment variable of that name, which on Windows ignores case. A name that is neither fails
998
+ the command before anything runs
999
+
1000
+ A replaced value stays within its argument, spaces and all. The command is echoed with the values in, so it can be
1001
+ rerun by hand; that also shows any token passed through an environment variable. Anything more, such as settings
1002
+ files or a sign-in, goes in a wrapper script of your own that the command runs.
1003
+
1004
+ The first run can sign in or open a browser; later ones run once per shelve, often as the steps of a per-commit run,
1005
+ so keep them non-interactive. A tool that exits with a non-zero code fails the command. `review` then stops at that
1006
+ commit with the command that resumes it, which shelves the commit again and reruns the tool, and `new` names the
1007
+ `update <alias> --shelve` that reruns it once the tool works. `--dry-run` says which tool would run. The tool runs on
1008
+ the terminal, so its output shows as it is written and it can prompt. Like a hook, it runs under git-p4son's
1009
+ [jj lock](#locking-and-the-git-workflow), so it must not run jj commands that snapshot.
1010
+
937
1011
  ## Hooks
938
1012
 
939
1013
  Hooks work similarly to git hooks. They are executables (unix)/scripts (windows) that you place in
@@ -945,17 +1019,17 @@ The hook process CWD is the directory where git-p4son was invoked, and `GIT_P4SO
945
1019
  set to the git-p4son repository root. `GIT_P4SON_BACKEND` is `git` or `jj`, the [backend](#choosing-the-backend)
946
1020
  the command runs with.
947
1021
 
948
- On Windows, `.ps1`, `.nu`, `.sh`, and `.py` files are run with
949
- `powershell.exe -NoProfile -ExecutionPolicy Bypass -File`, `nu.exe`, `bash.exe`, and `python.exe` respectively.
950
- Customize or add Windows script associations in `.git-p4son/config.toml`:
1022
+ On Windows, `.ps1`, `.sh`, and `.py` files are run with
1023
+ `powershell.exe -NoProfile -ExecutionPolicy Bypass -File`, `bash.exe`, and `python.exe` respectively.
1024
+ Customize or add Windows script runners in `.git-p4son/config.toml`:
951
1025
 
952
1026
  ```toml
953
- [hooks.extension-associations]
1027
+ [core.script-runners]
954
1028
  ".ps1" = ["pwsh.exe", "-NoProfile", "-File"]
955
- ".py" = "python.exe"
1029
+ ".nu" = "nu.exe"
956
1030
  ```
957
1031
 
958
- Non-executable or unrecognized hook files, and invalid association entries, are skipped with a warning.
1032
+ Non-executable or unrecognized hook files, and invalid runner entries, are skipped with a warning.
959
1033
 
960
1034
  ### pre-sync hook
961
1035
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  CONFIG_DIR = '.git-p4son'
4
4
 
5
- __version__ = "0.7.0"
5
+ __version__ = "0.8.0"
6
6
  __author__ = "Andreas Andersson"
7
7
  __email__ = "andreas@neoboid.com"