git@vger.kernel.org mailing list mirror (one of many)
 help / Atom feed
* [PATCH 00/29] t: detect and fix broken &&-chains in subshells
@ 2018-06-26  7:29 Eric Sunshine
  2018-06-26  7:29 ` [PATCH 01/29] t7508: use test_when_finished() instead of managing exit code manually Eric Sunshine
                   ` (31 more replies)
  0 siblings, 32 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

The --chain-lint[1] option detects breakage in the top-level &&-chain of
tests. This series undertakes the more complex task of teaching it to
also detect &&-chain breakage within subshells. See patch 29/29 for the
gory details of how that's done.

The series is built atop 'master', however, it has a conflict with an
in-flight topic. In particular, patch 1/29 rewrites a test in t7508 in
'master' to avoid &&-chain breakage. 'jc/clean-after-sanity-tests' in
'next' performs pretty much the same rewrite. If this series is queued
atop 'master', then it needs patch 1/29; if it is queued somewhere above
'jc/clean-after-sanity-tests', then 1/29 can be dropped.

Aside from identifying a rather significant number of &&-chain breaks,
repairing those broken chains uncovered genuine bugs in several tests
which were hidden by missing &&-chain links. Those bugs are also fixed
by this series. I would appreciate if the following people would
double-check my fixes:

Stefan Bellar - 8/29 "t7400" and (especially) 13/29 "lib-submodule-update"
Jonathan Tan - 10/29 "t9001"
Elijah Newren - 6/29 "t6036"

In order to keep the noise level down and ease review burden, please
take into account that I largely avoided modernizations and cleanups,
and limited changes to merely adding "&&" even when some other
transformation would have made the fix nicer overall. (For example, I
resisted the urge to replace a series of 'echo' statements in a subshell
with a simple here-doc.)

Finally, although all simple &&-chain fixes originally inhabited a
single patch, they were split out into several patches to avoid hitting
vger.kernel.org's message size limit. However, when queuing, all patches
titled "t????: fix broken &&-chains in subshells" could be squashed into
a single patch titled "t: fix broken &&-chains in subshells".

[1]: https://public-inbox.org/git/20150320100429.GA17354@peff.net/

Eric Sunshine (29):
  t7508: use test_when_finished() instead of managing exit code manually
  t0001: use "{...}" block around "||" expression rather than subshell
  t1300: use sane_unset() to avoid breaking &&-chain
  t3303: use standard here-doc tag "EOF" to avoid fooling --chain-lint
  t5505: modernize and simplify hard-to-digest test
  t6036: fix broken "merge fails but has appropriate contents" tests
  t7201: drop pointless "exit 0" at end of subshell
  t7400: fix broken "submodule add/reconfigure --force" test
  t7810: use test_expect_code() instead of hand-rolled comparison
  t9001: fix broken "invoke hook" test
  t9104: use "{...}" block around "||" expression rather than subshell
  t9401: drop unnecessary nested subshell
  t/lib-submodule-update: fix broken "replace submodule must-fail" test
  t: drop subshell with missing &&-chain in favor of simpler construct
  t: drop unnecessary terminating semicolons in subshell
  t: use test_might_fail() instead of manipulating exit code manually
  t: use test_must_fail() instead of checking exit code manually
  t0000-t0999: fix broken &&-chains in subshells
  t1000-t1999: fix broken &&-chains in subshells
  t2000-t2999: fix broken &&-chains in subshells
  t3000-t3999: fix broken &&-chains in subshells
  t3030: fix broken &&-chains in subshells
  t4000-t4999: fix broken &&-chains in subshells
  t5000-t5999: fix broken &&-chains in subshells
  t6000-t6999: fix broken &&-chains in subshells
  t7000-t7999: fix broken &&-chains in subshells
  t9000-t9999: fix broken &&-chains in subshells
  t9119: fix broken &&-chains in subshells
  t/test-lib: teach --chain-lint to detect broken &&-chains in subshells

 t/lib-submodule-update.sh                     |  10 +-
 t/t0000-basic.sh                              |   2 +-
 t/t0001-init.sh                               |   2 +-
 t/t0003-attributes.sh                         |  24 +-
 t/t0021-conversion.sh                         |   4 +-
 t/t0090-cache-tree.sh                         |   2 +-
 t/t1004-read-tree-m-u-wf.sh                   |   8 +-
 t/t1005-read-tree-reset.sh                    |  10 +-
 t/t1008-read-tree-overlay.sh                  |   2 +-
 t/t1020-subdirectory.sh                       |   2 +-
 t/t1050-large.sh                              |   6 +-
 t/t1300-config.sh                             |   2 +-
 t/t1411-reflog-show.sh                        |   6 +-
 t/t1507-rev-parse-upstream.sh                 |   6 +-
 t/t1512-rev-parse-disambiguation.sh           |   6 +-
 t/t1700-split-index.sh                        |   2 +-
 t/t2016-checkout-patch.sh                     |  24 +-
 t/t2103-update-index-ignore-missing.sh        |   2 +-
 t/t2202-add-addremove.sh                      |  14 +-
 t/t3000-ls-files-others.sh                    |   2 +-
 t/t3006-ls-files-long.sh                      |   2 +-
 t/t3008-ls-files-lazy-init-name-hash.sh       |   8 +-
 t/t3030-merge-recursive.sh                    | 340 +++++++++---------
 t/t3050-subprojects-fetch.sh                  |   8 +-
 t/t3102-ls-tree-wildcards.sh                  |   2 +-
 t/t3301-notes.sh                              |   8 +-
 t/t3303-notes-subtrees.sh                     |  12 +-
 t/t3400-rebase.sh                             |   8 +-
 t/t3402-rebase-merge.sh                       |   4 +-
 t/t3404-rebase-interactive.sh                 |   6 +-
 t/t3418-rebase-continue.sh                    |   4 +-
 t/t3700-add.sh                                |   8 +-
 t/t3701-add-interactive.sh                    |  16 +-
 t/t3904-stash-patch.sh                        |   8 +-
 t/t4001-diff-rename.sh                        |   2 +-
 t/t4010-diff-pathspec.sh                      |   4 +-
 t/t4012-diff-binary.sh                        |   6 +-
 t/t4025-hunk-header.sh                        |   8 +-
 t/t4041-diff-submodule-option.sh              |   4 +-
 t/t4060-diff-submodule-option-diff-format.sh  |   2 +-
 t/t4121-apply-diffs.sh                        |   2 +-
 t/t5300-pack-object.sh                        |   2 +-
 t/t5302-pack-index.sh                         |   2 +-
 t/t5400-send-pack.sh                          |   4 +-
 t/t5401-update-hooks.sh                       |   4 +-
 t/t5405-send-pack-rewind.sh                   |   3 +-
 t/t5406-remote-rejects.sh                     |   2 +-
 t/t5500-fetch-pack.sh                         |   2 +-
 t/t5505-remote.sh                             |  10 +-
 t/t5512-ls-remote.sh                          |   4 +-
 t/t5516-fetch-push.sh                         |  10 +-
 t/t5517-push-mirror.sh                        |  10 +-
 t/t5526-fetch-submodules.sh                   |   2 +-
 t/t5531-deep-submodule-push.sh                |   2 +-
 t/t5543-atomic-push.sh                        |   2 +-
 t/t5601-clone.sh                              |   2 +-
 t/t5605-clone-local.sh                        |   2 +-
 t/t5801-remote-helpers.sh                     |   2 +-
 t/t6010-merge-base.sh                         |   2 +-
 t/t6029-merge-subtree.sh                      |  16 +-
 t/t6036-recursive-corner-cases.sh             |  14 +-
 t/t6042-merge-rename-corner-cases.sh          |   8 +-
 t/t6043-merge-rename-directories.sh           |   2 +-
 t/t7001-mv.sh                                 |   2 +-
 t/t7105-reset-patch.sh                        |  12 +-
 t/t7201-co.sh                                 |  41 ++-
 t/t7301-clean-interactive.sh                  |  41 ++-
 t/t7400-submodule-basic.sh                    |  12 +-
 t/t7406-submodule-update.sh                   |   4 +-
 t/t7408-submodule-reference.sh                |   2 +-
 t/t7501-commit.sh                             |  56 +--
 t/t7506-status-submodule.sh                   |  10 +-
 t/t7508-status.sh                             |  20 +-
 t/t7610-mergetool.sh                          |   8 +-
 t/t7810-grep.sh                               |   7 +-
 t/t9001-send-email.sh                         |  10 +-
 t/t9100-git-svn-basic.sh                      |   2 +-
 t/t9101-git-svn-props.sh                      |   2 +-
 t/t9104-git-svn-follow-parent.sh              |   4 +-
 t/t9119-git-svn-info.sh                       | 120 +++----
 t/t9122-git-svn-author.sh                     |   6 +-
 t/t9129-git-svn-i18n-commitencoding.sh        |   2 +-
 t/t9130-git-svn-authors-file.sh               |   4 +-
 t/t9134-git-svn-ignore-paths.sh               |   6 +-
 t/t9137-git-svn-dcommit-clobber-series.sh     |   2 +-
 t/t9138-git-svn-authors-prog.sh               |   6 +-
 t/t9146-git-svn-empty-dirs.sh                 |  12 +-
 t/t9147-git-svn-include-paths.sh              |   6 +-
 t/t9164-git-svn-dcommit-concurrent.sh         |   2 +-
 ...65-git-svn-fetch-merge-branch-of-branch.sh |   2 +-
 t/t9200-git-cvsexportcommit.sh                |   6 +-
 t/t9400-git-cvsserver-server.sh               |   6 +-
 t/t9401-git-cvsserver-crlf.sh                 |   4 +-
 t/t9600-cvsimport.sh                          |   2 +-
 t/t9806-git-p4-options.sh                     |   2 +-
 t/t9810-git-p4-rcs.sh                         |   2 +-
 t/t9811-git-p4-label-import.sh                |   2 +-
 t/t9814-git-p4-rename.sh                      |  16 +-
 t/t9815-git-p4-submit-fail.sh                 |   2 +-
 t/t9830-git-p4-symlink-dir.sh                 |   2 +-
 t/t9831-git-p4-triggers.sh                    |   2 +-
 t/t9902-completion.sh                         |   4 +-
 t/t9903-bash-prompt.sh                        |   2 +-
 t/test-lib.sh                                 | 245 ++++++++++++-
 104 files changed, 810 insertions(+), 593 deletions(-)

-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 01/29] t7508: use test_when_finished() instead of managing exit code manually
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 02/29] t0001: use "{...}" block around "||" expression rather than subshell Eric Sunshine
                   ` (30 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

This test manages its own exit code in order to perform a cleanup action
unconditionally, whether the test succeeds or fails overall. In doing
so, it intentionally breaks the &&-chain. Such manual exit code
management to ensure cleanup predates the invention of
test_when_finished().

An upcoming change will teach --chain-lint to detect &&-chain breakage
inside subshells, so this manual exit code management with intentional
&&-chain breakage will run afoul of --chain-lint. Therefore, replace
the manual exit code handling with test_when_finished() and a normal
&&-chain. While at it, drop the now-unnecessary subshell.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---

Notes:
    This series is built atop 'master'. If the series is queued there,
    this patch is needed to avoid test-suite breakage. However, the
    issue fixed by this patch is already also fixed by
    'jc/clean-after-sanity-tests' in 'next' (although, that patch
    doesn't bother dropping the now-unnecessary subshell, like this
    patch does.)

 t/t7508-status.sh | 20 ++++++++------------
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 18a40257fb..67bf4393bb 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1099,18 +1099,14 @@ EOF
 '
 
 test_expect_success POSIXPERM,SANITY 'status succeeds in a read-only repository' '
-	(
-		chmod a-w .git &&
-		# make dir1/tracked stat-dirty
-		>dir1/tracked1 && mv -f dir1/tracked1 dir1/tracked &&
-		git status -s >output &&
-		! grep dir1/tracked output &&
-		# make sure "status" succeeded without writing index out
-		git diff-files | grep dir1/tracked
-	)
-	status=$?
-	chmod 775 .git
-	(exit $status)
+	chmod a-w .git &&
+	test_when_finished "chmod 775 .git" &&
+	# make dir1/tracked stat-dirty
+	>dir1/tracked1 && mv -f dir1/tracked1 dir1/tracked &&
+	git status -s >output &&
+	! grep dir1/tracked output &&
+	# make sure "status" succeeded without writing index out
+	git diff-files | grep dir1/tracked
 '
 
 (cd sm && echo > bar && git add bar && git commit -q -m 'Add bar') && git add sm
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 02/29] t0001: use "{...}" block around "||" expression rather than subshell
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
  2018-06-26  7:29 ` [PATCH 01/29] t7508: use test_when_finished() instead of managing exit code manually Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 03/29] t1300: use sane_unset() to avoid breaking &&-chain Eric Sunshine
                   ` (29 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

This test uses (... || true) as a shorthand for an if-then-else
statement. The subshell prevents it from breaking the top-level
&&-chain.

However, an upcoming change will teach --chain-lint to check the
&&-chain inside subshells. Although it specially recognizes and allows
(... || git ...) and (... || test*), it intentionally avoids treating
(... || true) specially since such a construct typically can be
expressed more naturally with test_might_fail() and a normal &&-chain.

This case is special, though, since the invoked command, 'setfacl',
might not even exist (indeed, MacOS has no such command) which is not a
valid use-case for test_might_fail(). Sidestep the issue by wrapping the
"||" expression in a "{...}" block instead of a subshell since "{...}"
blocks are not checked for &&-chain breakage.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t0001-init.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index c413bff9cf..fa44a55a5b 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -260,7 +260,7 @@ test_expect_success POSIXPERM 'init creates a new deep directory (umask vs. shar
 		# the repository itself should follow "shared"
 		mkdir newdir &&
 		# Remove a default ACL if possible.
-		(setfacl -k newdir 2>/dev/null || true) &&
+		{ setfacl -k newdir 2>/dev/null || true; } &&
 		umask 002 &&
 		git init --bare --shared=0660 newdir/a/b/c &&
 		test_path_is_dir newdir/a/b/c/refs &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 03/29] t1300: use sane_unset() to avoid breaking &&-chain
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
  2018-06-26  7:29 ` [PATCH 01/29] t7508: use test_when_finished() instead of managing exit code manually Eric Sunshine
  2018-06-26  7:29 ` [PATCH 02/29] t0001: use "{...}" block around "||" expression rather than subshell Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 04/29] t3303: use standard here-doc tag "EOF" to avoid fooling --chain-lint Eric Sunshine
                   ` (28 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

This test intentionally breaks the &&-chain after "unset HOME" since it
doesn't know if 'unset' will succeed or fail. However, an upcoming
change will teach --chain-lint to detect &&-chain breakage inside
subshells, and it will catch this broken &&-chain. Instead, use
sane_unset() which can be safely linked into the &&-chain.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t1300-config.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 03c223708e..24706ba412 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -888,7 +888,7 @@ EOF
 
 test_expect_success !MINGW 'get --path copes with unset $HOME' '
 	(
-		unset HOME;
+		sane_unset HOME &&
 		test_must_fail git config --get --path path.home \
 			>result 2>msg &&
 		git config --get --path path.normal >>result &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 04/29] t3303: use standard here-doc tag "EOF" to avoid fooling --chain-lint
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (2 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 03/29] t1300: use sane_unset() to avoid breaking &&-chain Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 05/29] t5505: modernize and simplify hard-to-digest test Eric Sunshine
                   ` (27 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

An upcoming change will teach --chain-lint to detect &&-chain breakage
inside subshells. The check works by performing textual transformations
on the test to link the subshell body directly into the parent's
&&-chain. Special care is taken with the final statement in a
subshell. For instance:

    statement1 &&
    (
        statement2
    ) &&
    statement3

is transformed to:

    statement1 &&
    statement2 &&
    statement3

Notice that "statement2" gains a "&&".

Special care is is taken with here-docs since "&&" needs to be added to
the "<<EOF" line which opens the here-doc, not the "EOF" line which
closes it. For practical reasons (namely, transformations are performed
line-by-line), only here-docs tagged with "EOF" are recognized.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t3303-notes-subtrees.sh | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/t/t3303-notes-subtrees.sh b/t/t3303-notes-subtrees.sh
index 704aee81ef..e353faa50b 100755
--- a/t/t3303-notes-subtrees.sh
+++ b/t/t3303-notes-subtrees.sh
@@ -39,7 +39,7 @@ test_expect_success "setup: create $number_of_commits commits" '
 		while [ $nr -lt $number_of_commits ]; do
 			nr=$(($nr+1)) &&
 			test_tick &&
-			cat <<INPUT_END
+			cat <<EOF
 commit refs/heads/master
 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 data <<COMMIT
@@ -47,15 +47,15 @@ commit #$nr
 COMMIT
 
 M 644 inline file
-data <<EOF
+data <<DATA
 file in commit #$nr
-EOF
+DATA
 
-INPUT_END
+EOF
 
 		done &&
 		test_tick &&
-		cat <<INPUT_END
+		cat <<EOF
 commit refs/notes/commits
 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 data <<COMMIT
@@ -64,7 +64,7 @@ COMMIT
 
 deleteall
 
-INPUT_END
+EOF
 
 	) |
 	git fast-import --quiet &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 05/29] t5505: modernize and simplify hard-to-digest test
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (3 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 04/29] t3303: use standard here-doc tag "EOF" to avoid fooling --chain-lint Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 06/29] t6036: fix broken "merge fails but has appropriate contents" tests Eric Sunshine
                   ` (26 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

This test uses a subshell within a subshell but is formatted in such a
way as to suggests that the inner subshell is a sibling rather than a
child, which makes it difficult to digest the test's structure and
intent.

Worse, the inner subshell performs cleanup of actions from earlier in
the test, however, a failure between the initial actions and the cleanup
will prevent the cleanup from taking place.

Fix these problems by modernizing and simplifying the test and by using
test_when_finished() for the cleanup action.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t5505-remote.sh | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index a6c0178f3a..3552b51b4c 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -348,17 +348,13 @@ URL: $(pwd)/one
 EOF
 
 test_expect_success 'prune --dry-run' '
-	(
-		cd one &&
-		git branch -m side2 side) &&
+	git -C one branch -m side2 side &&
+	test_when_finished "git -C one branch -m side side2" &&
 	(
 		cd test &&
 		git remote prune --dry-run origin >output &&
 		git rev-parse refs/remotes/origin/side2 &&
 		test_must_fail git rev-parse refs/remotes/origin/side &&
-	(
-		cd ../one &&
-		git branch -m side side2) &&
 		test_i18ncmp expect output
 	)
 '
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 06/29] t6036: fix broken "merge fails but has appropriate contents" tests
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (4 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 05/29] t5505: modernize and simplify hard-to-digest test Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  8:44   ` Elijah Newren
  2018-06-26  7:29 ` [PATCH 07/29] t7201: drop pointless "exit 0" at end of subshell Eric Sunshine
                   ` (25 subsequent siblings)
  31 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

These tests reference non-existent object "c" when they really mean to
be referencing "C", however, this error went unnoticed due to a broken
&&-chain later in the test. Fix these errors, as well as the broken
&&-chains behind which they hid.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t6036-recursive-corner-cases.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh
index b5621303d6..b32ff8e1db 100755
--- a/t/t6036-recursive-corner-cases.sh
+++ b/t/t6036-recursive-corner-cases.sh
@@ -506,10 +506,10 @@ test_expect_success 'merge of D & E2 fails but has appropriate contents' '
 		test_line_count = 2 out &&
 
 		git rev-parse >expect    \
-			B:a   E2:a/file  c:a/file   A:ignore-me &&
+			B:a   E2:a/file  C:a/file   A:ignore-me &&
 		git rev-parse   >actual   \
 			:2:a  :3:a/file  :1:a/file  :0:ignore-me &&
-		test_cmp expect actual
+		test_cmp expect actual &&
 
 		test_path_is_file a~HEAD
 	)
@@ -533,10 +533,10 @@ test_expect_success 'merge of E2 & D fails but has appropriate contents' '
 		test_line_count = 2 out &&
 
 		git rev-parse >expect    \
-			B:a   E2:a/file  c:a/file   A:ignore-me &&
+			B:a   E2:a/file  C:a/file   A:ignore-me &&
 		git rev-parse   >actual   \
 			:3:a  :2:a/file  :1:a/file  :0:ignore-me &&
-		test_cmp expect actual
+		test_cmp expect actual &&
 
 		test_path_is_file a~D^0
 	)
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 07/29] t7201: drop pointless "exit 0" at end of subshell
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (5 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 06/29] t6036: fix broken "merge fails but has appropriate contents" tests Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 08/29] t7400: fix broken "submodule add/reconfigure --force" test Eric Sunshine
                   ` (24 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

This test employs a for-loop inside a subshell and correctly aborts the
loop and fails the test overall (via "exit 1") if any iteration of the
for-loop fails. Otherwise, it exits the subshell with an explicit
"exit 0", presumably to indicate that all iterations of the for-loop
succeeded. The &&-chain is (perhaps deliberately) broken between the
for-loop and the "exit 0".

An upcoming change will teach --chain-lint to detect &&-chain breakage
inside subshells, thus the missing &&-chain link will run afoul of
--chain-lint. Rather than fixing the &&-chain breakage, instead just
drop the unnecessary "exit 0".

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t7201-co.sh | 1 -
 1 file changed, 1 deletion(-)

diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index ab9da61da3..8d8a63a24b 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -673,7 +673,6 @@ test_expect_success 'custom merge driver with checkout -m' '
 		do
 			grep $t arm || exit 1
 		done
-		exit 0
 	) &&
 
 	mv arm expect &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 08/29] t7400: fix broken "submodule add/reconfigure --force" test
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (6 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 07/29] t7201: drop pointless "exit 0" at end of subshell Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-27 18:04   ` Stefan Beller
  2018-06-26  7:29 ` [PATCH 09/29] t7810: use test_expect_code() instead of hand-rolled comparison Eric Sunshine
                   ` (23 subsequent siblings)
  31 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

This test has been dysfunctional since it was added by 619acfc78c
(submodule add: extend force flag to add existing repos, 2016-10-06),
however, two problems early in the test went unnoticed due to a broken
&&-chain later in the test.

First, it tries configuring the submodule with repository "bogus-url",
however, "git submodule add" insists that the repository be either an
absolute URL or a relative pathname requiring prefix "./" or "../" (this
is true even with --force), but "bogus-url" does not meet those
criteria, thus the command fails.

Second, it then tries configuring a submodule with a path which is
.gitignore'd, which is disallowed. This restriction can be overridden
with --force, but the test neglects to use that option.

Fix both problems, as well as the broken &&-chain behind which they hid.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t7400-submodule-basic.sh | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 812db137b8..401adaed32 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -171,12 +171,12 @@ test_expect_success 'submodule add to .gitignored path with --force' '
 test_expect_success 'submodule add to reconfigure existing submodule with --force' '
 	(
 		cd addtest-ignore &&
-		git submodule add --force bogus-url submod &&
-		git submodule add -b initial "$submodurl" submod-branch &&
-		test "bogus-url" = "$(git config -f .gitmodules submodule.submod.url)" &&
-		test "bogus-url" = "$(git config submodule.submod.url)" &&
+		git submodule add --force /bogus-url submod &&
+		git submodule add --force -b initial "$submodurl" submod-branch &&
+		test "/bogus-url" = "$(git config -f .gitmodules submodule.submod.url)" &&
+		test "/bogus-url" = "$(git config submodule.submod.url)" &&
 		# Restore the url
-		git submodule add --force "$submodurl" submod
+		git submodule add --force "$submodurl" submod &&
 		test "$submodurl" = "$(git config -f .gitmodules submodule.submod.url)" &&
 		test "$submodurl" = "$(git config submodule.submod.url)"
 	)
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 09/29] t7810: use test_expect_code() instead of hand-rolled comparison
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (7 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 08/29] t7400: fix broken "submodule add/reconfigure --force" test Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 10/29] t9001: fix broken "invoke hook" test Eric Sunshine
                   ` (22 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

This test manually checks the exit code of git-grep for a particular
value. In doing so, it breaks the &&-chain. An upcoming change will
teach --chain-lint to check the &&-chain inside subshells, so this
manual exit code handling will run afoul of the &&-chain check.
Therefore, replace the manual handling with test_expect_code() and a
normal &&-chain.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t7810-grep.sh | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 1797f632a3..fecee602c1 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -845,10 +845,9 @@ test_expect_success 'grep from a subdirectory to search wider area (1)' '
 test_expect_success 'grep from a subdirectory to search wider area (2)' '
 	mkdir -p s &&
 	(
-		cd s || exit 1
-		( git grep xxyyzz .. >out ; echo $? >status )
-		! test -s out &&
-		test 1 = $(cat status)
+		cd s &&
+		test_expect_code 1 git grep xxyyzz .. >out &&
+		! test -s out
 	)
 '
 
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 10/29] t9001: fix broken "invoke hook" test
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (8 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 09/29] t7810: use test_expect_code() instead of hand-rolled comparison Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26 17:07   ` Jonathan Tan
  2018-06-26  7:29 ` [PATCH 11/29] t9104: use "{...}" block around "||" expression rather than subshell Eric Sunshine
                   ` (21 subsequent siblings)
  31 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

This test has been dysfunctional since it was added by 6489660b4b
(send-email: support validate hook, 2017-05-12), however, the problem
went unnoticed due to a broken &&-chain late in the test.

The test wants to verify that a non-zero exit code from the
'sendemail-validate' hook causes git-send-email to abort with a
particular error message. A command which is expected to fail should be
run with 'test_must_fail', however, the tests neglects to do so.

Fix this problem, as well as the broken &&-chain behind which the
problem hid.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t9001-send-email.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index e80eacbb1b..776769fe0d 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -1966,11 +1966,11 @@ test_expect_success $PREREQ 'invoke hook' '
 
 		# Verify error message when a patch is rejected by the hook
 		sed -e "s/add master/x/" ../0001-add-master.patch >../another.patch &&
-		git send-email \
+		test_must_fail git send-email \
 			--from="Example <nobody@example.com>" \
 			--to=nobody@example.com \
 			--smtp-server="$(pwd)/../fake.sendmail" \
-			../another.patch 2>err
+			../another.patch 2>err &&
 		test_i18ngrep "rejected by sendemail-validate hook" err
 	)
 '
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 11/29] t9104: use "{...}" block around "||" expression rather than subshell
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (9 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 10/29] t9001: fix broken "invoke hook" test Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 12/29] t9401: drop unnecessary nested subshell Eric Sunshine
                   ` (20 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

This test uses "(... || svn ...)" as a shorthand for an if-then-else
statement. The subshell prevents it from breaking the top-level
&&-chain.

However, an upcoming change will teach --chain-lint to check the
&&-chain inside subshells. Although it takes special care to allow
"||" inside subshells, it only recognizes "(... || git ...)" and
"(... || test*), so the "||" in this test will trip up --chain-lint.

A test later in this same script employs the same "... || svn ..."
construct, however, it wraps it in a "{...}" block instead of a
subshell. Therefore, rather than adding "(... || svn ...)" as a yet
another --chain-lint special case, follow suit and make this test use
"{...}", as well.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t9104-git-svn-follow-parent.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 5e0ad19177..f9aa734d4e 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -53,10 +53,10 @@ test_expect_success 'init and fetch from one svn-remote' '
         '
 
 test_expect_success 'follow deleted parent' '
-        (svn_cmd cp -m "resurrecting trunk as junk" \
+	{ svn_cmd cp -m "resurrecting trunk as junk" \
                "$svnrepo"/trunk@2 "$svnrepo"/junk ||
          svn cp -m "resurrecting trunk as junk" \
-               -r2 "$svnrepo"/trunk "$svnrepo"/junk) &&
+		-r2 "$svnrepo"/trunk "$svnrepo"/junk; } &&
         git config --add svn-remote.svn.fetch \
           junk:refs/remotes/svn/junk &&
         git svn fetch -i svn/thunk &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 12/29] t9401: drop unnecessary nested subshell
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (10 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 11/29] t9104: use "{...}" block around "||" expression rather than subshell Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 13/29] t/lib-submodule-update: fix broken "replace submodule must-fail" test Eric Sunshine
                   ` (19 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

This test employs an unnecessary nested subshell:

    (cd foo &&
     statement1 &&
     (cd bar &&
      statement2))

An upcoming change will teach --chain-lint to check the &&-chain in
subshells. The check works by performing textual transformations on the
test to link the subshell body directly into the parent's &&-chain. It
employs heuristics to identify the extent of a subshell, however,
closing two subshells on a single line like this will fool it.

Rather than extending the heuristics even further for this one-off case,
just drop the pointless nested subshell.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t9401-git-cvsserver-crlf.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh
index 84787eee9a..8b8d7ac34a 100755
--- a/t/t9401-git-cvsserver-crlf.sh
+++ b/t/t9401-git-cvsserver-crlf.sh
@@ -288,9 +288,9 @@ test_expect_success 'add bin (guess)' '
 test_expect_success 'remove files (guess)' '
     (cd cvswork &&
     GIT_CONFIG="$git_config" cvs -Q rm -f subdir/file.h &&
-    (cd subdir &&
+    cd subdir &&
     GIT_CONFIG="$git_config" cvs -Q rm -f withCr.bin
-    )) &&
+    ) &&
     marked_as cvswork/subdir withCr.bin -kb &&
     marked_as cvswork/subdir file.h ""
 '
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 13/29] t/lib-submodule-update: fix broken "replace submodule must-fail" test
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (11 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 12/29] t9401: drop unnecessary nested subshell Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-27 18:30   ` [PATCH] t/lib-submodule-update: fix absorbing test Stefan Beller
  2018-06-26  7:29 ` [PATCH 14/29] t: drop subshell with missing &&-chain in favor of simpler construct Eric Sunshine
                   ` (18 subsequent siblings)
  31 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

This test has been dysfunctional since it was added by 259f3ee296
(lib-submodule-update.sh: define tests for recursing into submodules,
2017-03-14), however, problems went unnoticed due to a broken &&-chain
toward the end of the test.

The test wants to verify that replacing a submodule containing a .git
directory must fail. All other "must fail" tests in this script invoke
the supplied command as 'test_must_fail', however, this test neglects to
do so.

To make matters worse, the command actually succeeds even though it's
not supposed to. Presumably, this is a "known breakage", which means
that the entire test should be marked 'test_expect_failure', however, it
is instead marked 'test_expect_success'.

Fix both problems, as well as the broken &&-chain behind which these
problems hid.

While at it, fix broken &&-chains in a couple neighboring tests.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/lib-submodule-update.sh | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
index 1f38a85371..8a2edee1cb 100755
--- a/t/lib-submodule-update.sh
+++ b/t/lib-submodule-update.sh
@@ -755,7 +755,7 @@ test_submodule_recursing_with_args_common() {
 			: >sub1/untrackedfile &&
 			test_must_fail $command replace_sub1_with_file &&
 			test_superproject_content origin/add_sub1 &&
-			test_submodule_content sub1 origin/add_sub1
+			test_submodule_content sub1 origin/add_sub1 &&
 			test -f sub1/untracked_file
 		)
 	'
@@ -842,7 +842,7 @@ test_submodule_switch_recursing_with_args () {
 			cd submodule_update &&
 			git branch -t add_sub1 origin/add_sub1 &&
 			: >sub1 &&
-			echo sub1 >.git/info/exclude
+			echo sub1 >.git/info/exclude &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -959,7 +959,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		)
 	'
 	# ... absorbing a .git directory.
-	test_expect_success "$command: replace submodule containing a .git directory with a directory must fail" '
+	test_expect_failure "$command: replace submodule containing a .git directory with a directory must fail" '
 		prolog &&
 		reset_work_tree_to_interested add_sub1 &&
 		(
@@ -967,9 +967,9 @@ test_submodule_forced_switch_recursing_with_args () {
 			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			replace_gitfile_with_git_dir sub1 &&
 			rm -rf .git/modules/sub1 &&
-			$command replace_sub1_with_directory &&
+			test_must_fail $command replace_sub1_with_directory &&
 			test_superproject_content origin/replace_sub1_with_directory &&
-			test_submodule_content sub1 origin/modify_sub1
+			test_submodule_content sub1 origin/modify_sub1 &&
 			test_git_directory_exists sub1
 		)
 	'
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 14/29] t: drop subshell with missing &&-chain in favor of simpler construct
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (12 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 13/29] t/lib-submodule-update: fix broken "replace submodule must-fail" test Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26 19:31   ` Junio C Hamano
  2018-06-26  7:29 ` [PATCH 15/29] t: drop unnecessary terminating semicolons in subshell Eric Sunshine
                   ` (17 subsequent siblings)
  31 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

These tests employ a noisy subshell (with missing &&-chain) to feed
input into Git commands:

    (echo a; echo b; echo c) | git some-command ...

Drop the subshell in favor of a simple 'printf':

    printf "%s\n" a b c | git some-command ...

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t0090-cache-tree.sh         |  2 +-
 t/t2016-checkout-patch.sh     | 24 ++++++++++----------
 t/t3404-rebase-interactive.sh |  6 ++---
 t/t3701-add-interactive.sh    | 16 +++++++-------
 t/t3904-stash-patch.sh        |  8 +++----
 t/t7105-reset-patch.sh        | 12 +++++-----
 t/t7301-clean-interactive.sh  | 41 +++++++++++++++++------------------
 t/t7501-commit.sh             |  4 ++--
 t/t7610-mergetool.sh          |  8 +++----
 9 files changed, 60 insertions(+), 61 deletions(-)

diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh
index 0c61268fd2..f86cc76c9d 100755
--- a/t/t0090-cache-tree.sh
+++ b/t/t0090-cache-tree.sh
@@ -156,7 +156,7 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi
 		return 44;
 	}
 	EOT
-	(echo p; echo 1; echo; echo s; echo n; echo y; echo q) |
+	printf "%s\n" p 1 "" s n y q |
 	git commit --interactive -m foo &&
 	test_cache_tree
 '
diff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh
index 9cd0ac4ba3..4dcad0f4a2 100755
--- a/t/t2016-checkout-patch.sh
+++ b/t/t2016-checkout-patch.sh
@@ -20,33 +20,33 @@ test_expect_success PERL 'setup' '
 
 test_expect_success PERL 'saying "n" does nothing' '
 	set_and_save_state dir/foo work head &&
-	(echo n; echo n) | git checkout -p &&
+	printf "%s\n" n n | git checkout -p &&
 	verify_saved_state bar &&
 	verify_saved_state dir/foo
 '
 
 test_expect_success PERL 'git checkout -p' '
-	(echo n; echo y) | git checkout -p &&
+	printf "%s\n" n y | git checkout -p &&
 	verify_saved_state bar &&
 	verify_state dir/foo head head
 '
 
 test_expect_success PERL 'git checkout -p with staged changes' '
 	set_state dir/foo work index &&
-	(echo n; echo y) | git checkout -p &&
+	printf "%s\n" n y | git checkout -p &&
 	verify_saved_state bar &&
 	verify_state dir/foo index index
 '
 
 test_expect_success PERL 'git checkout -p HEAD with NO staged changes: abort' '
 	set_and_save_state dir/foo work head &&
-	(echo n; echo y; echo n) | git checkout -p HEAD &&
+	printf "%s\n" n y n | git checkout -p HEAD &&
 	verify_saved_state bar &&
 	verify_saved_state dir/foo
 '
 
 test_expect_success PERL 'git checkout -p HEAD with NO staged changes: apply' '
-	(echo n; echo y; echo y) | git checkout -p HEAD &&
+	printf "%s\n" n y y | git checkout -p HEAD &&
 	verify_saved_state bar &&
 	verify_state dir/foo head head
 '
@@ -54,14 +54,14 @@ test_expect_success PERL 'git checkout -p HEAD with NO staged changes: apply' '
 test_expect_success PERL 'git checkout -p HEAD with change already staged' '
 	set_state dir/foo index index &&
 	# the third n is to get out in case it mistakenly does not apply
-	(echo n; echo y; echo n) | git checkout -p HEAD &&
+	printf "%s\n" n y n | git checkout -p HEAD &&
 	verify_saved_state bar &&
 	verify_state dir/foo head head
 '
 
 test_expect_success PERL 'git checkout -p HEAD^' '
 	# the third n is to get out in case it mistakenly does not apply
-	(echo n; echo y; echo n) | git checkout -p HEAD^ &&
+	printf "%s\n" n y n | git checkout -p HEAD^ &&
 	verify_saved_state bar &&
 	verify_state dir/foo parent parent
 '
@@ -69,7 +69,7 @@ test_expect_success PERL 'git checkout -p HEAD^' '
 test_expect_success PERL 'git checkout -p handles deletion' '
 	set_state dir/foo work index &&
 	rm dir/foo &&
-	(echo n; echo y) | git checkout -p &&
+	printf "%s\n" n y | git checkout -p &&
 	verify_saved_state bar &&
 	verify_state dir/foo index index
 '
@@ -81,21 +81,21 @@ test_expect_success PERL 'git checkout -p handles deletion' '
 
 test_expect_success PERL 'path limiting works: dir' '
 	set_state dir/foo work head &&
-	(echo y; echo n) | git checkout -p dir &&
+	printf "%s\n" y n | git checkout -p dir &&
 	verify_saved_state bar &&
 	verify_state dir/foo head head
 '
 
 test_expect_success PERL 'path limiting works: -- dir' '
 	set_state dir/foo work head &&
-	(echo y; echo n) | git checkout -p -- dir &&
+	printf "%s\n" y n | git checkout -p -- dir &&
 	verify_saved_state bar &&
 	verify_state dir/foo head head
 '
 
 test_expect_success PERL 'path limiting works: HEAD^ -- dir' '
 	# the third n is to get out in case it mistakenly does not apply
-	(echo y; echo n; echo n) | git checkout -p HEAD^ -- dir &&
+	printf "%s\n" y n n | git checkout -p HEAD^ -- dir &&
 	verify_saved_state bar &&
 	verify_state dir/foo parent parent
 '
@@ -103,7 +103,7 @@ test_expect_success PERL 'path limiting works: HEAD^ -- dir' '
 test_expect_success PERL 'path limiting works: foo inside dir' '
 	set_state dir/foo work head &&
 	# the third n is to get out in case it mistakenly does not apply
-	(echo y; echo n; echo n) | (cd dir && git checkout -p foo) &&
+	printf "%s\n" y n n | (cd dir && git checkout -p foo) &&
 	verify_saved_state bar &&
 	verify_state dir/foo head head
 '
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 352a52e59d..0dea186289 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -509,7 +509,7 @@ test_expect_success 'interrupted squash works as expected' '
 	one=$(git rev-parse HEAD~3) &&
 	set_fake_editor &&
 	test_must_fail env FAKE_LINES="1 squash 3 2" git rebase -i HEAD~3 &&
-	(echo one; echo two; echo four) > conflict &&
+	printf "%s\n" one two four > conflict &&
 	git add conflict &&
 	test_must_fail git rebase --continue &&
 	echo resolved > conflict &&
@@ -523,10 +523,10 @@ test_expect_success 'interrupted squash works as expected (case 2)' '
 	one=$(git rev-parse HEAD~3) &&
 	set_fake_editor &&
 	test_must_fail env FAKE_LINES="3 squash 1 2" git rebase -i HEAD~3 &&
-	(echo one; echo four) > conflict &&
+	printf "%s\n" one four > conflict &&
 	git add conflict &&
 	test_must_fail git rebase --continue &&
-	(echo one; echo two; echo four) > conflict &&
+	printf "%s\n" one two four > conflict &&
 	git add conflict &&
 	test_must_fail git rebase --continue &&
 	echo resolved > conflict &&
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index b170fb02b8..7eec7bb3bb 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -46,13 +46,13 @@ test_expect_success 'setup expected' '
 '
 
 test_expect_success 'diff works (initial)' '
-	(echo d; echo 1) | git add -i >output &&
+	printf "%s\n" d 1 | git add -i >output &&
 	sed -ne "/new file/,/content/p" <output >diff &&
 	diff_cmp expected diff
 '
 test_expect_success 'revert works (initial)' '
 	git add file &&
-	(echo r; echo 1) | git add -i &&
+	printf "%s\n" r 1 | git add -i &&
 	git ls-files >output &&
 	! grep . output
 '
@@ -83,13 +83,13 @@ test_expect_success 'setup expected' '
 '
 
 test_expect_success 'diff works (commit)' '
-	(echo d; echo 1) | git add -i >output &&
+	printf "%s\n" d 1 | git add -i >output &&
 	sed -ne "/^index/,/content/p" <output >diff &&
 	diff_cmp expected diff
 '
 test_expect_success 'revert works (commit)' '
 	git add file &&
-	(echo r; echo 1) | git add -i &&
+	printf "%s\n" r 1 | git add -i &&
 	git add -i </dev/null >output &&
 	grep "unchanged *+3/-0 file" output
 '
@@ -102,7 +102,7 @@ test_expect_success 'setup expected' '
 
 test_expect_success 'dummy edit works' '
 	test_set_editor : &&
-	(echo e; echo a) | git add -p &&
+	printf "%s\n" e a | git add -p &&
 	git diff > diff &&
 	diff_cmp expected diff
 '
@@ -127,7 +127,7 @@ test_expect_success 'setup fake editor' '
 
 test_expect_success 'bad edit rejected' '
 	git reset &&
-	(echo e; echo n; echo d) | git add -p >output &&
+	printf "%s\n" e n d | git add -p >output &&
 	grep "hunk does not apply" output
 '
 
@@ -140,7 +140,7 @@ test_expect_success 'setup patch' '
 
 test_expect_success 'garbage edit rejected' '
 	git reset &&
-	(echo e; echo n; echo d) | git add -p >output &&
+	printf "%s\n" e n d | git add -p >output &&
 	grep "hunk does not apply" output
 '
 
@@ -170,7 +170,7 @@ test_expect_success 'setup expected' '
 '
 
 test_expect_success 'real edit works' '
-	(echo e; echo n; echo d) | git add -p &&
+	printf "%s\n" e n d | git add -p &&
 	git diff >output &&
 	diff_cmp expected output
 '
diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh
index 83744f8c93..f32e272786 100755
--- a/t/t3904-stash-patch.sh
+++ b/t/t3904-stash-patch.sh
@@ -29,14 +29,14 @@ test_expect_success 'setup' '
 test_expect_success 'saying "n" does nothing' '
 	set_state HEAD HEADfile_work HEADfile_index &&
 	set_state dir/foo work index &&
-	(echo n; echo n; echo n) | test_must_fail git stash save -p &&
+	printf "%s\n" n n n | test_must_fail git stash save -p &&
 	verify_state HEAD HEADfile_work HEADfile_index &&
 	verify_saved_state bar &&
 	verify_state dir/foo work index
 '
 
 test_expect_success 'git stash -p' '
-	(echo y; echo n; echo y) | git stash save -p &&
+	printf "%s\n" y n y | git stash save -p &&
 	verify_state HEAD committed HEADfile_index &&
 	verify_saved_state bar &&
 	verify_state dir/foo head index &&
@@ -51,7 +51,7 @@ test_expect_success 'git stash -p --no-keep-index' '
 	set_state HEAD HEADfile_work HEADfile_index &&
 	set_state bar bar_work bar_index &&
 	set_state dir/foo work index &&
-	(echo y; echo n; echo y) | git stash save -p --no-keep-index &&
+	printf "%s\n" y n y | git stash save -p --no-keep-index &&
 	verify_state HEAD committed committed &&
 	verify_state bar bar_work dummy &&
 	verify_state dir/foo head head &&
@@ -66,7 +66,7 @@ test_expect_success 'git stash --no-keep-index -p' '
 	set_state HEAD HEADfile_work HEADfile_index &&
 	set_state bar bar_work bar_index &&
 	set_state dir/foo work index &&
-	(echo y; echo n; echo y) | git stash save --no-keep-index -p &&
+	printf "%s\n" y n y | git stash save --no-keep-index -p &&
 	verify_state HEAD committed committed &&
 	verify_state dir/foo head head &&
 	verify_state bar bar_work dummy &&
diff --git a/t/t7105-reset-patch.sh b/t/t7105-reset-patch.sh
index 98b7d7b969..d907b6dd18 100755
--- a/t/t7105-reset-patch.sh
+++ b/t/t7105-reset-patch.sh
@@ -19,20 +19,20 @@ test_expect_success PERL 'setup' '
 
 test_expect_success PERL 'saying "n" does nothing' '
 	set_and_save_state dir/foo work work &&
-	(echo n; echo n) | git reset -p &&
+	printf "%s\n" n n | git reset -p &&
 	verify_saved_state dir/foo &&
 	verify_saved_state bar
 '
 
 test_expect_success PERL 'git reset -p' '
-	(echo n; echo y) | git reset -p >output &&
+	printf "%s\n" n y | git reset -p >output &&
 	verify_state dir/foo work head &&
 	verify_saved_state bar &&
 	test_i18ngrep "Unstage" output
 '
 
 test_expect_success PERL 'git reset -p HEAD^' '
-	(echo n; echo y) | git reset -p HEAD^ >output &&
+	printf "%s\n" n y | git reset -p HEAD^ >output &&
 	verify_state dir/foo work parent &&
 	verify_saved_state bar &&
 	test_i18ngrep "Apply" output
@@ -45,20 +45,20 @@ test_expect_success PERL 'git reset -p HEAD^' '
 
 test_expect_success PERL 'git reset -p dir' '
 	set_state dir/foo work work &&
-	(echo y; echo n) | git reset -p dir &&
+	printf "%s\n" y n | git reset -p dir &&
 	verify_state dir/foo work head &&
 	verify_saved_state bar
 '
 
 test_expect_success PERL 'git reset -p -- foo (inside dir)' '
 	set_state dir/foo work work &&
-	(echo y; echo n) | (cd dir && git reset -p -- foo) &&
+	printf "%s\n" y n | (cd dir && git reset -p -- foo) &&
 	verify_state dir/foo work head &&
 	verify_saved_state bar
 '
 
 test_expect_success PERL 'git reset -p HEAD^ -- dir' '
-	(echo y; echo n) | git reset -p HEAD^ -- dir &&
+	printf "%s\n" y n | git reset -p HEAD^ -- dir &&
 	verify_state dir/foo work parent &&
 	verify_saved_state bar
 '
diff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh
index 1bf9789c8a..2bc8526f59 100755
--- a/t/t7301-clean-interactive.sh
+++ b/t/t7301-clean-interactive.sh
@@ -107,7 +107,7 @@ test_expect_success 'git clean -id (filter all)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo f; echo "*"; echo; echo c) | \
+	printf "%s\n" f "*" "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -129,7 +129,7 @@ test_expect_success 'git clean -id (filter patterns)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo f; echo "part3.* *.out"; echo; echo c) | \
+	printf "%s\n" f "part3.* *.out" "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -151,7 +151,7 @@ test_expect_success 'git clean -id (filter patterns 2)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo f; echo "* !*.out"; echo; echo c) | \
+	printf "%s\n" f "* !*.out" "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -173,7 +173,7 @@ test_expect_success 'git clean -id (select - all)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo s; echo "*"; echo; echo c) | \
+	printf "%s\n" s "*" "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -195,7 +195,7 @@ test_expect_success 'git clean -id (select - none)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo s; echo; echo c) | \
+	printf "%s\n" s "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -217,7 +217,7 @@ test_expect_success 'git clean -id (select - number)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo s; echo 3; echo; echo c) | \
+	printf "%s\n" s 3 "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -239,7 +239,7 @@ test_expect_success 'git clean -id (select - number 2)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo s; echo 2 3; echo 5; echo; echo c) | \
+	printf "%s\n" s "2 3" 5 "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -261,7 +261,7 @@ test_expect_success 'git clean -id (select - number 3)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo s; echo 3,4 5; echo; echo c) | \
+	printf "%s\n" s "3,4 5" "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -282,7 +282,7 @@ test_expect_success 'git clean -id (select - filenames)' '
 
 	mkdir -p build docs &&
 	touch a.out foo.txt bar.txt baz.txt &&
-	(echo s; echo a.out fo ba bar; echo; echo c) | \
+	printf "%s\n" s "a.out fo ba bar" "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test ! -f a.out &&
@@ -298,7 +298,7 @@ test_expect_success 'git clean -id (select - range)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo s; echo 1,3-4; echo 2; echo; echo c) | \
+	printf "%s\n" s "1,3-4" 2 "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -320,7 +320,7 @@ test_expect_success 'git clean -id (select - range 2)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo s; echo 4- 1; echo; echo c) | \
+	printf "%s\n" s "4- 1" "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -342,7 +342,7 @@ test_expect_success 'git clean -id (inverse select)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo s; echo "*"; echo -5- 1 -2; echo; echo c) | \
+	printf "%s\n" s "*" "-5- 1 -2" "" c |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -364,7 +364,7 @@ test_expect_success 'git clean -id (ask)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo a; echo Y; echo y; echo no; echo yes; echo bad; echo) | \
+	printf "%s\n" a Y y no yes bad "" |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -386,7 +386,7 @@ test_expect_success 'git clean -id (ask - Ctrl+D)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(echo a; echo Y; echo no; echo yes; echo "\04") | \
+	printf "%s\n" a Y no yes "\04" |
 	git clean -id &&
 	test -f Makefile &&
 	test -f README &&
@@ -408,8 +408,8 @@ test_expect_success 'git clean -id with prefix and path (filter)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(cd build/ && \
-	 (echo f; echo "docs"; echo "*.h"; echo ; echo c) | \
+	(cd build/ &&
+	 printf "%s\n" f docs "*.h" "" c |
 	 git clean -id ..) &&
 	test -f Makefile &&
 	test -f README &&
@@ -431,9 +431,8 @@ test_expect_success 'git clean -id with prefix and path (select by name)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(cd build/ && \
-	 (echo s; echo "../docs/"; echo "../src/part3.c"; \
-	  echo "../src/part4.c";  echo; echo c) | \
+	(cd build/ &&
+	 printf "%s\n" s ../docs/ ../src/part3.c ../src/part4.c "" c |
 	 git clean -id ..) &&
 	test -f Makefile &&
 	test -f README &&
@@ -455,8 +454,8 @@ test_expect_success 'git clean -id with prefix and path (ask)' '
 	mkdir -p build docs &&
 	touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
 	docs/manual.txt obj.o build/lib.so &&
-	(cd build/ && \
-	 (echo a; echo Y; echo y; echo no; echo yes; echo bad; echo) | \
+	(cd build/ &&
+	 printf "%s\n" a Y y no yes bad "" |
 	 git clean -id ..) &&
 	test -f Makefile &&
 	test -f README &&
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index 9dbbd01fc0..589b6cea23 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -47,7 +47,7 @@ test_expect_success 'paths and -a do not mix' '
 test_expect_success PERL 'can use paths with --interactive' '
 	echo bong-o-bong >file &&
 	# 2: update, 1:st path, that is all, 7: quit
-	( echo 2; echo 1; echo; echo 7 ) |
+	printf "%s\n" 2 1 "" 7 |
 	git commit -m foo --interactive file &&
 	git reset --hard HEAD^
 '
@@ -293,7 +293,7 @@ test_expect_success PERL 'interactive add' '
 test_expect_success PERL "commit --interactive doesn't change index if editor aborts" '
 	echo zoo >file &&
 	test_must_fail git diff --exit-code >diff1 &&
-	(echo u ; echo "*" ; echo q) |
+	printf "%s\n" u "*" q |
 	(
 		EDITOR=: &&
 		export EDITOR &&
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
index 1a430b9c40..a66d038083 100755
--- a/t/t7610-mergetool.sh
+++ b/t/t7610-mergetool.sh
@@ -57,18 +57,18 @@ test_expect_success 'setup' '
 
 	git checkout -b delete-base branch1 &&
 	mkdir -p a/a &&
-	(echo one; echo two; echo 3; echo 4) >a/a/file.txt &&
+	printf "%s\n" one two 3 4 >a/a/file.txt &&
 	git add a/a/file.txt &&
 	git commit -m"base file" &&
 	git checkout -b move-to-b delete-base &&
 	mkdir -p b/b &&
 	git mv a/a/file.txt b/b/file.txt &&
-	(echo one; echo two; echo 4) >b/b/file.txt &&
+	printf "%s\n" one two 4 >b/b/file.txt &&
 	git commit -a -m"move to b" &&
 	git checkout -b move-to-c delete-base &&
 	mkdir -p c/c &&
 	git mv a/a/file.txt c/c/file.txt &&
-	(echo one; echo two; echo 3) >c/c/file.txt &&
+	printf "%s\n" one two 3 >c/c/file.txt &&
 	git commit -a -m"move to c" &&
 
 	git checkout -b stash1 master &&
@@ -349,7 +349,7 @@ test_expect_success 'mergetool keeps tempfiles when aborting delete/delete' '
 	git checkout -b test$test_count move-to-c &&
 	test_config mergetool.keepTemporaries true &&
 	test_must_fail git merge move-to-b &&
-	! (echo a; echo n) | git mergetool a/a/file.txt &&
+	! printf "%s\n" a n | git mergetool a/a/file.txt &&
 	test -d a/a &&
 	cat >expect <<-\EOF &&
 	file_BASE_.txt
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 15/29] t: drop unnecessary terminating semicolons in subshell
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (13 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 14/29] t: drop subshell with missing &&-chain in favor of simpler construct Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 16/29] t: use test_might_fail() instead of manipulating exit code manually Eric Sunshine
                   ` (16 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

An upcoming change will teach --chain-lint to check the &&-chain inside
subshells. The semicolons after the final commands in these subshells
will trip up --chain-lint since they break the &&-chain. Since those
semicolons are unnecessary, just drop them.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t3102-ls-tree-wildcards.sh | 2 +-
 t/t4010-diff-pathspec.sh     | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index e804377f1c..1e16c6b8ea 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -23,7 +23,7 @@ test_expect_success 'ls-tree outside prefix' '
 	cat >expect <<-EOF &&
 	100644 blob $EMPTY_BLOB	../a[a]/three
 	EOF
-	( cd aa && git ls-tree -r HEAD "../a[a]"; ) >actual &&
+	( cd aa && git ls-tree -r HEAD "../a[a]" ) >actual &&
 	test_cmp expect actual
 '
 
diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh
index 35b35a81c8..b7f25071cf 100755
--- a/t/t4010-diff-pathspec.sh
+++ b/t/t4010-diff-pathspec.sh
@@ -111,10 +111,10 @@ test_expect_success 'diff-tree -r with wildcard' '
 test_expect_success 'setup submodules' '
 	test_tick &&
 	git init submod &&
-	( cd submod && test_commit first; ) &&
+	( cd submod && test_commit first ) &&
 	git add submod &&
 	git commit -m first &&
-	( cd submod && test_commit second; ) &&
+	( cd submod && test_commit second ) &&
 	git add submod &&
 	git commit -m second
 '
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 16/29] t: use test_might_fail() instead of manipulating exit code manually
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (14 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 15/29] t: drop unnecessary terminating semicolons in subshell Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 17/29] t: use test_must_fail() instead of checking " Eric Sunshine
                   ` (15 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

These tests manually coerce the exit code of invoked commands to
"success" when they don't care if the command succeeds or fails since
failure of those commands should not cause the test to fail overall.
Such manual management predates the invention of test_might_fail().

An upcoming change will teach --chain-lint to check the &&-chain inside
subshells. This sort of manual exit code manipulation will trip up
--chain-lint due to the intentional break in the &&-chain. Therefore,
replace manual exit code management with test_might_fail() and a normal
&&-chain.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t1507-rev-parse-upstream.sh | 6 +++---
 t/t1700-split-index.sh        | 2 +-
 t/t4012-diff-binary.sh        | 6 ++----
 t/t5400-send-pack.sh          | 4 ++--
 4 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh
index 93c77eac45..349f6e10af 100755
--- a/t/t1507-rev-parse-upstream.sh
+++ b/t/t1507-rev-parse-upstream.sh
@@ -123,9 +123,9 @@ test_expect_success 'checkout -b new my-side@{u} forks from the same' '
 
 test_expect_success 'merge my-side@{u} records the correct name' '
 (
-	cd clone || exit
-	git checkout master || exit
-	git branch -D new ;# can fail but is ok
+	cd clone &&
+	git checkout master &&
+	test_might_fail git branch -D new &&
 	git branch -t new my-side@{u} &&
 	git merge -s ours new@{u} &&
 	git show -s --pretty=tformat:%s >actual &&
diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
index 1e81b33b2e..39133bcbc8 100755
--- a/t/t1700-split-index.sh
+++ b/t/t1700-split-index.sh
@@ -435,7 +435,7 @@ test_expect_success 'writing split index with null sha1 does not write cache tre
 	commit=$(git commit-tree $tree -p HEAD <msg) &&
 	git update-ref HEAD "$commit" &&
 	GIT_ALLOW_NULL_SHA1=1 git reset --hard &&
-	(test-tool dump-cache-tree >cache-tree.out || true) &&
+	test_might_fail test-tool dump-cache-tree >cache-tree.out &&
 	test_line_count = 0 cache-tree.out
 '
 
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index 0a8af76aab..6579c81216 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -102,10 +102,8 @@ test_expect_success 'apply binary patch' '
 
 test_expect_success 'diff --no-index with binary creation' '
 	echo Q | q_to_nul >binary &&
-	(: hide error code from diff, which just indicates differences
-	 git diff --binary --no-index /dev/null binary >current ||
-	 true
-	) &&
+	# hide error code from diff, which just indicates differences
+	test_might_fail git diff --binary --no-index /dev/null binary >current &&
 	rm binary &&
 	git apply --binary <current &&
 	echo Q >expected &&
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 911eae1bf7..f1932ea431 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -86,7 +86,7 @@ test_expect_success 'push can be used to delete a ref' '
 test_expect_success 'refuse deleting push with denyDeletes' '
 	(
 	    cd victim &&
-	    ( git branch -D extra || : ) &&
+	    test_might_fail git branch -D extra &&
 	    git config receive.denyDeletes true &&
 	    git branch extra master
 	) &&
@@ -119,7 +119,7 @@ test_expect_success 'override denyDeletes with git -c receive-pack' '
 test_expect_success 'denyNonFastforwards trumps --force' '
 	(
 	    cd victim &&
-	    ( git branch -D extra || : ) &&
+	    test_might_fail git branch -D extra &&
 	    git config receive.denyNonFastforwards true
 	) &&
 	victim_orig=$(cd victim && git rev-parse --verify master) &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 17/29] t: use test_must_fail() instead of checking exit code manually
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (15 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 16/29] t: use test_might_fail() instead of manipulating exit code manually Eric Sunshine
@ 2018-06-26  7:29 ` " Eric Sunshine
  2018-06-26  7:59   ` Luke Diamand
  2018-06-26  8:58   ` Elijah Newren
  2018-06-26  7:29 ` [PATCH 18/29] t0000-t0999: fix broken &&-chains in subshells Eric Sunshine
                   ` (14 subsequent siblings)
  31 siblings, 2 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

These tests intentionally break the &&-chain to manually check the exit
code of invoked commands which they expect to fail, and invert that
local expected failure into a successful exit code for the test overall.
Such manual exit code manipulation predates the invention of
test_must_fail().

An upcoming change will teach --chain-lint to check the &&-chain inside
subshells. This sort of manual exit code checking will trip up
--chain-lint due to the intentional break in the &&-chain. Therefore,
replace the manual exit code management with test_must_fail() and a
normal &&-chain.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t5405-send-pack-rewind.sh |  3 +--
 t/t9814-git-p4-rename.sh    | 16 ++--------------
 2 files changed, 3 insertions(+), 16 deletions(-)

diff --git a/t/t5405-send-pack-rewind.sh b/t/t5405-send-pack-rewind.sh
index 4bda18a662..235fb7686a 100755
--- a/t/t5405-send-pack-rewind.sh
+++ b/t/t5405-send-pack-rewind.sh
@@ -25,8 +25,7 @@ test_expect_success 'non forced push should die not segfault' '
 
 	(
 		cd another &&
-		git push .. master:master
-		test $? = 1
+		test_must_fail git push .. master:master
 	)
 
 '
diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh
index e7e0268e98..80aac5ab16 100755
--- a/t/t9814-git-p4-rename.sh
+++ b/t/t9814-git-p4-rename.sh
@@ -12,20 +12,8 @@ test_expect_success 'start p4d' '
 test_expect_success 'p4 help unknown returns 1' '
 	(
 		cd "$cli" &&
-		(
-			p4 help client >errs 2>&1
-			echo $? >retval
-		)
-		echo 0 >expected &&
-		test_cmp expected retval &&
-		rm retval &&
-		(
-			p4 help nosuchcommand >errs 2>&1
-			echo $? >retval
-		)
-		echo 1 >expected &&
-		test_cmp expected retval &&
-		rm retval
+		p4 help client &&
+		test_must_fail p4 help nosuchcommand
 	)
 '
 
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 18/29] t0000-t0999: fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (16 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 17/29] t: use test_must_fail() instead of checking " Eric Sunshine
@ 2018-06-26  7:29 ` Eric Sunshine
  2018-06-26  7:29 ` [PATCH 19/29] t1000-t1999: " Eric Sunshine
                   ` (13 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t0000-basic.sh      |  2 +-
 t/t0003-attributes.sh | 24 ++++++++++++------------
 t/t0021-conversion.sh |  4 ++--
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index af61d083b4..34859fe4a5 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -1081,7 +1081,7 @@ test_expect_success 'very long name in the index handled sanely' '
 	(
 		git ls-files -s path4 |
 		sed -e "s/	.*/	/" |
-		tr -d "\012"
+		tr -d "\012" &&
 		echo "$a"
 	) | git update-index --index-info &&
 	len=$(git ls-files "a*" | wc -c) &&
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index f19ae4f8cc..5c37c2e1f8 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -34,15 +34,15 @@ test_expect_success 'open-quoted pathname' '
 test_expect_success 'setup' '
 	mkdir -p a/b/d a/c b &&
 	(
-		echo "[attr]notest !test"
-		echo "\" d \"	test=d"
-		echo " e	test=e"
-		echo " e\"	test=e"
-		echo "f	test=f"
-		echo "a/i test=a/i"
-		echo "onoff test -test"
-		echo "offon -test test"
-		echo "no notest"
+		echo "[attr]notest !test" &&
+		echo "\" d \"	test=d" &&
+		echo " e	test=e" &&
+		echo " e\"	test=e" &&
+		echo "f	test=f" &&
+		echo "a/i test=a/i" &&
+		echo "onoff test -test" &&
+		echo "offon -test test" &&
+		echo "no notest" &&
 		echo "A/e/F test=A/e/F"
 	) >.gitattributes &&
 	(
@@ -51,7 +51,7 @@ test_expect_success 'setup' '
 	) >a/.gitattributes &&
 	(
 		echo "h test=a/b/h" &&
-		echo "d/* test=a/b/d/*"
+		echo "d/* test=a/b/d/*" &&
 		echo "d/yes notest"
 	) >a/b/.gitattributes &&
 	(
@@ -287,7 +287,7 @@ test_expect_success 'bare repository: check that .gitattribute is ignored' '
 	(
 		cd bare.git &&
 		(
-			echo "f	test=f"
+			echo "f	test=f" &&
 			echo "a/i test=a/i"
 		) >.gitattributes &&
 		attr_check f unspecified &&
@@ -312,7 +312,7 @@ test_expect_success 'bare repository: test info/attributes' '
 	(
 		cd bare.git &&
 		(
-			echo "f	test=f"
+			echo "f	test=f" &&
 			echo "a/i test=a/i"
 		) >info/attributes &&
 		attr_check f f &&
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 9479a4aaab..6a213608cc 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -785,7 +785,7 @@ test_expect_success PERL 'missing file in delayed checkout' '
 		cd repo &&
 		git init &&
 		echo "*.a filter=bug" >.gitattributes &&
-		cp "$TEST_ROOT/test.o" missing-delay.a
+		cp "$TEST_ROOT/test.o" missing-delay.a &&
 		git add . &&
 		git commit -m "test commit"
 	) &&
@@ -807,7 +807,7 @@ test_expect_success PERL 'invalid file in delayed checkout' '
 		git init &&
 		echo "*.a filter=bug" >.gitattributes &&
 		cp "$TEST_ROOT/test.o" invalid-delay.a &&
-		cp "$TEST_ROOT/test.o" unfiltered
+		cp "$TEST_ROOT/test.o" unfiltered &&
 		git add . &&
 		git commit -m "test commit"
 	) &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 19/29] t1000-t1999: fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (17 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 18/29] t0000-t0999: fix broken &&-chains in subshells Eric Sunshine
@ 2018-06-26  7:29 ` " Eric Sunshine
  2018-06-26  7:29 ` [PATCH 20/29] t2000-t2999: " Eric Sunshine
                   ` (12 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t1004-read-tree-m-u-wf.sh         |  8 ++++----
 t/t1005-read-tree-reset.sh          | 10 +++++-----
 t/t1008-read-tree-overlay.sh        |  2 +-
 t/t1020-subdirectory.sh             |  2 +-
 t/t1050-large.sh                    |  6 +++---
 t/t1411-reflog-show.sh              |  6 +++---
 t/t1512-rev-parse-disambiguation.sh |  6 +++---
 7 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh
index c7ce5d8bb5..a479549fb6 100755
--- a/t/t1004-read-tree-m-u-wf.sh
+++ b/t/t1004-read-tree-m-u-wf.sh
@@ -212,10 +212,10 @@ test_expect_success 'D/F' '
 	read_tree_u_must_succeed -m -u branch-point side-b side-a &&
 	git ls-files -u >actual &&
 	(
-		a=$(git rev-parse branch-point:subdir/file2)
-		b=$(git rev-parse side-a:subdir/file2/another)
-		echo "100644 $a 1	subdir/file2"
-		echo "100644 $a 2	subdir/file2"
+		a=$(git rev-parse branch-point:subdir/file2) &&
+		b=$(git rev-parse side-a:subdir/file2/another) &&
+		echo "100644 $a 1	subdir/file2" &&
+		echo "100644 $a 2	subdir/file2" &&
 		echo "100644 $b 3	subdir/file2/another"
 	) >expect &&
 	test_cmp expect actual
diff --git a/t/t1005-read-tree-reset.sh b/t/t1005-read-tree-reset.sh
index 074568500a..83b09e1310 100755
--- a/t/t1005-read-tree-reset.sh
+++ b/t/t1005-read-tree-reset.sh
@@ -33,7 +33,7 @@ test_expect_success 'reset should remove remnants from a failed merge' '
 	git ls-files -s >expect &&
 	sha1=$(git rev-parse :new) &&
 	(
-		echo "100644 $sha1 1	old"
+		echo "100644 $sha1 1	old" &&
 		echo "100644 $sha1 3	old"
 	) | git update-index --index-info &&
 	>old &&
@@ -48,7 +48,7 @@ test_expect_success 'two-way reset should remove remnants too' '
 	git ls-files -s >expect &&
 	sha1=$(git rev-parse :new) &&
 	(
-		echo "100644 $sha1 1	old"
+		echo "100644 $sha1 1	old" &&
 		echo "100644 $sha1 3	old"
 	) | git update-index --index-info &&
 	>old &&
@@ -63,7 +63,7 @@ test_expect_success 'Porcelain reset should remove remnants too' '
 	git ls-files -s >expect &&
 	sha1=$(git rev-parse :new) &&
 	(
-		echo "100644 $sha1 1	old"
+		echo "100644 $sha1 1	old" &&
 		echo "100644 $sha1 3	old"
 	) | git update-index --index-info &&
 	>old &&
@@ -78,7 +78,7 @@ test_expect_success 'Porcelain checkout -f should remove remnants too' '
 	git ls-files -s >expect &&
 	sha1=$(git rev-parse :new) &&
 	(
-		echo "100644 $sha1 1	old"
+		echo "100644 $sha1 1	old" &&
 		echo "100644 $sha1 3	old"
 	) | git update-index --index-info &&
 	>old &&
@@ -93,7 +93,7 @@ test_expect_success 'Porcelain checkout -f HEAD should remove remnants too' '
 	git ls-files -s >expect &&
 	sha1=$(git rev-parse :new) &&
 	(
-		echo "100644 $sha1 1	old"
+		echo "100644 $sha1 1	old" &&
 		echo "100644 $sha1 3	old"
 	) | git update-index --index-info &&
 	>old &&
diff --git a/t/t1008-read-tree-overlay.sh b/t/t1008-read-tree-overlay.sh
index 4c50ed955e..e74b185b6c 100755
--- a/t/t1008-read-tree-overlay.sh
+++ b/t/t1008-read-tree-overlay.sh
@@ -23,7 +23,7 @@ test_expect_success setup '
 
 test_expect_success 'multi-read' '
 	read_tree_must_succeed initial master side &&
-	(echo a; echo b/c) >expect &&
+	(echo a && echo b/c) >expect &&
 	git ls-files >actual &&
 	test_cmp expect actual
 '
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index df3183ea1a..c2df75e495 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -148,7 +148,7 @@ test_expect_success 'GIT_PREFIX for built-ins' '
 	(
 		cd dir &&
 		echo "change" >two &&
-		GIT_EXTERNAL_DIFF=./diff git diff >../actual
+		GIT_EXTERNAL_DIFF=./diff git diff >../actual &&
 		git checkout -- two
 	) &&
 	test_cmp expect actual
diff --git a/t/t1050-large.sh b/t/t1050-large.sh
index f9eb143f43..1a9b21b293 100755
--- a/t/t1050-large.sh
+++ b/t/t1050-large.sh
@@ -108,7 +108,7 @@ test_expect_success 'packsize limit' '
 		test-tool genrandom "c" $(( 128 * 1024 )) >mid3 &&
 		git add mid1 mid2 mid3 &&
 
-		count=0
+		count=0 &&
 		for pi in .git/objects/pack/pack-*.idx
 		do
 			test -f "$pi" && count=$(( $count + 1 ))
@@ -116,8 +116,8 @@ test_expect_success 'packsize limit' '
 		test $count = 2 &&
 
 		(
-			git hash-object --stdin <mid1
-			git hash-object --stdin <mid2
+			git hash-object --stdin <mid1 &&
+			git hash-object --stdin <mid2 &&
 			git hash-object --stdin <mid3
 		) |
 		sort >expect &&
diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh
index 596907758d..4d62ceef9c 100755
--- a/t/t1411-reflog-show.sh
+++ b/t/t1411-reflog-show.sh
@@ -159,9 +159,9 @@ test_expect_success 'git log -g -p shows diffs vs. parents' '
 	git log -1 -p HEAD^ >log.one &&
 	git log -1 -p HEAD >log.two &&
 	(
-		cat log.one; echo
-		cat log.two; echo
-		cat log.one; echo
+		cat log.one && echo &&
+		cat log.two && echo &&
+		cat log.one && echo &&
 		cat log.two
 	) >expect &&
 	test_cmp expect actual
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
index 96fe3754c8..e4d5b56014 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -34,8 +34,8 @@ test_expect_success 'blob and tree' '
 		for i in 0 1 2 3 4 5 6 7 8 9
 		do
 			echo $i
-		done
-		echo
+		done &&
+		echo &&
 		echo b1rwzyc3
 	) >a0blgqsjc &&
 
@@ -222,7 +222,7 @@ test_expect_success 'more history' '
 
 	test_might_fail git rm -f a0blgqsjc &&
 	(
-		git cat-file blob $side:f5518nwu
+		git cat-file blob $side:f5518nwu &&
 		echo j3l0i9s6
 	) >ab2gs879 &&
 	git add ab2gs879 &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 20/29] t2000-t2999: fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (18 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 19/29] t1000-t1999: " Eric Sunshine
@ 2018-06-26  7:29 ` " Eric Sunshine
  2018-06-26  7:29 ` [PATCH 21/29] t3000-t3999: " Eric Sunshine
                   ` (11 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t2103-update-index-ignore-missing.sh |  2 +-
 t/t2202-add-addremove.sh               | 14 +++++++-------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/t/t2103-update-index-ignore-missing.sh b/t/t2103-update-index-ignore-missing.sh
index 332694e7d3..0114f05228 100755
--- a/t/t2103-update-index-ignore-missing.sh
+++ b/t/t2103-update-index-ignore-missing.sh
@@ -32,7 +32,7 @@ test_expect_success basics '
 		test_create_repo xyzzy &&
 		cd xyzzy &&
 		>file &&
-		git add file
+		git add file &&
 		git commit -m "sub initial"
 	) &&
 	git add xyzzy &&
diff --git a/t/t2202-add-addremove.sh b/t/t2202-add-addremove.sh
index 6a5a3166b1..17744e8c57 100755
--- a/t/t2202-add-addremove.sh
+++ b/t/t2202-add-addremove.sh
@@ -6,12 +6,12 @@ test_description='git add --all'
 
 test_expect_success setup '
 	(
-		echo .gitignore
+		echo .gitignore &&
 		echo will-remove
 	) >expect &&
 	(
-		echo actual
-		echo expect
+		echo actual &&
+		echo expect &&
 		echo ignored
 	) >.gitignore &&
 	git --literal-pathspecs add --all &&
@@ -25,10 +25,10 @@ test_expect_success setup '
 
 test_expect_success 'git add --all' '
 	(
-		echo .gitignore
-		echo not-ignored
-		echo "M	.gitignore"
-		echo "A	not-ignored"
+		echo .gitignore &&
+		echo not-ignored &&
+		echo "M	.gitignore" &&
+		echo "A	not-ignored" &&
 		echo "D	will-remove"
 	) >expect &&
 	>ignored &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 21/29] t3000-t3999: fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (19 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 20/29] t2000-t2999: " Eric Sunshine
@ 2018-06-26  7:29 ` " Eric Sunshine
  2018-06-26  7:29 ` [PATCH 22/29] t3030: " Eric Sunshine
                   ` (10 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t3000-ls-files-others.sh              | 2 +-
 t/t3006-ls-files-long.sh                | 2 +-
 t/t3008-ls-files-lazy-init-name-hash.sh | 8 ++++----
 t/t3050-subprojects-fetch.sh            | 8 ++++----
 t/t3301-notes.sh                        | 8 ++++----
 t/t3400-rebase.sh                       | 8 ++++----
 t/t3402-rebase-merge.sh                 | 4 ++--
 t/t3418-rebase-continue.sh              | 4 ++--
 t/t3700-add.sh                          | 8 ++++----
 9 files changed, 26 insertions(+), 26 deletions(-)

diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh
index c525656b2c..afd4756134 100755
--- a/t/t3000-ls-files-others.sh
+++ b/t/t3000-ls-files-others.sh
@@ -84,7 +84,7 @@ test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' '
 	) &&
 	(
 		cd super &&
-		"$SHELL_PATH" "$TEST_DIRECTORY/../contrib/workdir/git-new-workdir" ../sub sub
+		"$SHELL_PATH" "$TEST_DIRECTORY/../contrib/workdir/git-new-workdir" ../sub sub &&
 		git ls-files --others --exclude-standard >../actual
 	) &&
 	echo sub/ >expect &&
diff --git a/t/t3006-ls-files-long.sh b/t/t3006-ls-files-long.sh
index 202ad658b8..e109c3fbfb 100755
--- a/t/t3006-ls-files-long.sh
+++ b/t/t3006-ls-files-long.sh
@@ -29,7 +29,7 @@ test_expect_success 'overly-long path does not replace another by mistake' '
 	printf "$pat" "$blob_a" "$path_a" "$blob_z" "$path_z" |
 	git update-index --add --index-info &&
 	(
-		echo "$path_a"
+		echo "$path_a" &&
 		echo "$path_z"
 	) >expect &&
 	git ls-files >actual &&
diff --git a/t/t3008-ls-files-lazy-init-name-hash.sh b/t/t3008-ls-files-lazy-init-name-hash.sh
index 08af596ba6..64f047332b 100755
--- a/t/t3008-ls-files-lazy-init-name-hash.sh
+++ b/t/t3008-ls-files-lazy-init-name-hash.sh
@@ -14,10 +14,10 @@ LAZY_THREAD_COST=2000
 
 test_expect_success 'no buffer overflow in lazy_init_name_hash' '
 	(
-	    test_seq $LAZY_THREAD_COST | sed "s/^/a_/"
-	    echo b/b/b
-	    test_seq $LAZY_THREAD_COST | sed "s/^/c_/"
-	    test_seq 50 | sed "s/^/d_/" | tr "\n" "/"; echo d
+	    test_seq $LAZY_THREAD_COST | sed "s/^/a_/" &&
+	    echo b/b/b &&
+	    test_seq $LAZY_THREAD_COST | sed "s/^/c_/" &&
+	    test_seq 50 | sed "s/^/d_/" | tr "\n" "/" && echo d
 	) |
 	sed "s/^/100644 $EMPTY_BLOB	/" |
 	git update-index --index-info &&
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 2f5f41a012..f1f09abdd9 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -21,10 +21,10 @@ test_expect_success setup '
 
 test_expect_success clone '
 	git clone "file://$(pwd)/.git" cloned &&
-	(git rev-parse HEAD; git ls-files -s) >expected &&
+	(git rev-parse HEAD && git ls-files -s) >expected &&
 	(
 		cd cloned &&
-		(git rev-parse HEAD; git ls-files -s) >../actual
+		(git rev-parse HEAD && git ls-files -s) >../actual
 	) &&
 	test_cmp expected actual
 '
@@ -40,11 +40,11 @@ test_expect_success advance '
 '
 
 test_expect_success fetch '
-	(git rev-parse HEAD; git ls-files -s) >expected &&
+	(git rev-parse HEAD && git ls-files -s) >expected &&
 	(
 		cd cloned &&
 		git pull &&
-		(git rev-parse HEAD; git ls-files -s) >../actual
+		(git rev-parse HEAD && git ls-files -s) >../actual
 	) &&
 	test_cmp expected actual
 '
diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh
index 2d200fdf36..ac62dc0e8f 100755
--- a/t/t3301-notes.sh
+++ b/t/t3301-notes.sh
@@ -914,7 +914,7 @@ test_expect_success 'git notes copy --stdin' '
 		${indent}
 		${indent}yet another note
 	EOF
-	(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \
+	(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^) &&
 	echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
 	git notes copy --stdin &&
 	git log -2 >actual &&
@@ -939,7 +939,7 @@ test_expect_success 'git notes copy --for-rewrite (unconfigured)' '
 	EOF
 	test_commit 14th &&
 	test_commit 15th &&
-	(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \
+	(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^) &&
 	echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
 	git notes copy --for-rewrite=foo &&
 	git log -2 >actual &&
@@ -972,7 +972,7 @@ test_expect_success 'git notes copy --for-rewrite (enabled)' '
 	EOF
 	test_config notes.rewriteMode overwrite &&
 	test_config notes.rewriteRef "refs/notes/*" &&
-	(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \
+	(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^) &&
 	echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
 	git notes copy --for-rewrite=foo &&
 	git log -2 >actual &&
@@ -1059,7 +1059,7 @@ test_expect_success 'git notes copy --for-rewrite (append two to one)' '
 	git notes add -f -m"append 2" HEAD^^ &&
 	test_config notes.rewriteMode concatenate &&
 	test_config notes.rewriteRef "refs/notes/*" &&
-	(echo $(git rev-parse HEAD^) $(git rev-parse HEAD);
+	(echo $(git rev-parse HEAD^) $(git rev-parse HEAD) &&
 	echo $(git rev-parse HEAD^^) $(git rev-parse HEAD)) |
 	git notes copy --for-rewrite=foo &&
 	git log -1 >actual &&
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 72d9564747..3996ee0135 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -200,10 +200,10 @@ test_expect_success 'rebase -q is quiet' '
 
 test_expect_success 'Rebase a commit that sprinkles CRs in' '
 	(
-		echo "One"
-		echo "TwoQ"
-		echo "Three"
-		echo "FQur"
+		echo "One" &&
+		echo "TwoQ" &&
+		echo "Three" &&
+		echo "FQur" &&
 		echo "Five"
 	) | q_to_cr >CR &&
 	git add CR &&
diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh
index 488945e007..a1ec501a87 100755
--- a/t/t3402-rebase-merge.sh
+++ b/t/t3402-rebase-merge.sh
@@ -25,7 +25,7 @@ test_expect_success setup '
 	git commit -a -m"master updates a bit more." &&
 
 	git checkout side &&
-	(echo "0 $T" ; cat original) >renamed &&
+	(echo "0 $T" && cat original) >renamed &&
 	git add renamed &&
 	git update-index --force-remove original &&
 	git commit -a -m"side renames and edits." &&
@@ -143,7 +143,7 @@ test_expect_success 'rebase -s funny -Xopt' '
 	git checkout -b test-funny master^ &&
 	test_commit funny &&
 	(
-		PATH=./test-bin:$PATH
+		PATH=./test-bin:$PATH &&
 		git rebase -s funny -Xopt master
 	) &&
 	test -f funny.was.run
diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh
index 03bf1b8a3b..853e015839 100755
--- a/t/t3418-rebase-continue.sh
+++ b/t/t3418-rebase-continue.sh
@@ -60,7 +60,7 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '
 	EOF
 	chmod +x test-bin/git-merge-funny &&
 	(
-		PATH=./test-bin:$PATH
+		PATH=./test-bin:$PATH &&
 		test_must_fail git rebase -s funny -Xopt master topic
 	) &&
 	test -f funny.was.run &&
@@ -68,7 +68,7 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '
 	echo "Resolved" >F2 &&
 	git add F2 &&
 	(
-		PATH=./test-bin:$PATH
+		PATH=./test-bin:$PATH &&
 		git rebase --continue
 	) &&
 	test -f funny.was.run
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 07af05d7ae..618750167a 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -156,9 +156,9 @@ test_expect_success 'git add with filemode=0, symlinks=0, and unmerged entries'
 test_expect_success 'git add with filemode=0, symlinks=0 prefers stage 2 over stage 1' '
 	git rm --cached -f file symlink &&
 	(
-		echo "100644 $(git hash-object -w stage1) 1	file"
-		echo "100755 $(git hash-object -w stage2) 2	file"
-		echo "100644 $(printf 1 | git hash-object -w -t blob --stdin) 1	symlink"
+		echo "100644 $(git hash-object -w stage1) 1	file" &&
+		echo "100755 $(git hash-object -w stage2) 2	file" &&
+		echo "100644 $(printf 1 | git hash-object -w -t blob --stdin) 1	symlink" &&
 		echo "120000 $(printf 2 | git hash-object -w -t blob --stdin) 2	symlink"
 	) | git update-index --index-info &&
 	git config core.filemode 0 &&
@@ -265,7 +265,7 @@ test_expect_success 'git add to resolve conflicts on otherwise ignored path' '
 	git reset --hard &&
 	H=$(git rev-parse :1/2/a) &&
 	(
-		echo "100644 $H 1	track-this"
+		echo "100644 $H 1	track-this" &&
 		echo "100644 $H 3	track-this"
 	) | git update-index --index-info &&
 	echo track-this >>.gitignore &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 22/29] t3030: fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (20 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 21/29] t3000-t3999: " Eric Sunshine
@ 2018-06-26  7:29 ` " Eric Sunshine
  2018-06-26  7:29 ` [PATCH 23/29] t4000-t4999: " Eric Sunshine
                   ` (9 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t3030-merge-recursive.sh | 340 ++++++++++++++++++-------------------
 1 file changed, 170 insertions(+), 170 deletions(-)

diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
index 3563e77b37..ff641b348a 100755
--- a/t/t3030-merge-recursive.sh
+++ b/t/t3030-merge-recursive.sh
@@ -36,15 +36,15 @@ test_expect_success 'setup 1' '
 	test_tick &&
 	git commit -m "master modifies a and d/e" &&
 	c1=$(git rev-parse --verify HEAD) &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o1	a"
-		echo "100644 blob $o0	b"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o1	d/e"
-		echo "100644 $o1 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 blob $o1	a" &&
+		echo "100644 blob $o0	b" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o1	d/e" &&
+		echo "100644 $o1 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o1 0	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -54,15 +54,15 @@ test_expect_success 'setup 2' '
 
 	rm -rf [abcd] &&
 	git checkout side &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o0	a"
-		echo "100644 blob $o0	b"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o0	d/e"
-		echo "100644 $o0 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 blob $o0	a" &&
+		echo "100644 blob $o0	b" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o0	d/e" &&
+		echo "100644 $o0 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o0 0	d/e"
 	) >expected &&
 	test_cmp expected actual &&
@@ -75,15 +75,15 @@ test_expect_success 'setup 2' '
 	test_tick &&
 	git commit -m "side modifies a" &&
 	c2=$(git rev-parse --verify HEAD) &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o2	a"
-		echo "100644 blob $o0	b"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o0	d/e"
-		echo "100644 $o2 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 blob $o2	a" &&
+		echo "100644 blob $o0	b" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o0	d/e" &&
+		echo "100644 $o2 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o0 0	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -93,15 +93,15 @@ test_expect_success 'setup 3' '
 
 	rm -rf [abcd] &&
 	git checkout df-1 &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o0	a"
-		echo "100644 blob $o0	b"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o0	d/e"
-		echo "100644 $o0 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 blob $o0	a" &&
+		echo "100644 blob $o0	b" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o0	d/e" &&
+		echo "100644 $o0 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o0 0	d/e"
 	) >expected &&
 	test_cmp expected actual &&
@@ -112,15 +112,15 @@ test_expect_success 'setup 3' '
 	test_tick &&
 	git commit -m "df-1 makes b/c" &&
 	c3=$(git rev-parse --verify HEAD) &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o0	a"
-		echo "100644 blob $o3	b/c"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o0	d/e"
-		echo "100644 $o0 0	a"
-		echo "100644 $o3 0	b/c"
-		echo "100644 $o0 0	c"
+		echo "100644 blob $o0	a" &&
+		echo "100644 blob $o3	b/c" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o0	d/e" &&
+		echo "100644 $o0 0	a" &&
+		echo "100644 $o3 0	b/c" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o0 0	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -130,15 +130,15 @@ test_expect_success 'setup 4' '
 
 	rm -rf [abcd] &&
 	git checkout df-2 &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o0	a"
-		echo "100644 blob $o0	b"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o0	d/e"
-		echo "100644 $o0 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 blob $o0	a" &&
+		echo "100644 blob $o0	b" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o0	d/e" &&
+		echo "100644 $o0 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o0 0	d/e"
 	) >expected &&
 	test_cmp expected actual &&
@@ -149,15 +149,15 @@ test_expect_success 'setup 4' '
 	test_tick &&
 	git commit -m "df-2 makes a/c" &&
 	c4=$(git rev-parse --verify HEAD) &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o4	a/c"
-		echo "100644 blob $o0	b"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o0	d/e"
-		echo "100644 $o4 0	a/c"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 blob $o4	a/c" &&
+		echo "100644 blob $o0	b" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o0	d/e" &&
+		echo "100644 $o4 0	a/c" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o0 0	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -167,15 +167,15 @@ test_expect_success 'setup 5' '
 
 	rm -rf [abcd] &&
 	git checkout remove &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o0	a"
-		echo "100644 blob $o0	b"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o0	d/e"
-		echo "100644 $o0 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 blob $o0	a" &&
+		echo "100644 blob $o0	b" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o0	d/e" &&
+		echo "100644 $o0 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o0 0	d/e"
 	) >expected &&
 	test_cmp expected actual &&
@@ -190,13 +190,13 @@ test_expect_success 'setup 5' '
 	test_tick &&
 	git commit -m "remove removes b and modifies a" &&
 	c5=$(git rev-parse --verify HEAD) &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o5	a"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o0	d/e"
-		echo "100644 $o5 0	a"
-		echo "100644 $o0 0	c"
+		echo "100644 blob $o5	a" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o0	d/e" &&
+		echo "100644 $o5 0	a" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o0 0	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -207,15 +207,15 @@ test_expect_success 'setup 6' '
 
 	rm -rf [abcd] &&
 	git checkout df-3 &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o0	a"
-		echo "100644 blob $o0	b"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o0	d/e"
-		echo "100644 $o0 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 blob $o0	a" &&
+		echo "100644 blob $o0	b" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o0	d/e" &&
+		echo "100644 $o0 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o0 0	d/e"
 	) >expected &&
 	test_cmp expected actual &&
@@ -226,15 +226,15 @@ test_expect_success 'setup 6' '
 	test_tick &&
 	git commit -m "df-3 makes d" &&
 	c6=$(git rev-parse --verify HEAD) &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o0	a"
-		echo "100644 blob $o0	b"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o6	d"
-		echo "100644 $o0 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 blob $o0	a" &&
+		echo "100644 blob $o0	b" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o6	d" &&
+		echo "100644 $o0 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o6 0	d"
 	) >expected &&
 	test_cmp expected actual
@@ -286,11 +286,11 @@ test_expect_success 'merge-recursive result' '
 
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o0 1	a"
-		echo "100644 $o2 2	a"
-		echo "100644 $o1 3	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 $o0 1	a" &&
+		echo "100644 $o2 2	a" &&
+		echo "100644 $o1 3	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o1 0	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -325,10 +325,10 @@ test_expect_success 'merge-recursive remove conflict' '
 
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o0 1	a"
-		echo "100644 $o1 2	a"
-		echo "100644 $o5 3	a"
-		echo "100644 $o0 0	c"
+		echo "100644 $o0 1	a" &&
+		echo "100644 $o1 2	a" &&
+		echo "100644 $o5 3	a" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o1 0	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -347,9 +347,9 @@ test_expect_success 'merge-recursive result' '
 
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o1 0	a"
-		echo "100644 $o3 0	b/c"
-		echo "100644 $o0 0	c"
+		echo "100644 $o1 0	a" &&
+		echo "100644 $o3 0	b/c" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o1 0	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -369,11 +369,11 @@ test_expect_success 'merge-recursive d/f conflict result' '
 
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o0 1	a"
-		echo "100644 $o1 2	a"
-		echo "100644 $o4 0	a/c"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 $o0 1	a" &&
+		echo "100644 $o1 2	a" &&
+		echo "100644 $o4 0	a/c" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o1 0	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -393,11 +393,11 @@ test_expect_success 'merge-recursive d/f conflict result the other way' '
 
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o0 1	a"
-		echo "100644 $o1 3	a"
-		echo "100644 $o4 0	a/c"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 $o0 1	a" &&
+		echo "100644 $o1 3	a" &&
+		echo "100644 $o4 0	a/c" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o1 0	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -417,11 +417,11 @@ test_expect_success 'merge-recursive d/f conflict result' '
 
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o1 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
-		echo "100644 $o6 3	d"
-		echo "100644 $o0 1	d/e"
+		echo "100644 $o1 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
+		echo "100644 $o6 3	d" &&
+		echo "100644 $o0 1	d/e" &&
 		echo "100644 $o1 2	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -441,11 +441,11 @@ test_expect_success 'merge-recursive d/f conflict result' '
 
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o1 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
-		echo "100644 $o6 2	d"
-		echo "100644 $o0 1	d/e"
+		echo "100644 $o1 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
+		echo "100644 $o6 2	d" &&
+		echo "100644 $o0 1	d/e" &&
 		echo "100644 $o1 3	d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -465,13 +465,13 @@ test_expect_success 'reset and bind merge' '
 	git read-tree --prefix=M/ master &&
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o1 0	M/a"
-		echo "100644 $o0 0	M/b"
-		echo "100644 $o0 0	M/c"
-		echo "100644 $o1 0	M/d/e"
-		echo "100644 $o1 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 $o1 0	M/a" &&
+		echo "100644 $o0 0	M/b" &&
+		echo "100644 $o0 0	M/c" &&
+		echo "100644 $o1 0	M/d/e" &&
+		echo "100644 $o1 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o1 0	d/e"
 	) >expected &&
 	test_cmp expected actual &&
@@ -479,17 +479,17 @@ test_expect_success 'reset and bind merge' '
 	git read-tree --prefix=a1/ master &&
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o1 0	M/a"
-		echo "100644 $o0 0	M/b"
-		echo "100644 $o0 0	M/c"
-		echo "100644 $o1 0	M/d/e"
-		echo "100644 $o1 0	a"
-		echo "100644 $o1 0	a1/a"
-		echo "100644 $o0 0	a1/b"
-		echo "100644 $o0 0	a1/c"
-		echo "100644 $o1 0	a1/d/e"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
+		echo "100644 $o1 0	M/a" &&
+		echo "100644 $o0 0	M/b" &&
+		echo "100644 $o0 0	M/c" &&
+		echo "100644 $o1 0	M/d/e" &&
+		echo "100644 $o1 0	a" &&
+		echo "100644 $o1 0	a1/a" &&
+		echo "100644 $o0 0	a1/b" &&
+		echo "100644 $o0 0	a1/c" &&
+		echo "100644 $o1 0	a1/d/e" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
 		echo "100644 $o1 0	d/e"
 	) >expected &&
 	test_cmp expected actual &&
@@ -497,21 +497,21 @@ test_expect_success 'reset and bind merge' '
 	git read-tree --prefix=z/ master &&
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o1 0	M/a"
-		echo "100644 $o0 0	M/b"
-		echo "100644 $o0 0	M/c"
-		echo "100644 $o1 0	M/d/e"
-		echo "100644 $o1 0	a"
-		echo "100644 $o1 0	a1/a"
-		echo "100644 $o0 0	a1/b"
-		echo "100644 $o0 0	a1/c"
-		echo "100644 $o1 0	a1/d/e"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
-		echo "100644 $o1 0	d/e"
-		echo "100644 $o1 0	z/a"
-		echo "100644 $o0 0	z/b"
-		echo "100644 $o0 0	z/c"
+		echo "100644 $o1 0	M/a" &&
+		echo "100644 $o0 0	M/b" &&
+		echo "100644 $o0 0	M/c" &&
+		echo "100644 $o1 0	M/d/e" &&
+		echo "100644 $o1 0	a" &&
+		echo "100644 $o1 0	a1/a" &&
+		echo "100644 $o0 0	a1/b" &&
+		echo "100644 $o0 0	a1/c" &&
+		echo "100644 $o1 0	a1/d/e" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
+		echo "100644 $o1 0	d/e" &&
+		echo "100644 $o1 0	z/a" &&
+		echo "100644 $o0 0	z/b" &&
+		echo "100644 $o0 0	z/c" &&
 		echo "100644 $o1 0	z/d/e"
 	) >expected &&
 	test_cmp expected actual
@@ -589,8 +589,8 @@ test_expect_success 'merge-recursive simple w/submodule result' '
 
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o5 0	a"
-		echo "100644 $o0 0	c"
+		echo "100644 $o5 0	a" &&
+		echo "100644 $o0 0	c" &&
 		echo "160000 $c1 0	d"
 	) >expected &&
 	test_cmp expected actual
@@ -601,13 +601,13 @@ test_expect_success 'merge-recursive copy vs. rename' '
 	git merge rename &&
 	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "100644 blob $o0	b"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o0	d/e"
-		echo "100644 blob $o0	e"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
-		echo "100644 $o0 0	d/e"
+		echo "100644 blob $o0	b" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o0	d/e" &&
+		echo "100644 blob $o0	e" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
+		echo "100644 $o0 0	d/e" &&
 		echo "100644 $o0 0	e"
 	) >expected &&
 	test_cmp expected actual
@@ -617,17 +617,17 @@ test_expect_failure 'merge-recursive rename vs. rename/symlink' '
 
 	git checkout -f rename &&
 	git merge rename-ln &&
-	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	( git ls-tree -r HEAD && git ls-files -s ) >actual &&
 	(
-		echo "120000 blob $oln	a"
-		echo "100644 blob $o0	b"
-		echo "100644 blob $o0	c"
-		echo "100644 blob $o0	d/e"
-		echo "100644 blob $o0	e"
-		echo "120000 $oln 0	a"
-		echo "100644 $o0 0	b"
-		echo "100644 $o0 0	c"
-		echo "100644 $o0 0	d/e"
+		echo "120000 blob $oln	a" &&
+		echo "100644 blob $o0	b" &&
+		echo "100644 blob $o0	c" &&
+		echo "100644 blob $o0	d/e" &&
+		echo "100644 blob $o0	e" &&
+		echo "120000 $oln 0	a" &&
+		echo "100644 $o0 0	b" &&
+		echo "100644 $o0 0	c" &&
+		echo "100644 $o0 0	d/e" &&
 		echo "100644 $o0 0	e"
 	) >expected &&
 	test_cmp expected actual
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 23/29] t4000-t4999: fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (21 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 22/29] t3030: " Eric Sunshine
@ 2018-06-26  7:29 ` " Eric Sunshine
  2018-06-26  7:29 ` [PATCH 24/29] t5000-t5999: " Eric Sunshine
                   ` (8 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t4001-diff-rename.sh                       | 2 +-
 t/t4025-hunk-header.sh                       | 8 ++++----
 t/t4041-diff-submodule-option.sh             | 4 ++--
 t/t4060-diff-submodule-option-diff-format.sh | 2 +-
 t/t4121-apply-diffs.sh                       | 2 +-
 5 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh
index bf4030371a..c16486a9d4 100755
--- a/t/t4001-diff-rename.sh
+++ b/t/t4001-diff-rename.sh
@@ -180,7 +180,7 @@ test_expect_success 'setup for many rename source candidates' '
 	git add "path??" &&
 	test_tick &&
 	git commit -m "hundred" &&
-	(cat path1; echo new) >new-path &&
+	(cat path1 && echo new) >new-path &&
 	echo old >>path1 &&
 	git add new-path path1 &&
 	git diff -l 4 -C -C --cached --name-status >actual 2>actual.err &&
diff --git a/t/t4025-hunk-header.sh b/t/t4025-hunk-header.sh
index 7a3dbc1ea2..fa44e78869 100755
--- a/t/t4025-hunk-header.sh
+++ b/t/t4025-hunk-header.sh
@@ -12,12 +12,12 @@ NS="$N$N$N$N$N$N$N$N$N$N$N$N$N"
 test_expect_success setup '
 
 	(
-		echo "A $NS"
+		echo "A $NS" &&
 		for c in B C D E F G H I J K
 		do
 			echo "  $c"
-		done
-		echo "L  $NS"
+		done &&
+		echo "L  $NS" &&
 		for c in M N O P Q R S T U V
 		do
 			echo "  $c"
@@ -34,7 +34,7 @@ test_expect_success 'hunk header truncation with an overly long line' '
 
 	git diff | sed -n -e "s/^.*@@//p" >actual &&
 	(
-		echo " A $N$N$N$N$N$N$N$N$N2"
+		echo " A $N$N$N$N$N$N$N$N$N2" &&
 		echo " L  $N$N$N$N$N$N$N$N$N1"
 	) >expected &&
 	test_cmp actual expected
diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh
index 058ee0829d..4e3499ef84 100755
--- a/t/t4041-diff-submodule-option.sh
+++ b/t/t4041-diff-submodule-option.sh
@@ -498,7 +498,7 @@ test_expect_success 'given commit --submodule=short' '
 test_expect_success 'setup .git file for sm2' '
 	(cd sm2 &&
 	 REAL="$(pwd)/../.real" &&
-	 mv .git "$REAL"
+	 mv .git "$REAL" &&
 	 echo "gitdir: $REAL" >.git)
 '
 
@@ -527,7 +527,7 @@ test_expect_success 'diff --submodule with objects referenced by alternates' '
 		git commit -m "sub a"
 	) &&
 	(cd sub_alt &&
-		sha1_before=$(git rev-parse --short HEAD)
+		sha1_before=$(git rev-parse --short HEAD) &&
 		echo b >b &&
 		git add b &&
 		git commit -m b &&
diff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh
index 4b168d0ed7..0eba4620f0 100755
--- a/t/t4060-diff-submodule-option-diff-format.sh
+++ b/t/t4060-diff-submodule-option-diff-format.sh
@@ -721,7 +721,7 @@ test_expect_success 'given commit' '
 test_expect_success 'setup .git file for sm2' '
 	(cd sm2 &&
 	 REAL="$(pwd)/../.real" &&
-	 mv .git "$REAL"
+	 mv .git "$REAL" &&
 	 echo "gitdir: $REAL" >.git)
 '
 
diff --git a/t/t4121-apply-diffs.sh b/t/t4121-apply-diffs.sh
index aff551a1d7..66368effd5 100755
--- a/t/t4121-apply-diffs.sh
+++ b/t/t4121-apply-diffs.sh
@@ -27,6 +27,6 @@ test_expect_success 'setup' \
 
 test_expect_success \
 	'check if contextually independent diffs for the same file apply' \
-	'( git diff test~2 test~1; git diff test~1 test~0 )| git apply'
+	'( git diff test~2 test~1 && git diff test~1 test~0 )| git apply'
 
 test_done
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 24/29] t5000-t5999: fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (22 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 23/29] t4000-t4999: " Eric Sunshine
@ 2018-06-26  7:29 ` " Eric Sunshine
  2018-06-26  7:29 ` [PATCH 25/29] t6000-t6999: " Eric Sunshine
                   ` (7 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t5300-pack-object.sh         |  2 +-
 t/t5302-pack-index.sh          |  2 +-
 t/t5401-update-hooks.sh        |  4 ++--
 t/t5406-remote-rejects.sh      |  2 +-
 t/t5500-fetch-pack.sh          |  2 +-
 t/t5505-remote.sh              |  2 +-
 t/t5512-ls-remote.sh           |  4 ++--
 t/t5516-fetch-push.sh          | 10 +++++-----
 t/t5517-push-mirror.sh         | 10 +++++-----
 t/t5526-fetch-submodules.sh    |  2 +-
 t/t5531-deep-submodule-push.sh |  2 +-
 t/t5543-atomic-push.sh         |  2 +-
 t/t5601-clone.sh               |  2 +-
 t/t5605-clone-local.sh         |  2 +-
 t/t5801-remote-helpers.sh      |  2 +-
 15 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 2336d09dcc..6c620cd540 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -191,7 +191,7 @@ test_expect_success 'survive missing objects/pack directory' '
 		mkdir missing-pack &&
 		cd missing-pack &&
 		git init &&
-		GOP=.git/objects/pack
+		GOP=.git/objects/pack &&
 		rm -fr $GOP &&
 		git index-pack --stdin --keep=test <../test-3-${packname_3}.pack &&
 		test -f $GOP/pack-${packname_3}.pack &&
diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh
index bb9b8bb309..91d51b35f9 100755
--- a/t/t5302-pack-index.sh
+++ b/t/t5302-pack-index.sh
@@ -237,7 +237,7 @@ test_expect_success 'running index-pack in the object store' '
     rm -f .git/objects/pack/* &&
     cp test-1-${pack1}.pack .git/objects/pack/pack-${pack1}.pack &&
     (
-	cd .git/objects/pack
+	cd .git/objects/pack &&
 	git index-pack pack-${pack1}.pack
     ) &&
     test -f .git/objects/pack/pack-${pack1}.idx
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
index 7f278d8ce9..b5f886a0e2 100755
--- a/t/t5401-update-hooks.sh
+++ b/t/t5401-update-hooks.sh
@@ -82,13 +82,13 @@ test_expect_success 'hooks ran' '
 '
 
 test_expect_success 'pre-receive hook input' '
-	(echo $commit0 $commit1 refs/heads/master;
+	(echo $commit0 $commit1 refs/heads/master &&
 	 echo $commit1 $commit0 refs/heads/tofail
 	) | test_cmp - victim.git/pre-receive.stdin
 '
 
 test_expect_success 'update hook arguments' '
-	(echo refs/heads/master $commit0 $commit1;
+	(echo refs/heads/master $commit0 $commit1 &&
 	 echo refs/heads/tofail $commit1 $commit0
 	) | test_cmp - victim.git/update.args
 '
diff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh
index 59e80a5ea2..350d2e6ea5 100755
--- a/t/t5406-remote-rejects.sh
+++ b/t/t5406-remote-rejects.sh
@@ -6,7 +6,7 @@ test_description='remote push rejects are reported by client'
 
 test_expect_success 'setup' '
 	mkdir .git/hooks &&
-	(echo "#!/bin/sh" ; echo "exit 1") >.git/hooks/update &&
+	(echo "#!/bin/sh" && echo "exit 1") >.git/hooks/update &&
 	chmod +x .git/hooks/update &&
 	echo 1 >file &&
 	git add file &&
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 8390c0a2d2..c394779f65 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -259,7 +259,7 @@ test_expect_success 'clone shallow object count' '
 test_expect_success 'pull in shallow repo with missing merge base' '
 	(
 		cd shallow &&
-		git fetch --depth 4 .. A
+		git fetch --depth 4 .. A &&
 		test_must_fail git merge --allow-unrelated-histories FETCH_HEAD
 	)
 '
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 3552b51b4c..11e14a1e0f 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -844,7 +844,7 @@ test_expect_success 'migrate a remote from named file in $GIT_DIR/branches (2)'
 		git remote rename origin origin &&
 		test_path_is_missing .git/branches/origin &&
 		test "$(git config remote.origin.url)" = "quux" &&
-		test "$(git config remote.origin.fetch)" = "refs/heads/foom:refs/heads/origin"
+		test "$(git config remote.origin.fetch)" = "refs/heads/foom:refs/heads/origin" &&
 		test "$(git config remote.origin.push)" = "HEAD:refs/heads/foom"
 	)
 '
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 6a949484d0..ea020040e8 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -15,7 +15,7 @@ test_expect_success setup '
 	git tag mark1.10 &&
 	git show-ref --tags -d | sed -e "s/ /	/" >expected.tag &&
 	(
-		echo "$(git rev-parse HEAD)	HEAD"
+		echo "$(git rev-parse HEAD)	HEAD" &&
 		git show-ref -d	| sed -e "s/ /	/"
 	) >expected.all &&
 
@@ -105,7 +105,7 @@ test_expect_success 'use branch.<name>.remote if possible' '
 	git clone . other.git &&
 	(
 		cd other.git &&
-		echo "$(git rev-parse HEAD)	HEAD"
+		echo "$(git rev-parse HEAD)	HEAD" &&
 		git show-ref	| sed -e "s/ /	/"
 	) >exp &&
 
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index a5077d8b7c..bd8f23e430 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -923,7 +923,7 @@ test_expect_success 'push into aliased refs (consistent)' '
 	(
 		cd child1 &&
 		git branch foo &&
-		git symbolic-ref refs/heads/bar refs/heads/foo
+		git symbolic-ref refs/heads/bar refs/heads/foo &&
 		git config receive.denyCurrentBranch false
 	) &&
 	(
@@ -945,7 +945,7 @@ test_expect_success 'push into aliased refs (inconsistent)' '
 	(
 		cd child1 &&
 		git branch foo &&
-		git symbolic-ref refs/heads/bar refs/heads/foo
+		git symbolic-ref refs/heads/bar refs/heads/foo &&
 		git config receive.denyCurrentBranch false
 	) &&
 	(
@@ -1011,7 +1011,7 @@ test_expect_success 'push --porcelain rejected' '
 	mk_empty testrepo &&
 	git push testrepo refs/heads/master:refs/remotes/origin/master &&
 	(cd testrepo &&
-		git reset --hard origin/master^
+		git reset --hard origin/master^ &&
 		git config receive.denyCurrentBranch true) &&
 
 	echo >.git/foo  "To testrepo"  &&
@@ -1025,7 +1025,7 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 	mk_empty testrepo &&
 	git push testrepo refs/heads/master:refs/remotes/origin/master &&
 	(cd testrepo &&
-		git reset --hard origin/master
+		git reset --hard origin/master &&
 		git config receive.denyCurrentBranch true) &&
 
 	echo >.git/foo  "To testrepo"  &&
@@ -1333,7 +1333,7 @@ test_expect_success 'push --follow-tag only pushes relevant tags' '
 		git commit --allow-empty -m "future commit" &&
 		git tag -m "future" future &&
 		git checkout master &&
-		git for-each-ref refs/heads/master refs/tags/tag >../expect
+		git for-each-ref refs/heads/master refs/tags/tag >../expect &&
 		git push --follow-tag ../dst master
 	) &&
 	(
diff --git a/t/t5517-push-mirror.sh b/t/t5517-push-mirror.sh
index 02f160aae0..c05a661400 100755
--- a/t/t5517-push-mirror.sh
+++ b/t/t5517-push-mirror.sh
@@ -71,7 +71,7 @@ test_expect_success 'push mirror force updates existing branches' '
 		git push --mirror up &&
 		echo two >foo && git add foo && git commit -m two &&
 		git push --mirror up &&
-		git reset --hard HEAD^
+		git reset --hard HEAD^ &&
 		git push --mirror up
 	) &&
 	master_master=$(cd master && git show-ref -s --verify refs/heads/master) &&
@@ -88,7 +88,7 @@ test_expect_success 'push mirror removes branches' '
 		echo one >foo && git add foo && git commit -m one &&
 		git branch remove master &&
 		git push --mirror up &&
-		git branch -D remove
+		git branch -D remove &&
 		git push --mirror up
 	) &&
 	(
@@ -170,7 +170,7 @@ test_expect_success 'push mirror force updates existing tags' '
 		echo two >foo && git add foo && git commit -m two &&
 		git tag -f tmaster master &&
 		git push --mirror up &&
-		git reset --hard HEAD^
+		git reset --hard HEAD^ &&
 		git tag -f tmaster master &&
 		git push --mirror up
 	) &&
@@ -188,7 +188,7 @@ test_expect_success 'push mirror removes tags' '
 		echo one >foo && git add foo && git commit -m one &&
 		git tag -f tremove master &&
 		git push --mirror up &&
-		git tag -d tremove
+		git tag -d tremove &&
 		git push --mirror up
 	) &&
 	(
@@ -235,7 +235,7 @@ test_expect_success 'remote.foo.mirror adds and removes branches' '
 		git branch keep master &&
 		git branch remove master &&
 		git push up &&
-		git branch -D remove
+		git branch -D remove &&
 		git push up
 	) &&
 	(
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index 9cc4b569c0..143638c8cd 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -379,7 +379,7 @@ test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necess
 			git config -f .gitmodules submodule.subdir/deepsubmodule.fetchRecursive false
 		) &&
 		git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err &&
-		git config --unset fetch.recurseSubmodules
+		git config --unset fetch.recurseSubmodules &&
 		(
 			cd submodule &&
 			git config --unset -f .gitmodules submodule.subdir/deepsubmodule.fetchRecursive
diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh
index 39cb2c1c34..e2c37fd978 100755
--- a/t/t5531-deep-submodule-push.sh
+++ b/t/t5531-deep-submodule-push.sh
@@ -354,7 +354,7 @@ test_expect_success 'push succeeds if submodule has no remote and is on the firs
 	git clone a a1 &&
 	(
 		cd a1 &&
-		git init b
+		git init b &&
 		(
 			cd b &&
 			>junk &&
diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh
index 3480b33007..7079bcf9a0 100755
--- a/t/t5543-atomic-push.sh
+++ b/t/t5543-atomic-push.sh
@@ -178,7 +178,7 @@ test_expect_success 'atomic push obeys update hook preventing a branch to be pus
 test_expect_success 'atomic push is not advertised if configured' '
 	mk_repo_pair &&
 	(
-		cd upstream
+		cd upstream &&
 		git config receive.advertiseatomic 0
 	) &&
 	(
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 0b62037744..ddaa96ac4f 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -618,7 +618,7 @@ hex2oct () {
 test_expect_success 'clone on case-insensitive fs' '
 	git init icasefs &&
 	(
-		cd icasefs
+		cd icasefs &&
 		o=$(git hash-object -w --stdin </dev/null | hex2oct) &&
 		t=$(printf "100644 X\0${o}100644 x\0${o}" |
 			git hash-object -w -t tree --stdin) &&
diff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh
index 3c087e907c..af23419ebf 100755
--- a/t/t5605-clone-local.sh
+++ b/t/t5605-clone-local.sh
@@ -94,7 +94,7 @@ test_expect_success 'clone empty repository' '
 	 git config receive.denyCurrentBranch warn) &&
 	git clone empty empty-clone &&
 	test_tick &&
-	(cd empty-clone
+	(cd empty-clone &&
 	 echo "content" >> foo &&
 	 git add foo &&
 	 git commit -m "Initial commit" &&
diff --git a/t/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh
index 362b1581e0..ee5757966f 100755
--- a/t/t5801-remote-helpers.sh
+++ b/t/t5801-remote-helpers.sh
@@ -96,7 +96,7 @@ test_expect_success 'push new branch with old:new refspec' '
 
 test_expect_success 'push new branch with HEAD:new refspec' '
 	(cd local &&
-	 git checkout new-name
+	 git checkout new-name &&
 	 git push origin HEAD:new-refspec-2
 	) &&
 	compare_refs local HEAD server refs/heads/new-refspec-2
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 25/29] t6000-t6999: fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (23 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 24/29] t5000-t5999: " Eric Sunshine
@ 2018-06-26  7:29 ` " Eric Sunshine
  2018-06-26  7:29 ` [PATCH 26/29] t7000-t7999: " Eric Sunshine
                   ` (6 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t6010-merge-base.sh                |  2 +-
 t/t6029-merge-subtree.sh             | 16 ++++++++--------
 t/t6036-recursive-corner-cases.sh    |  6 +++---
 t/t6042-merge-rename-corner-cases.sh |  8 ++++----
 t/t6043-merge-rename-directories.sh  |  2 +-
 5 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/t/t6010-merge-base.sh b/t/t6010-merge-base.sh
index aa2d360ce3..44c726ea39 100755
--- a/t/t6010-merge-base.sh
+++ b/t/t6010-merge-base.sh
@@ -245,7 +245,7 @@ test_expect_success 'using reflog to find the fork point' '
 			git commit --allow-empty -m "Derived #$count" &&
 			git rev-parse HEAD >derived$count &&
 			git checkout -B base $E || exit 1
-		done
+		done &&
 
 		for count in 1 2 3
 		do
diff --git a/t/t6029-merge-subtree.sh b/t/t6029-merge-subtree.sh
index 3e692454a7..7d5bc78472 100755
--- a/t/t6029-merge-subtree.sh
+++ b/t/t6029-merge-subtree.sh
@@ -55,7 +55,7 @@ test_expect_success 'initial merge' '
 	git checkout -b work &&
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o1 0	git-gui/git-gui.sh"
+		echo "100644 $o1 0	git-gui/git-gui.sh" &&
 		echo "100644 $o2 0	git.c"
 	) >expected &&
 	test_cmp expected actual
@@ -72,7 +72,7 @@ test_expect_success 'merge update' '
 	git pull -s subtree gui master2 &&
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o3 0	git-gui/git-gui.sh"
+		echo "100644 $o3 0	git-gui/git-gui.sh" &&
 		echo "100644 $o2 0	git.c"
 	) >expected &&
 	test_cmp expected actual
@@ -88,8 +88,8 @@ test_expect_success 'initial ambiguous subtree' '
 	git checkout -b work2 &&
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o1 0	git-gui/git-gui.sh"
-		echo "100644 $o1 0	git-gui2/git-gui.sh"
+		echo "100644 $o1 0	git-gui/git-gui.sh" &&
+		echo "100644 $o1 0	git-gui2/git-gui.sh" &&
 		echo "100644 $o2 0	git.c"
 	) >expected &&
 	test_cmp expected actual
@@ -101,8 +101,8 @@ test_expect_success 'merge using explicit' '
 	git pull -Xsubtree=git-gui gui master2 &&
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o3 0	git-gui/git-gui.sh"
-		echo "100644 $o1 0	git-gui2/git-gui.sh"
+		echo "100644 $o3 0	git-gui/git-gui.sh" &&
+		echo "100644 $o1 0	git-gui2/git-gui.sh" &&
 		echo "100644 $o2 0	git.c"
 	) >expected &&
 	test_cmp expected actual
@@ -114,8 +114,8 @@ test_expect_success 'merge2 using explicit' '
 	git pull -Xsubtree=git-gui2 gui master2 &&
 	git ls-files -s >actual &&
 	(
-		echo "100644 $o1 0	git-gui/git-gui.sh"
-		echo "100644 $o3 0	git-gui2/git-gui.sh"
+		echo "100644 $o1 0	git-gui/git-gui.sh" &&
+		echo "100644 $o3 0	git-gui2/git-gui.sh" &&
 		echo "100644 $o2 0	git.c"
 	) >expected &&
 	test_cmp expected actual
diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh
index b32ff8e1db..892cf08743 100755
--- a/t/t6036-recursive-corner-cases.sh
+++ b/t/t6036-recursive-corner-cases.sh
@@ -72,7 +72,7 @@ test_expect_success 'merge simple rename+criss-cross with no modifications' '
 		git rev-parse   >actual     \
 			:2:three   :3:three &&
 		git hash-object >>actual    \
-			three~HEAD three~R2^0
+			three~HEAD three~R2^0 &&
 		test_cmp expect actual
 	)
 '
@@ -148,7 +148,7 @@ test_expect_success 'merge criss-cross + rename merges with basic modification'
 		git rev-parse   >actual     \
 			:2:three   :3:three &&
 		git hash-object >>actual    \
-			three~HEAD three~R2^0
+			three~HEAD three~R2^0 &&
 		test_cmp expect actual
 	)
 '
@@ -228,7 +228,7 @@ test_expect_success 'git detects differently handled merges conflict' '
 			D:new_a  E:new_a &&
 		git rev-parse   >actual     \
 			:2:new_a :3:new_a &&
-		test_cmp expect actual
+		test_cmp expect actual &&
 
 		git cat-file -p B:new_a >ours &&
 		git cat-file -p C:new_a >theirs &&
diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh
index 1cbd946fc2..661b633478 100755
--- a/t/t6042-merge-rename-corner-cases.sh
+++ b/t/t6042-merge-rename-corner-cases.sh
@@ -352,7 +352,7 @@ test_expect_success 'rename/directory conflict + content merge conflict' '
 			base:file   left-conflict:newfile  right:file &&
 		git rev-parse >actual                                 \
 			:1:newfile  :2:newfile             :3:newfile &&
-		test_cmp expect actual
+		test_cmp expect actual &&
 
 		test_path_is_file newfile/realfile &&
 		test_path_is_file newfile~HEAD
@@ -580,7 +580,7 @@ test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge'
 			C:a   A:a   B:b   C:C &&
 		git rev-parse >actual          \
 			:3:a  :1:a  :2:b  :3:c &&
-		test_cmp expect actual
+		test_cmp expect actual &&
 
 		test_path_is_file a &&
 		test_path_is_file b &&
@@ -680,13 +680,13 @@ test_expect_success 'rename/rename/add-dest merge still knows about conflicting
 			A:a   C:b   B:b   C:c   B:c &&
 		git rev-parse >actual                \
 			:1:a  :2:b  :3:b  :2:c  :3:c &&
-		test_cmp expect actual
+		test_cmp expect actual &&
 
 		git rev-parse >expect               \
 			C:c     B:c     C:b     B:b &&
 		git hash-object >actual                \
 			c~HEAD  c~B\^0  b~HEAD  b~B\^0 &&
-		test_cmp expect actual
+		test_cmp expect actual &&
 
 		test_path_is_missing b &&
 		test_path_is_missing c
diff --git a/t/t6043-merge-rename-directories.sh b/t/t6043-merge-rename-directories.sh
index 2e28f2908d..4a71f17edd 100755
--- a/t/t6043-merge-rename-directories.sh
+++ b/t/t6043-merge-rename-directories.sh
@@ -3583,7 +3583,7 @@ test_expect_success '11d-check: Avoid losing not-uptodate with rename + D/F conf
 		grep -q stuff z/c &&
 		test_seq 1 10 >expected &&
 		echo stuff >>expected &&
-		test_cmp expected z/c
+		test_cmp expected z/c &&
 
 		git ls-files -s >out &&
 		test_line_count = 4 out &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 26/29] t7000-t7999: fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (24 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 25/29] t6000-t6999: " Eric Sunshine
@ 2018-06-26  7:29 ` " Eric Sunshine
  2018-06-26  7:29 ` [PATCH 27/29] t9000-t9999: " Eric Sunshine
                   ` (5 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t7001-mv.sh                  |  2 +-
 t/t7201-co.sh                  | 40 +++++++++++++-------------
 t/t7400-submodule-basic.sh     |  2 +-
 t/t7406-submodule-update.sh    |  4 +--
 t/t7408-submodule-reference.sh |  2 +-
 t/t7501-commit.sh              | 52 +++++++++++++++++-----------------
 t/t7506-status-submodule.sh    | 10 +++----
 7 files changed, 56 insertions(+), 56 deletions(-)

diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index cc3fd2baf2..9e59e5a5dd 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -509,7 +509,7 @@ test_expect_success 'moving nested submodules' '
 		touch nested_level1 &&
 		git init &&
 		git add . &&
-		git commit -m "nested level 1"
+		git commit -m "nested level 1" &&
 		git submodule add ../sub_nested_nested &&
 		git commit -m "add nested level 2"
 	) &&
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 8d8a63a24b..94cb039a03 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -528,10 +528,10 @@ test_expect_success 'checkout with --merge' '
 	cat sample >filf &&
 	git checkout -m -- fild file filf &&
 	(
-		echo "<<<<<<< ours"
-		echo ourside
-		echo "======="
-		echo theirside
+		echo "<<<<<<< ours" &&
+		echo ourside &&
+		echo "=======" &&
+		echo theirside &&
 		echo ">>>>>>> theirs"
 	) >merged &&
 	test_cmp expect fild &&
@@ -549,12 +549,12 @@ test_expect_success 'checkout with --merge, in diff3 -m style' '
 	cat sample >filf &&
 	git checkout -m -- fild file filf &&
 	(
-		echo "<<<<<<< ours"
-		echo ourside
-		echo "||||||| base"
-		echo original
-		echo "======="
-		echo theirside
+		echo "<<<<<<< ours" &&
+		echo ourside &&
+		echo "||||||| base" &&
+		echo original &&
+		echo "=======" &&
+		echo theirside &&
 		echo ">>>>>>> theirs"
 	) >merged &&
 	test_cmp expect fild &&
@@ -572,10 +572,10 @@ test_expect_success 'checkout --conflict=merge, overriding config' '
 	cat sample >filf &&
 	git checkout --conflict=merge -- fild file filf &&
 	(
-		echo "<<<<<<< ours"
-		echo ourside
-		echo "======="
-		echo theirside
+		echo "<<<<<<< ours" &&
+		echo ourside &&
+		echo "=======" &&
+		echo theirside &&
 		echo ">>>>>>> theirs"
 	) >merged &&
 	test_cmp expect fild &&
@@ -593,12 +593,12 @@ test_expect_success 'checkout --conflict=diff3' '
 	cat sample >filf &&
 	git checkout --conflict=diff3 -- fild file filf &&
 	(
-		echo "<<<<<<< ours"
-		echo ourside
-		echo "||||||| base"
-		echo original
-		echo "======="
-		echo theirside
+		echo "<<<<<<< ours" &&
+		echo ourside &&
+		echo "||||||| base" &&
+		echo original &&
+		echo "=======" &&
+		echo theirside &&
 		echo ">>>>>>> theirs"
 	) >merged &&
 	test_cmp expect fild &&
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 401adaed32..76cf522a08 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -818,7 +818,7 @@ test_expect_success '../bar/a/b/c works with relative local path - ../foo/bar.gi
 		cp pristine-.git-config .git/config &&
 		cp pristine-.gitmodules .gitmodules &&
 		mkdir -p a/b/c &&
-		(cd a/b/c; git init) &&
+		(cd a/b/c && git init) &&
 		git config remote.origin.url ../foo/bar.git &&
 		git submodule add ../bar/a/b/c ./a/b/c &&
 		git submodule init &&
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 9e0d31700e..b141145fc2 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -865,9 +865,9 @@ test_expect_success 'submodule update places git-dir in superprojects git-dir re
 	 (cd submodule/subsubmodule &&
 	  git log > ../../expected
 	 ) &&
-	 (cd .git/modules/submodule/modules/subsubmodule
+	 (cd .git/modules/submodule/modules/subsubmodule &&
 	  git log > ../../../../../actual
-	 )
+	 ) &&
 	 test_cmp actual expected
 	)
 '
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index 08d9add05e..34ac28c056 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -148,7 +148,7 @@ test_expect_success 'preparing second superproject with a nested submodule plus
 		cd supersuper &&
 		echo "I am super super." >file &&
 		git add file &&
-		git commit -m B-super-super-initial
+		git commit -m B-super-super-initial &&
 		git submodule add "file://$base_dir/super" subwithsub &&
 		git commit -m B-super-super-added &&
 		git submodule update --init --recursive &&
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index 589b6cea23..39b14b2bdb 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -411,8 +411,8 @@ test_expect_success 'sign off (1)' '
 	git commit -s -m "thank you" &&
 	git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
 	(
-		echo thank you
-		echo
+		echo thank you &&
+		echo &&
 		git var GIT_COMMITTER_IDENT |
 		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
 	) >expected &&
@@ -430,9 +430,9 @@ test_expect_success 'sign off (2)' '
 $existing" &&
 	git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
 	(
-		echo thank you
-		echo
-		echo $existing
+		echo thank you &&
+		echo &&
+		echo $existing &&
 		git var GIT_COMMITTER_IDENT |
 		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
 	) >expected &&
@@ -450,9 +450,9 @@ test_expect_success 'signoff gap' '
 $alt" &&
 	git cat-file commit HEAD | sed -e "1,/^\$/d" > actual &&
 	(
-		echo welcome
-		echo
-		echo $alt
+		echo welcome &&
+		echo &&
+		echo $alt &&
 		git var GIT_COMMITTER_IDENT |
 		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
 	) >expected &&
@@ -470,11 +470,11 @@ We have now
 $alt" &&
 	git cat-file commit HEAD | sed -e "1,/^\$/d" > actual &&
 	(
-		echo welcome
-		echo
-		echo We have now
-		echo $alt
-		echo
+		echo welcome &&
+		echo &&
+		echo We have now &&
+		echo $alt &&
+		echo &&
 		git var GIT_COMMITTER_IDENT |
 		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
 	) >expected &&
@@ -491,11 +491,11 @@ non-trailer line
 Myfooter: x" &&
 	git cat-file commit HEAD | sed -e "1,/^\$/d" > actual &&
 	(
-		echo subject
-		echo
-		echo non-trailer line
-		echo Myfooter: x
-		echo
+		echo subject &&
+		echo &&
+		echo non-trailer line &&
+		echo Myfooter: x &&
+		echo &&
 		echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
 	) >expected &&
 	test_cmp expected actual &&
@@ -508,10 +508,10 @@ non-trailer line
 Myfooter: x" &&
 	git cat-file commit HEAD | sed -e "1,/^\$/d" > actual &&
 	(
-		echo subject
-		echo
-		echo non-trailer line
-		echo Myfooter: x
+		echo subject &&
+		echo &&
+		echo non-trailer line &&
+		echo Myfooter: x &&
 		echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
 	) >expected &&
 	test_cmp expected actual
@@ -524,10 +524,10 @@ test_expect_success 'multiple -m' '
 	git commit -m "one" -m "two" -m "three" &&
 	git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
 	(
-		echo one
-		echo
-		echo two
-		echo
+		echo one &&
+		echo &&
+		echo two &&
+		echo &&
 		echo three
 	) >expected &&
 	test_cmp expected actual
diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh
index b4b74dbe29..943708fb04 100755
--- a/t/t7506-status-submodule.sh
+++ b/t/t7506-status-submodule.sh
@@ -193,9 +193,9 @@ test_expect_success 'status with added and untracked file in modified submodule
 
 test_expect_success 'setup .git file for sub' '
 	(cd sub &&
-	 rm -f new-file
+	 rm -f new-file &&
 	 REAL="$(pwd)/../.real" &&
-	 mv .git "$REAL"
+	 mv .git "$REAL" &&
 	 echo "gitdir: $REAL" >.git) &&
 	 echo .real >>.gitignore &&
 	 git commit -m "added .real to .gitignore" .gitignore
@@ -209,12 +209,12 @@ test_expect_success 'status with added file in modified submodule with .git file
 
 test_expect_success 'status with a lot of untracked files in the submodule' '
 	(
-		cd sub
+		cd sub &&
 		i=0 &&
 		while test $i -lt 1024
 		do
-			>some-file-$i
-			i=$(( $i + 1 ))
+			>some-file-$i &&
+			i=$(( $i + 1 )) || exit 1
 		done
 	) &&
 	git status --porcelain sub 2>err.actual &&
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 27/29] t9000-t9999: fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (25 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 26/29] t7000-t7999: " Eric Sunshine
@ 2018-06-26  7:29 ` " Eric Sunshine
  2018-06-26  7:30 ` [PATCH 28/29] t9119: " Eric Sunshine
                   ` (4 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:29 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t9001-send-email.sh                           |  6 +++---
 t/t9100-git-svn-basic.sh                        |  2 +-
 t/t9101-git-svn-props.sh                        |  2 +-
 t/t9122-git-svn-author.sh                       |  6 +++---
 t/t9129-git-svn-i18n-commitencoding.sh          |  2 +-
 t/t9130-git-svn-authors-file.sh                 |  4 ++--
 t/t9134-git-svn-ignore-paths.sh                 |  6 +++---
 t/t9137-git-svn-dcommit-clobber-series.sh       |  2 +-
 t/t9138-git-svn-authors-prog.sh                 |  6 +++---
 t/t9146-git-svn-empty-dirs.sh                   | 12 ++++++------
 t/t9147-git-svn-include-paths.sh                |  6 +++---
 t/t9164-git-svn-dcommit-concurrent.sh           |  2 +-
 t/t9165-git-svn-fetch-merge-branch-of-branch.sh |  2 +-
 t/t9200-git-cvsexportcommit.sh                  |  6 +++---
 t/t9400-git-cvsserver-server.sh                 |  6 +++---
 t/t9600-cvsimport.sh                            |  2 +-
 t/t9806-git-p4-options.sh                       |  2 +-
 t/t9810-git-p4-rcs.sh                           |  2 +-
 t/t9811-git-p4-label-import.sh                  |  2 +-
 t/t9815-git-p4-submit-fail.sh                   |  2 +-
 t/t9830-git-p4-symlink-dir.sh                   |  2 +-
 t/t9831-git-p4-triggers.sh                      |  2 +-
 t/t9902-completion.sh                           |  4 ++--
 t/t9903-bash-prompt.sh                          |  2 +-
 24 files changed, 45 insertions(+), 45 deletions(-)

diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 776769fe0d..53314ff54e 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -330,7 +330,7 @@ test_expect_success $PREREQ 'Show all headers' '
 
 test_expect_success $PREREQ 'Prompting works' '
 	clean_fake_sendmail &&
-	(echo "to@example.com"
+	(echo "to@example.com" &&
 	 echo ""
 	) | GIT_SEND_EMAIL_NOTTY=1 git send-email \
 		--smtp-server="$(pwd)/fake.sendmail" \
@@ -470,8 +470,8 @@ test_expect_success $PREREQ 'Invalid In-Reply-To' '
 
 test_expect_success $PREREQ 'Valid In-Reply-To when prompting' '
 	clean_fake_sendmail &&
-	(echo "From Example <from@example.com>"
-	 echo "To Example <to@example.com>"
+	(echo "From Example <from@example.com>" &&
+	 echo "To Example <to@example.com>" &&
 	 echo ""
 	) | GIT_SEND_EMAIL_NOTTY=1 git send-email \
 		--smtp-server="$(pwd)/fake.sendmail" \
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index c937330a5f..9af6078844 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -31,7 +31,7 @@ test_expect_success \
 	(
 		cd import &&
 		echo foo >foo &&
-		ln -s foo foo.link
+		ln -s foo foo.link &&
 		mkdir -p dir/a/b/c/d/e &&
 		echo "deep dir" >dir/a/b/c/d/e/file &&
 		mkdir bar &&
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index 07bfb63777..8a5c8dc1aa 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -149,7 +149,7 @@ test_expect_success 'test show-ignore' "
 		svn_cmd up &&
 		svn_cmd propset -R svn:ignore '
 no-such-file*
-' .
+' . &&
 		svn_cmd commit -m 'propset svn:ignore'
 	) &&
 	git svn show-ignore > show-ignore.got &&
diff --git a/t/t9122-git-svn-author.sh b/t/t9122-git-svn-author.sh
index 30013b7bb9..9e8fe38e7e 100755
--- a/t/t9122-git-svn-author.sh
+++ b/t/t9122-git-svn-author.sh
@@ -7,8 +7,8 @@ test_expect_success 'setup svn repository' '
 	svn_cmd checkout "$svnrepo" work.svn &&
 	(
 		cd work.svn &&
-		echo >file
-		svn_cmd add file
+		echo >file &&
+		svn_cmd add file &&
 		svn_cmd commit -m "first commit" file
 	)
 '
@@ -17,7 +17,7 @@ test_expect_success 'interact with it via git svn' '
 	mkdir work.git &&
 	(
 		cd work.git &&
-		git svn init "$svnrepo"
+		git svn init "$svnrepo" &&
 		git svn fetch &&
 
 		echo modification >file &&
diff --git a/t/t9129-git-svn-i18n-commitencoding.sh b/t/t9129-git-svn-i18n-commitencoding.sh
index 8dbd6476fa..2c213ae654 100755
--- a/t/t9129-git-svn-i18n-commitencoding.sh
+++ b/t/t9129-git-svn-i18n-commitencoding.sh
@@ -51,7 +51,7 @@ do
 		git add F &&
 		git commit -a -F "$TEST_DIRECTORY"/t3900/$H.txt &&
 		E=$(git cat-file commit HEAD | sed -ne "s/^encoding //p") &&
-		test "z$E" = "z$H"
+		test "z$E" = "z$H" &&
 		compare_git_head_with "$TEST_DIRECTORY"/t3900/$H.txt
 	)
 	'
diff --git a/t/t9130-git-svn-authors-file.sh b/t/t9130-git-svn-authors-file.sh
index d8262854bb..cb764bcadc 100755
--- a/t/t9130-git-svn-authors-file.sh
+++ b/t/t9130-git-svn-authors-file.sh
@@ -25,7 +25,7 @@ test_expect_success 'start import with incomplete authors file' '
 
 test_expect_success 'imported 2 revisions successfully' '
 	(
-		cd x
+		cd x &&
 		git rev-list refs/remotes/git-svn >actual &&
 		test_line_count = 2 actual &&
 		git rev-list -1 --pretty=raw refs/remotes/git-svn >actual &&
@@ -42,7 +42,7 @@ EOF
 
 test_expect_success 'continues to import once authors have been added' '
 	(
-		cd x
+		cd x &&
 		git svn fetch --authors-file=../svn-authors &&
 		git rev-list refs/remotes/git-svn >actual &&
 		test_line_count = 4 actual &&
diff --git a/t/t9134-git-svn-ignore-paths.sh b/t/t9134-git-svn-ignore-paths.sh
index 09ff10cd9b..fff49c4100 100755
--- a/t/t9134-git-svn-ignore-paths.sh
+++ b/t/t9134-git-svn-ignore-paths.sh
@@ -82,7 +82,7 @@ test_expect_success 'update git svn-cloned repo (option ignore)' '
 test_expect_success 'SVN-side change inside of ignored www' '
 	(
 		cd s &&
-		echo zaq >> www/test_www.txt
+		echo zaq >> www/test_www.txt &&
 		svn_cmd commit -m "SVN-side change inside of www/test_www.txt" &&
 		svn_cmd up &&
 		svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt"
@@ -114,8 +114,8 @@ test_expect_success 'update git svn-cloned repo (option ignore)' '
 test_expect_success 'SVN-side change in and out of ignored www' '
 	(
 		cd s &&
-		echo cvf >> www/test_www.txt
-		echo ygg >> qqq/test_qqq.txt
+		echo cvf >> www/test_www.txt &&
+		echo ygg >> qqq/test_qqq.txt &&
 		svn_cmd commit -m "SVN-side change in and out of ignored www" &&
 		svn_cmd up &&
 		svn_cmd log -v | fgrep "SVN-side change in and out of ignored www"
diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
index 5fa07a369f..067b15bad2 100755
--- a/t/t9137-git-svn-dcommit-clobber-series.sh
+++ b/t/t9137-git-svn-dcommit-clobber-series.sh
@@ -7,7 +7,7 @@ test_description='git svn dcommit clobber series'
 test_expect_success 'initialize repo' '
 	mkdir import &&
 	(cd import &&
-	awk "BEGIN { for (i = 1; i < 64; i++) { print i } }" > file
+	awk "BEGIN { for (i = 1; i < 64; i++) { print i } }" > file &&
 	svn_cmd import -m "initial" . "$svnrepo"
 	) &&
 	git svn init "$svnrepo" &&
diff --git a/t/t9138-git-svn-authors-prog.sh b/t/t9138-git-svn-authors-prog.sh
index 93ef44fae8..027b416720 100755
--- a/t/t9138-git-svn-authors-prog.sh
+++ b/t/t9138-git-svn-authors-prog.sh
@@ -38,7 +38,7 @@ test_expect_success 'import authors with prog and file' '
 
 test_expect_success 'imported 6 revisions successfully' '
 	(
-		cd x
+		cd x &&
 		git rev-list refs/remotes/git-svn >actual &&
 		test_line_count = 6 actual
 	)
@@ -46,7 +46,7 @@ test_expect_success 'imported 6 revisions successfully' '
 
 test_expect_success 'authors-prog ran correctly' '
 	(
-		cd x
+		cd x &&
 		git rev-list -1 --pretty=raw refs/remotes/git-svn~1 >actual &&
 		grep "^author ee-foo <ee-foo@example\.com> " actual &&
 		git rev-list -1 --pretty=raw refs/remotes/git-svn~2 >actual &&
@@ -62,7 +62,7 @@ test_expect_success 'authors-prog ran correctly' '
 
 test_expect_success 'authors-file overrode authors-prog' '
 	(
-		cd x
+		cd x &&
 		git rev-list -1 --pretty=raw refs/remotes/git-svn >actual &&
 		grep "^author FFFFFFF FFFFFFF <fFf@other\.example\.com> " actual
 	)
diff --git a/t/t9146-git-svn-empty-dirs.sh b/t/t9146-git-svn-empty-dirs.sh
index 6d3130e618..954948812c 100755
--- a/t/t9146-git-svn-empty-dirs.sh
+++ b/t/t9146-git-svn-empty-dirs.sh
@@ -79,21 +79,21 @@ test_expect_success 'git svn mkdirs -r works' '
 		do
 			if ! test -d "$i"
 			then
-				echo >&2 "$i does not exist"
+				echo >&2 "$i does not exist" &&
 				exit 1
 			fi
-		done
+		done &&
 
 		if test -d "! !"
 		then
-			echo >&2 "$i should not exist"
+			echo >&2 "$i should not exist" &&
 			exit 1
-		fi
+		fi &&
 
 		git svn mkdirs -r8 &&
 		if ! test -d "! !"
 		then
-			echo >&2 "$i not exist"
+			echo >&2 "$i not exist" &&
 			exit 1
 		fi
 	)
@@ -115,7 +115,7 @@ test_expect_success 'empty directories in trunk exist' '
 		do
 			if ! test -d "$i"
 			then
-				echo >&2 "$i does not exist"
+				echo >&2 "$i does not exist" &&
 				exit 1
 			fi
 		done
diff --git a/t/t9147-git-svn-include-paths.sh b/t/t9147-git-svn-include-paths.sh
index a90ff58629..d292bf9f55 100755
--- a/t/t9147-git-svn-include-paths.sh
+++ b/t/t9147-git-svn-include-paths.sh
@@ -84,7 +84,7 @@ test_expect_success 'update git svn-cloned repo (option include)' '
 test_expect_success 'SVN-side change inside of ignored www' '
 	(
 		cd s &&
-		echo zaq >> www/test_www.txt
+		echo zaq >> www/test_www.txt &&
 		svn_cmd commit -m "SVN-side change inside of www/test_www.txt" &&
 		svn_cmd up &&
 		svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt"
@@ -116,8 +116,8 @@ test_expect_success 'update git svn-cloned repo (option include)' '
 test_expect_success 'SVN-side change in and out of included qqq' '
 	(
 		cd s &&
-		echo cvf >> www/test_www.txt
-		echo ygg >> qqq/test_qqq.txt
+		echo cvf >> www/test_www.txt &&
+		echo ygg >> qqq/test_qqq.txt &&
 		svn_cmd commit -m "SVN-side change in and out of ignored www" &&
 		svn_cmd up &&
 		svn_cmd log -v | fgrep "SVN-side change in and out of ignored www"
diff --git a/t/t9164-git-svn-dcommit-concurrent.sh b/t/t9164-git-svn-dcommit-concurrent.sh
index d8464d4218..90346ff4e9 100755
--- a/t/t9164-git-svn-dcommit-concurrent.sh
+++ b/t/t9164-git-svn-dcommit-concurrent.sh
@@ -12,7 +12,7 @@ test_expect_success 'setup svn repository' '
 	svn_cmd checkout "$svnrepo" work.svn &&
 	(
 		cd work.svn &&
-		echo >file && echo > auto_updated_file
+		echo >file && echo > auto_updated_file &&
 		svn_cmd add file auto_updated_file &&
 		svn_cmd commit -m "initial commit"
 	) &&
diff --git a/t/t9165-git-svn-fetch-merge-branch-of-branch.sh b/t/t9165-git-svn-fetch-merge-branch-of-branch.sh
index fa3ef3b1f7..a4813c2b09 100755
--- a/t/t9165-git-svn-fetch-merge-branch-of-branch.sh
+++ b/t/t9165-git-svn-fetch-merge-branch-of-branch.sh
@@ -39,7 +39,7 @@ test_expect_success 'initialize source svn repo' '
 		svn_cmd commit -m trunk &&
 		svn_cmd switch "$svnrepo"/branches/branch2 &&
 		svn_cmd merge "$svnrepo"/trunk &&
-		svn_cmd commit -m "merge trunk"
+		svn_cmd commit -m "merge trunk" &&
 		svn_cmd switch "$svnrepo"/trunk &&
 		svn_cmd merge --reintegrate "$svnrepo"/branches/branch2 &&
 		svn_cmd commit -m "merge branch2"
diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh
index 1319415ba8..cd61288aa1 100755
--- a/t/t9200-git-cvsexportcommit.sh
+++ b/t/t9200-git-cvsexportcommit.sh
@@ -187,7 +187,7 @@ test_expect_success \
       git commit -a -m "Update with spaces" &&
       id=$(git rev-list --max-count=1 HEAD) &&
       (cd "$CVSWORK" &&
-      git cvsexportcommit -c $id
+      git cvsexportcommit -c $id &&
       check_entries "G g" "with spaces.png/1.2/-kb|with spaces.txt/1.2/"
       )'
 
@@ -245,7 +245,7 @@ test_expect_success FILEMODE \
       git add G/off &&
       git commit -a -m "Execute test" &&
       (cd "$CVSWORK" &&
-      git cvsexportcommit -c HEAD
+      git cvsexportcommit -c HEAD &&
       test -x G/on &&
       ! test -x G/off
       )'
@@ -303,7 +303,7 @@ test_expect_success 're-commit a removed filename which remains in CVS attic' '
     git add attic_gremlin &&
     git commit -m "Added attic_gremlin" &&
 	git cvsexportcommit -w "$CVSWORK" -c HEAD &&
-    (cd "$CVSWORK"; cvs -Q update -d) &&
+    (cd "$CVSWORK" && cvs -Q update -d) &&
     test -f "$CVSWORK/attic_gremlin"
 '
 
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index 06742748e9..4207e9caa5 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -371,7 +371,7 @@ test_expect_success 'cvs update (merge)' \
   'echo Line 0 >expected &&
    for i in 1 2 3 4 5 6 7
    do
-     echo Line $i >>merge
+     echo Line $i >>merge &&
      echo Line $i >>expected
    done &&
    echo Line 8 >>expected &&
@@ -382,7 +382,7 @@ test_expect_success 'cvs update (merge)' \
    GIT_CONFIG="$git_config" cvs -Q update &&
    test "$(echo $(grep merge CVS/Entries|cut -d/ -f2,3,5))" = "merge/1.1/" &&
    test_cmp merge ../merge &&
-   ( echo Line 0; cat merge ) >merge.tmp &&
+   ( echo Line 0 && cat merge ) >merge.tmp &&
    mv merge.tmp merge &&
    cd "$WORKDIR" &&
    echo Line 8 >>merge &&
@@ -410,7 +410,7 @@ do
 done
 
 test_expect_success 'cvs update (conflict merge)' \
-  '( echo LINE 0; cat merge ) >merge.tmp &&
+  '( echo LINE 0 && cat merge ) >merge.tmp &&
    mv merge.tmp merge &&
    git add merge &&
    git commit -q -m "Merge test (conflict)" &&
diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh
index 804ce3850f..5dfee07d9a 100755
--- a/t/t9600-cvsimport.sh
+++ b/t/t9600-cvsimport.sh
@@ -135,7 +135,7 @@ test_expect_success PERL 'second update has correct .git/cvs-revisions' '
 
 	(cd module-git &&
 	 git log --format="o_fortuna 1.1 %H" -1 HEAD^^ &&
-	 git log --format="o_fortuna 1.2 %H" -1 HEAD^
+	 git log --format="o_fortuna 1.2 %H" -1 HEAD^ &&
 	 git log --format="tick 1.1 %H" -1 HEAD) > expected &&
 	test_cmp expected module-git/.git/cvs-revisions
 '
diff --git a/t/t9806-git-p4-options.sh b/t/t9806-git-p4-options.sh
index 1ab76c4246..3f5291b857 100755
--- a/t/t9806-git-p4-options.sh
+++ b/t/t9806-git-p4-options.sh
@@ -134,7 +134,7 @@ test_expect_success 'clone --changesfile' '
 	(
 		cd "$git" &&
 		git log --oneline p4/master >lines &&
-		test_line_count = 2 lines
+		test_line_count = 2 lines &&
 		test_path_is_file file1 &&
 		test_path_is_missing file2 &&
 		test_path_is_file file3
diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh
index 8134ab439b..cc53debe19 100755
--- a/t/t9810-git-p4-rcs.sh
+++ b/t/t9810-git-p4-rcs.sh
@@ -161,7 +161,7 @@ test_expect_success 'cleanup after failure' '
 test_expect_success 'ktext expansion should not expand multi-line $File::' '
 	(
 		cd "$cli" &&
-		cat >lv.pm <<-\EOF
+		cat >lv.pm <<-\EOF &&
 		my $wanted = sub { my $f = $File::Find::name;
 				    if ( -f && $f =~ /foo/ ) {
 		EOF
diff --git a/t/t9811-git-p4-label-import.sh b/t/t9811-git-p4-label-import.sh
index decb66ba30..602b0a5d5c 100755
--- a/t/t9811-git-p4-label-import.sh
+++ b/t/t9811-git-p4-label-import.sh
@@ -133,7 +133,7 @@ test_expect_success 'export git tags to p4' '
 		p4 labels ... | grep LIGHTWEIGHT_TAG &&
 		p4 label -o GIT_TAG_1 | grep "tag created in git:xyzzy" &&
 		p4 sync ...@GIT_TAG_1 &&
-		! test -f main/f10
+		! test -f main/f10 &&
 		p4 sync ...@GIT_TAG_2 &&
 		test -f main/f10
 	)
diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh
index 37b42d03a2..eaf03a6563 100755
--- a/t/t9815-git-p4-submit-fail.sh
+++ b/t/t9815-git-p4-submit-fail.sh
@@ -394,7 +394,7 @@ test_expect_success 'cleanup rename after submit cancel' '
 	(
 		cd "$cli" &&
 		test_path_is_missing text2 &&
-		p4 fstat -T action text2 2>&1 | grep "no such file"
+		p4 fstat -T action text2 2>&1 | grep "no such file" &&
 		test_path_is_file text &&
 		! p4 fstat -T action text
 	)
diff --git a/t/t9830-git-p4-symlink-dir.sh b/t/t9830-git-p4-symlink-dir.sh
index 3dc528bb1e..2ad1b0810d 100755
--- a/t/t9830-git-p4-symlink-dir.sh
+++ b/t/t9830-git-p4-symlink-dir.sh
@@ -30,7 +30,7 @@ test_expect_success 'symlinked directory' '
 	(
 		cd "$cli" &&
 		p4 sync &&
-		test -L some/sub/directory/subdir2
+		test -L some/sub/directory/subdir2 &&
 		test_path_is_file some/sub/directory/subdir2/file.t
 	)
 
diff --git a/t/t9831-git-p4-triggers.sh b/t/t9831-git-p4-triggers.sh
index bbcf14c664..be44c9751a 100755
--- a/t/t9831-git-p4-triggers.sh
+++ b/t/t9831-git-p4-triggers.sh
@@ -13,7 +13,7 @@ test_expect_success 'init depot' '
 		cd "$cli" &&
 		echo file1 >file1 &&
 		p4 add file1 &&
-		p4 submit -d "change 1"
+		p4 submit -d "change 1" &&
 		echo file2 >file2 &&
 		p4 add file2 &&
 		p4 submit -d "change 2"
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index a28640ce1a..69a5810555 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -1067,7 +1067,7 @@ test_expect_success '__git_complete_refs - remote' '
 	master-in-other Z
 	EOF
 	(
-		cur=
+		cur= &&
 		__git_complete_refs --remote=other &&
 		print_comp
 	) &&
@@ -1086,7 +1086,7 @@ test_expect_success '__git_complete_refs - track' '
 	master-in-other Z
 	EOF
 	(
-		cur=
+		cur= &&
 		__git_complete_refs --track &&
 		print_comp
 	) &&
diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh
index c3b89ae783..04440685a6 100755
--- a/t/t9903-bash-prompt.sh
+++ b/t/t9903-bash-prompt.sh
@@ -529,7 +529,7 @@ test_expect_success 'prompt - bash color pc mode - branch name' '
 	printf "BEFORE: (${c_green}\${__git_ps1_branch_name}${c_clear}):AFTER\\nmaster" >expected &&
 	(
 		GIT_PS1_SHOWCOLORHINTS=y &&
-		__git_ps1 "BEFORE:" ":AFTER" >"$actual"
+		__git_ps1 "BEFORE:" ":AFTER" >"$actual" &&
 		printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
 	) &&
 	test_cmp expected "$actual"
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 28/29] t9119: fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (26 preceding siblings ...)
  2018-06-26  7:29 ` [PATCH 27/29] t9000-t9999: " Eric Sunshine
@ 2018-06-26  7:30 ` " Eric Sunshine
  2018-06-26  7:30 ` [PATCH 29/29] t/test-lib: teach --chain-lint to detect " Eric Sunshine
                   ` (3 subsequent siblings)
  31 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:30 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t9119-git-svn-info.sh | 120 ++++++++++++++++++++--------------------
 1 file changed, 60 insertions(+), 60 deletions(-)

diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh
index 88241baee3..8201c3e808 100755
--- a/t/t9119-git-svn-info.sh
+++ b/t/t9119-git-svn-info.sh
@@ -22,8 +22,8 @@ esac
 # same value as "svn info" (i.e. the commit timestamp that touched the
 # path most recently); do not expect that field to match.
 test_cmp_info () {
-	sed -e '/^Text Last Updated:/d' "$1" >tmp.expect
-	sed -e '/^Text Last Updated:/d' "$2" >tmp.actual
+	sed -e '/^Text Last Updated:/d' "$1" >tmp.expect &&
+	sed -e '/^Text Last Updated:/d' "$2" >tmp.actual &&
 	test_cmp tmp.expect tmp.actual &&
 	rm -f tmp.expect tmp.actual
 }
@@ -59,24 +59,24 @@ test_expect_success 'setup repository and import' '
 	'
 
 test_expect_success 'info' "
-	(cd svnwc; svn info) > expected.info &&
-	(cd gitwc; git svn info) > actual.info &&
+	(cd svnwc && svn info) > expected.info &&
+	(cd gitwc && git svn info) > actual.info &&
 	test_cmp_info expected.info actual.info
 	"
 
 test_expect_success 'info --url' '
-	test "$(cd gitwc; git svn info --url)" = "$quoted_svnrepo"
+	test "$(cd gitwc && git svn info --url)" = "$quoted_svnrepo"
 	'
 
 test_expect_success 'info .' "
-	(cd svnwc; svn info .) > expected.info-dot &&
-	(cd gitwc; git svn info .) > actual.info-dot &&
+	(cd svnwc && svn info .) > expected.info-dot &&
+	(cd gitwc && git svn info .) > actual.info-dot &&
 	test_cmp_info expected.info-dot actual.info-dot
 	"
 
 test_expect_success 'info $(pwd)' '
-	(cd svnwc; svn info "$(pwd)") >expected.info-pwd &&
-	(cd gitwc; git svn info "$(pwd)") >actual.info-pwd &&
+	(cd svnwc && svn info "$(pwd)") >expected.info-pwd &&
+	(cd gitwc && git svn info "$(pwd)") >actual.info-pwd &&
 	grep -v ^Path: <expected.info-pwd >expected.info-np &&
 	grep -v ^Path: <actual.info-pwd >actual.info-np &&
 	test_cmp_info expected.info-np actual.info-np &&
@@ -85,8 +85,8 @@ test_expect_success 'info $(pwd)' '
 	'
 
 test_expect_success 'info $(pwd)/../___wc' '
-	(cd svnwc; svn info "$(pwd)/../svnwc") >expected.info-pwd &&
-	(cd gitwc; git svn info "$(pwd)/../gitwc") >actual.info-pwd &&
+	(cd svnwc && svn info "$(pwd)/../svnwc") >expected.info-pwd &&
+	(cd gitwc && git svn info "$(pwd)/../gitwc") >actual.info-pwd &&
 	grep -v ^Path: <expected.info-pwd >expected.info-np &&
 	grep -v ^Path: <actual.info-pwd >actual.info-np &&
 	test_cmp_info expected.info-np actual.info-np &&
@@ -95,8 +95,8 @@ test_expect_success 'info $(pwd)/../___wc' '
 	'
 
 test_expect_success 'info $(pwd)/../___wc//file' '
-	(cd svnwc; svn info "$(pwd)/../svnwc//file") >expected.info-pwd &&
-	(cd gitwc; git svn info "$(pwd)/../gitwc//file") >actual.info-pwd &&
+	(cd svnwc && svn info "$(pwd)/../svnwc//file") >expected.info-pwd &&
+	(cd gitwc && git svn info "$(pwd)/../gitwc//file") >actual.info-pwd &&
 	grep -v ^Path: <expected.info-pwd >expected.info-np &&
 	grep -v ^Path: <actual.info-pwd >actual.info-np &&
 	test_cmp_info expected.info-np actual.info-np &&
@@ -105,56 +105,56 @@ test_expect_success 'info $(pwd)/../___wc//file' '
 	'
 
 test_expect_success 'info --url .' '
-	test "$(cd gitwc; git svn info --url .)" = "$quoted_svnrepo"
+	test "$(cd gitwc && git svn info --url .)" = "$quoted_svnrepo"
 	'
 
 test_expect_success 'info file' "
-	(cd svnwc; svn info file) > expected.info-file &&
-	(cd gitwc; git svn info file) > actual.info-file &&
+	(cd svnwc && svn info file) > expected.info-file &&
+	(cd gitwc && git svn info file) > actual.info-file &&
 	test_cmp_info expected.info-file actual.info-file
 	"
 
 test_expect_success 'info --url file' '
-	test "$(cd gitwc; git svn info --url file)" = "$quoted_svnrepo/file"
+	test "$(cd gitwc && git svn info --url file)" = "$quoted_svnrepo/file"
 	'
 
 test_expect_success 'info directory' "
-	(cd svnwc; svn info directory) > expected.info-directory &&
-	(cd gitwc; git svn info directory) > actual.info-directory &&
+	(cd svnwc && svn info directory) > expected.info-directory &&
+	(cd gitwc && git svn info directory) > actual.info-directory &&
 	test_cmp_info expected.info-directory actual.info-directory
 	"
 
 test_expect_success 'info inside directory' "
-	(cd svnwc/directory; svn info) > expected.info-inside-directory &&
-	(cd gitwc/directory; git svn info) > actual.info-inside-directory &&
+	(cd svnwc/directory && svn info) > expected.info-inside-directory &&
+	(cd gitwc/directory && git svn info) > actual.info-inside-directory &&
 	test_cmp_info expected.info-inside-directory actual.info-inside-directory
 	"
 
 test_expect_success 'info --url directory' '
-	test "$(cd gitwc; git svn info --url directory)" = "$quoted_svnrepo/directory"
+	test "$(cd gitwc && git svn info --url directory)" = "$quoted_svnrepo/directory"
 	'
 
 test_expect_success 'info symlink-file' "
-	(cd svnwc; svn info symlink-file) > expected.info-symlink-file &&
-	(cd gitwc; git svn info symlink-file) > actual.info-symlink-file &&
+	(cd svnwc && svn info symlink-file) > expected.info-symlink-file &&
+	(cd gitwc && git svn info symlink-file) > actual.info-symlink-file &&
 	test_cmp_info expected.info-symlink-file actual.info-symlink-file
 	"
 
 test_expect_success 'info --url symlink-file' '
-	test "$(cd gitwc; git svn info --url symlink-file)" \
+	test "$(cd gitwc && git svn info --url symlink-file)" \
 	     = "$quoted_svnrepo/symlink-file"
 	'
 
 test_expect_success 'info symlink-directory' "
-	(cd svnwc; svn info symlink-directory) \
+	(cd svnwc && svn info symlink-directory) \
 		> expected.info-symlink-directory &&
-	(cd gitwc; git svn info symlink-directory) \
+	(cd gitwc && git svn info symlink-directory) \
 		> actual.info-symlink-directory &&
 	test_cmp_info expected.info-symlink-directory actual.info-symlink-directory
 	"
 
 test_expect_success 'info --url symlink-directory' '
-	test "$(cd gitwc; git svn info --url symlink-directory)" \
+	test "$(cd gitwc && git svn info --url symlink-directory)" \
 	     = "$quoted_svnrepo/symlink-directory"
 	'
 
@@ -169,13 +169,13 @@ test_expect_success 'info added-file' "
 		cd svnwc &&
 		svn_cmd add added-file > /dev/null
 	) &&
-	(cd svnwc; svn info added-file) > expected.info-added-file &&
-	(cd gitwc; git svn info added-file) > actual.info-added-file &&
+	(cd svnwc && svn info added-file) > expected.info-added-file &&
+	(cd gitwc && git svn info added-file) > actual.info-added-file &&
 	test_cmp_info expected.info-added-file actual.info-added-file
 	"
 
 test_expect_success 'info --url added-file' '
-	test "$(cd gitwc; git svn info --url added-file)" \
+	test "$(cd gitwc && git svn info --url added-file)" \
 	     = "$quoted_svnrepo/added-file"
 	'
 
@@ -190,15 +190,15 @@ test_expect_success 'info added-directory' "
 		cd gitwc &&
 		git add added-directory
 	) &&
-	(cd svnwc; svn info added-directory) \
+	(cd svnwc && svn info added-directory) \
 		> expected.info-added-directory &&
-	(cd gitwc; git svn info added-directory) \
+	(cd gitwc && git svn info added-directory) \
 		> actual.info-added-directory &&
 	test_cmp_info expected.info-added-directory actual.info-added-directory
 	"
 
 test_expect_success 'info --url added-directory' '
-	test "$(cd gitwc; git svn info --url added-directory)" \
+	test "$(cd gitwc && git svn info --url added-directory)" \
 	     = "$quoted_svnrepo/added-directory"
 	'
 
@@ -213,16 +213,16 @@ test_expect_success 'info added-symlink-file' "
 		ln -s added-file added-symlink-file &&
 		svn_cmd add added-symlink-file > /dev/null
 	) &&
-	(cd svnwc; svn info added-symlink-file) \
+	(cd svnwc && svn info added-symlink-file) \
 		> expected.info-added-symlink-file &&
-	(cd gitwc; git svn info added-symlink-file) \
+	(cd gitwc && git svn info added-symlink-file) \
 		> actual.info-added-symlink-file &&
 	test_cmp_info expected.info-added-symlink-file \
 		actual.info-added-symlink-file
 	"
 
 test_expect_success 'info --url added-symlink-file' '
-	test "$(cd gitwc; git svn info --url added-symlink-file)" \
+	test "$(cd gitwc && git svn info --url added-symlink-file)" \
 	     = "$quoted_svnrepo/added-symlink-file"
 	'
 
@@ -237,16 +237,16 @@ test_expect_success 'info added-symlink-directory' "
 		ln -s added-directory added-symlink-directory &&
 		svn_cmd add added-symlink-directory > /dev/null
 	) &&
-	(cd svnwc; svn info added-symlink-directory) \
+	(cd svnwc && svn info added-symlink-directory) \
 		> expected.info-added-symlink-directory &&
-	(cd gitwc; git svn info added-symlink-directory) \
+	(cd gitwc && git svn info added-symlink-directory) \
 		> actual.info-added-symlink-directory &&
 	test_cmp_info expected.info-added-symlink-directory \
 		actual.info-added-symlink-directory
 	"
 
 test_expect_success 'info --url added-symlink-directory' '
-	test "$(cd gitwc; git svn info --url added-symlink-directory)" \
+	test "$(cd gitwc && git svn info --url added-symlink-directory)" \
 	     = "$quoted_svnrepo/added-symlink-directory"
 	'
 
@@ -259,13 +259,13 @@ test_expect_success 'info deleted-file' "
 		cd svnwc &&
 		svn_cmd rm --force file > /dev/null
 	) &&
-	(cd svnwc; svn info file) >expected.info-deleted-file &&
-	(cd gitwc; git svn info file) >actual.info-deleted-file &&
+	(cd svnwc && svn info file) >expected.info-deleted-file &&
+	(cd gitwc && git svn info file) >actual.info-deleted-file &&
 	test_cmp_info expected.info-deleted-file actual.info-deleted-file
 	"
 
 test_expect_success 'info --url file (deleted)' '
-	test "$(cd gitwc; git svn info --url file)" \
+	test "$(cd gitwc && git svn info --url file)" \
 	     = "$quoted_svnrepo/file"
 	'
 
@@ -278,13 +278,13 @@ test_expect_success 'info deleted-directory' "
 		cd svnwc &&
 		svn_cmd rm --force directory > /dev/null
 	) &&
-	(cd svnwc; svn info directory) >expected.info-deleted-directory &&
-	(cd gitwc; git svn info directory) >actual.info-deleted-directory &&
+	(cd svnwc && svn info directory) >expected.info-deleted-directory &&
+	(cd gitwc && git svn info directory) >actual.info-deleted-directory &&
 	test_cmp_info expected.info-deleted-directory actual.info-deleted-directory
 	"
 
 test_expect_success 'info --url directory (deleted)' '
-	test "$(cd gitwc; git svn info --url directory)" \
+	test "$(cd gitwc && git svn info --url directory)" \
 	     = "$quoted_svnrepo/directory"
 	'
 
@@ -297,13 +297,13 @@ test_expect_success 'info deleted-symlink-file' "
 		cd svnwc &&
 		svn_cmd rm --force symlink-file > /dev/null
 	) &&
-	(cd svnwc; svn info symlink-file) >expected.info-deleted-symlink-file &&
-	(cd gitwc; git svn info symlink-file) >actual.info-deleted-symlink-file &&
+	(cd svnwc && svn info symlink-file) >expected.info-deleted-symlink-file &&
+	(cd gitwc && git svn info symlink-file) >actual.info-deleted-symlink-file &&
 	test_cmp_info expected.info-deleted-symlink-file actual.info-deleted-symlink-file
 	"
 
 test_expect_success 'info --url symlink-file (deleted)' '
-	test "$(cd gitwc; git svn info --url symlink-file)" \
+	test "$(cd gitwc && git svn info --url symlink-file)" \
 	     = "$quoted_svnrepo/symlink-file"
 	'
 
@@ -316,13 +316,13 @@ test_expect_success 'info deleted-symlink-directory' "
 		cd svnwc &&
 		svn_cmd rm --force symlink-directory > /dev/null
 	) &&
-	(cd svnwc; svn info symlink-directory) >expected.info-deleted-symlink-directory &&
-	(cd gitwc; git svn info symlink-directory) >actual.info-deleted-symlink-directory &&
+	(cd svnwc && svn info symlink-directory) >expected.info-deleted-symlink-directory &&
+	(cd gitwc && git svn info symlink-directory) >actual.info-deleted-symlink-directory &&
 	test_cmp_info expected.info-deleted-symlink-directory actual.info-deleted-symlink-directory
 	"
 
 test_expect_success 'info --url symlink-directory (deleted)' '
-	test "$(cd gitwc; git svn info --url symlink-directory)" \
+	test "$(cd gitwc && git svn info --url symlink-directory)" \
 	     = "$quoted_svnrepo/symlink-directory"
 	'
 
@@ -331,27 +331,27 @@ test_expect_success 'info --url symlink-directory (deleted)' '
 
 test_expect_success 'info unknown-file' "
 	echo two > gitwc/unknown-file &&
-	(cd gitwc; test_must_fail git svn info unknown-file) \
+	(cd gitwc && test_must_fail git svn info unknown-file) \
 		 2> actual.info-unknown-file &&
 	grep unknown-file actual.info-unknown-file
 	"
 
 test_expect_success 'info --url unknown-file' '
 	echo two > gitwc/unknown-file &&
-	(cd gitwc; test_must_fail git svn info --url unknown-file) \
+	(cd gitwc && test_must_fail git svn info --url unknown-file) \
 		 2> actual.info-url-unknown-file &&
 	grep unknown-file actual.info-url-unknown-file
 	'
 
 test_expect_success 'info unknown-directory' "
 	mkdir gitwc/unknown-directory svnwc/unknown-directory &&
-	(cd gitwc; test_must_fail git svn info unknown-directory) \
+	(cd gitwc && test_must_fail git svn info unknown-directory) \
 		 2> actual.info-unknown-directory &&
 	grep unknown-directory actual.info-unknown-directory
 	"
 
 test_expect_success 'info --url unknown-directory' '
-	(cd gitwc; test_must_fail git svn info --url unknown-directory) \
+	(cd gitwc && test_must_fail git svn info --url unknown-directory) \
 		 2> actual.info-url-unknown-directory &&
 	grep unknown-directory actual.info-url-unknown-directory
 	'
@@ -361,13 +361,13 @@ test_expect_success 'info unknown-symlink-file' "
 		cd gitwc &&
 		ln -s unknown-file unknown-symlink-file
 	) &&
-	(cd gitwc; test_must_fail git svn info unknown-symlink-file) \
+	(cd gitwc && test_must_fail git svn info unknown-symlink-file) \
 		 2> actual.info-unknown-symlink-file &&
 	grep unknown-symlink-file actual.info-unknown-symlink-file
 	"
 
 test_expect_success 'info --url unknown-symlink-file' '
-	(cd gitwc; test_must_fail git svn info --url unknown-symlink-file) \
+	(cd gitwc && test_must_fail git svn info --url unknown-symlink-file) \
 		 2> actual.info-url-unknown-symlink-file &&
 	grep unknown-symlink-file actual.info-url-unknown-symlink-file
 	'
@@ -377,13 +377,13 @@ test_expect_success 'info unknown-symlink-directory' "
 		cd gitwc &&
 		ln -s unknown-directory unknown-symlink-directory
 	) &&
-	(cd gitwc; test_must_fail git svn info unknown-symlink-directory) \
+	(cd gitwc && test_must_fail git svn info unknown-symlink-directory) \
 		 2> actual.info-unknown-symlink-directory &&
 	grep unknown-symlink-directory actual.info-unknown-symlink-directory
 	"
 
 test_expect_success 'info --url unknown-symlink-directory' '
-	(cd gitwc; test_must_fail git svn info --url unknown-symlink-directory) \
+	(cd gitwc && test_must_fail git svn info --url unknown-symlink-directory) \
 		 2> actual.info-url-unknown-symlink-directory &&
 	grep unknown-symlink-directory actual.info-url-unknown-symlink-directory
 	'
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (27 preceding siblings ...)
  2018-06-26  7:30 ` [PATCH 28/29] t9119: " Eric Sunshine
@ 2018-06-26  7:30 ` " Eric Sunshine
  2018-06-26 19:15   ` Junio C Hamano
  2018-06-26  9:20 ` [PATCH 00/29] t: detect and fix " Elijah Newren
                   ` (2 subsequent siblings)
  31 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  7:30 UTC (permalink / raw)
  To: git
  Cc: Jeff King, Jonathan Nieder, SZEDER Gábor, Stefan Beller,
	Elijah Newren, Jonathan Tan, Eric Sunshine

The --chain-lint option detects broken &&-chains by forcing the test to
exit early (as the very first step) with a sentinel value. If that
sentinel is the test's overall exit code, then the &&-chain is intact;
if not, then the chain is broken. Unfortunately, this detection does not
extend to &&-chains within subshells even when the subshell itself is
properly linked into the outer &&-chain.

Address this shortcoming by eliminating the subshell during the
"linting" phase and incorporating its body directly into the surrounding
&&-chain. To keep this transformation cheap, no attempt is made at
properly parsing shell code. Instead, the manipulations are purely
textual. For example:

    statement1 &&
    (
        statement2 &&
        statement3
    ) &&
    statement4

is transformed to:

    statement1 &&
        statement2 &&
        statement3 &&
    statement4

Notice how "statement3" gains the "&&" which dwelt originally on the
closing ") &&" line. Since this manipulation is purely textual (in fact,
line-by-line), special care is taken to ensure that the "&&" is moved to
the final _statement_ before the closing ")", not necessarily the final
_line_ of text within the subshell. For example, with a here-doc, the
"&&" needs to be added to the opening "<<EOF" line, not to the "EOF"
line which closes it.

In addition to modern subshell formatting shown above, old-style
formatting is also recognized:

    statement1 &&
    (statement2 &&
     statement3) &&
    statement4

Heuristics are employed to properly identify the extent of a subshell
formatted in the old-style since a number of legitimate constructs may
superficially appear to close the subshell even though they don't. For
instance, the ")" in "x=$(command) &&" and "case $x in *)" is specially
recognized to avoid being falsely considered the end of a subshell.

Due to the complexities of line-by-line detection (and limitations of
the tool, 'sed'), only subshells one level deep are handled, as well as
one-liner subshells one level below that. Subshells deeper than that or
multi-line subshells at level two are passed through as-is, thus
&&-chains in their bodies are not checked.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/test-lib.sh | 245 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 244 insertions(+), 1 deletion(-)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 28315706be..ade5066fff 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -664,6 +664,248 @@ test_eval_ () {
 	return $test_eval_ret_
 }
 
+test_subshell_sed_='
+# incomplete line -- slurp up next line
+/[^\\]\\$/ {
+      N
+      s/\\\n//
+}
+
+# here-doc -- swallow it to avoid false hits within its body (but keep the
+# command to which it was attached)
+/<<[ 	]*[-\\]*EOF[ 	]*&&[ 	]*$/ {
+	s/<<[ 	]*[-\\]*EOF//
+	h
+	:hereslurp
+	N
+	s/.*\n//
+	/^[ 	]*EOF[ 	]*$/!bhereslurp
+	x
+	}
+
+# one-liner "(... || git ...)" or "(... || test ...)" -- short-hand for
+# "if ... then : else ...", so leave untouched; contrast with "(... || true)"
+# which ought to be replaced with "test_might_fail ..." to avoid breaking
+# &&-chain
+/^[ 	]*(..*||[ 	]*git[ 	]..*)[ 	]*&&[ 	]*$/b
+/^[ 	]*(..*||[ 	]*git[ 	]..*)[ 	]*$/b
+/^[ 	]*(..*||[ 	]*test..*)[ 	]*&&[ 	]*$/b
+/^[ 	]*(..*||[ 	]*test..*)[ 	]*$/b
+
+# one-liner "(... &) &&" backgrounder -- needs to remain in subshell to avoid
+# becoming syntactically invalid "... & &&"
+/^[ 	]*(..*&[ 	]*)[ 	]*&&[ 	]*$/b
+
+# one-liner "(...) &&" -- strip "(" and ")"
+/^[ 	]*(..*)[ 	]*&&[ 	]*$/ {
+	s/(//
+	s/)[ 	]*&&[ 	]*$/ \&\&/
+	b
+}
+
+# same as above but without trailing "&&"
+/^[ 	]*(..*)[ 	]*$/ {
+	s/(//
+	s/)[ 	]*$//
+	b
+}
+
+# one-liner "(...) >x" (or "2>x" or "<x" or "|x" or "&" -- strip "(" and ")"
+/^[ 	]*(..*)[ 	]*[0-9]*[<>|&]/ {
+	s/(//
+	s/)[ 	]*\([0-9]*[<>|&]\)/\1/
+	b
+}
+
+# multi-line "(..." -- strip "(" and pass-thru enclosed lines until ")"
+/^[ 	]*(/ {
+	# strip "(" and stash for later printing
+	s/(//
+	h
+
+	:discard
+	N
+	s/.*\n//
+
+	# loop: slurp enclosed lines
+	:slurp
+	# end-of-file
+	$beof
+	# incomplete line
+	/[^\\]\\$/bincomplete
+	# here-doc
+	/<<[ 	]*[-\\]*EOF/bheredoc
+	# comment or empty line -- discard since closing ") &&" will need to
+	# add "&&" to final non-comment, non-empty subshell line
+	/^[ 	]*#/bdiscard
+	/^[ 	]*$/bdiscard
+	# one-liner "case ... esac"
+	/^[ 	]*case[ 	]*..*esac/bpassthru
+	# multi-line "case ... esac"
+	/^[ 	]*case[ 	]..*[ 	]in/bcase
+	# nested one-liner "(...) &&"
+	/^[ 	]*(.*)[ 	]*&&[ 	]*$/boneline
+	# nested one-liner "(...)"
+	/^[ 	]*(.*)[ 	]*$/boneline
+	# nested one-liner "(...) >x" (or "2>x" or "<x" or "|x")
+	/^[ 	]*(.*)[ 	]*[0-9]*[<>|]/bonelineredir
+	# nested multi-line "(...\n...)"
+	/^[ 	]*(/bnest
+	# closing ") &&" on own line
+	/^[ 	]*)[ 	]*&&[ 	]*$/bcloseamp
+	# closing ")" on own line
+	/^[ 	]*)[ 	]*$/bclose
+	# closing ") >x" (or "2>x" or "<x" or "|x") on own line
+	/^[ 	]*)[ 	]*[0-9]*[<>|]/bcloseredir
+	# "$((...))" -- not closing ")"
+	/\$(([^)][^)]*))[^)]*$/bpassthru
+	# "$(...)" -- not closing ")"
+	/\$([^)][^)]*)[^)]*$/bpassthru
+	# "=(...)" -- Bash array assignment; not closing ")"
+	/=(/bpassthru
+	# closing "...) &&"
+	/)[ 	]*&&[ 	]*$/bcloseampx
+	# closing "...)"
+	/)[ 	]*$/bclosex
+	# closing "...) >x" (or "2>x" or "<x" or "|x")
+	/)[ 	]*[<>|]/bcloseredirx
+	:passthru
+	# retrieve and print previous line
+	x
+	n
+	bslurp
+
+	# end-of-file -- must be closing "...)" line or empty line; if empty,
+	# strip ")" from previous line, else strip ")" from this line
+	:eof
+	/^[ 	]*$/bempty
+	x
+	p
+	:empty
+	x
+	/)[ 	]*[<>|]/s/[<>|]..*$//
+	s/)[ 	]*$//
+	b
+
+	# found "...\" -- slurp up next line
+	:incomplete
+	N
+	s/\\\n//
+	bslurp
+
+	# found here-doc inside subshell: when a subshell ends, we append
+	# "&&" to the final subshell line to chain it with lines outside the
+	# subshell, however, we cannot append "&&" to the ending EOF of a
+	# here-doc since "&&" belongs on the "<<EOF" opening line, so just
+	# discard the here-doc altogether (but keep the command to which it
+	# was attached)
+	:heredoc
+	s/<<[ 	]*[-\\]*EOF//
+	x
+	p
+	:hereslurpsub
+	N
+	s/.*\n//
+	/^[ 	]*EOF[ 	]*$/bdiscard
+	bhereslurpsub
+
+	# found "case ... in" -- pass-thru untouched to avoid "...)" arms
+	# being misidentified as subshell closing ")"
+	:case
+	x
+	p
+	x
+	:caseslurp
+	n
+	/^[ 	]*esac/besac
+	bcaseslurp
+	:esac
+	x
+	bdiscard
+
+	# found one-liner "(...) &&" or "(...)" -- strip "(" and ")"
+	:oneline
+	s/(//
+	s/)[ 	]*\(&&\)*[ 	]*$/ \1/
+	bpassthru
+
+	# found one-liner "(...) >x" (or "2>x" or "<x" or "|x") -- strip
+	# "(" and ")"
+	:onelineredir
+	s/(//
+	s/)[ 	]*\([0-9]*[<>|]\)/\1/
+	bpassthru
+
+	# found nested multi-line "(...\n...)" -- pass-thru untouched
+	:nest
+	x
+	p
+	x
+	:nslurp
+	n
+	# closing ")" on own line -- stop nested slurp
+	/^[ 	]*)/bnclose
+	# "$((...))" -- not closing ")"
+	/\$(([^)][^)]*))[^)]*$/bnslurp
+	# "$(...)" -- not closing ")"
+	/\$([^)][^)]*)[^)]*$/bnslurp
+	# closing "...)" -- stop nested slurp
+	/)/bnclose
+	bnslurp
+	:nclose
+	# stash ")" (or ") &&", etc.) line for later printing and drop
+	# leftover gunk from hold area
+	x
+	bdiscard
+
+	# found ") &&" -- drop ") &&" and add "&&" to final subshell line
+	:closeamp
+	x
+	s/$/ \&\&/
+	b
+
+	# found ")" -- drop it and print final subshell line
+	:close
+	x
+	b
+
+	# found ") >x" (or "2>x" or "<x" or "|x" or "|") -- replace ")" with
+	# ":" to keep ")|\n" syntactically valid, and add "&&" to final
+	# subshell line
+	:closeredir
+	x
+	s/$/ \&\&/
+	p
+	x
+	s/)/:/
+	b
+
+	# found "...) &&" -- drop ")" but keep "..."
+	:closeampx
+	x
+	p
+	x
+	s/)[ 	]*&&[ 	]*$/ \&\&/
+	b
+
+	# found "...)" -- drop ")" but keep "..."
+	:closex
+	x
+	p
+	x
+	s/)[ 	]*$//
+	b
+
+	# found "...) >x" (or "2>x" or "<x" or "|x") -- drop ")" but keep "..."
+	:closeredirx
+	x
+	p
+	x
+	s/)[ 	]*\([<>|]\)/ \&\& : \1/
+	b
+}
+'
+
 test_run_ () {
 	test_cleanup=:
 	expecting_failure=$2
@@ -675,7 +917,8 @@ test_run_ () {
 		trace=
 		# 117 is magic because it is unlikely to match the exit
 		# code of other programs
-		if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)"
+		test_linter=$(printf '%s\n' "$1" | sed -e "$test_subshell_sed_")
+		if test "OK-117" != "$(test_eval_ "(exit 117) && ${test_linter}${LF}${LF}echo OK-\$?" 3>&1)"
 		then
 			error "bug in the test script: broken &&-chain or run-away HERE-DOC: $1"
 		fi
-- 
2.18.0.419.gfe4b301394


^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 17/29] t: use test_must_fail() instead of checking exit code manually
  2018-06-26  7:29 ` [PATCH 17/29] t: use test_must_fail() instead of checking " Eric Sunshine
@ 2018-06-26  7:59   ` Luke Diamand
  2018-06-26  8:58   ` Elijah Newren
  1 sibling, 0 replies; 82+ messages in thread
From: Luke Diamand @ 2018-06-26  7:59 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git Users, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Elijah Newren, Jonathan Tan

On 26 June 2018 at 08:29, Eric Sunshine <sunshine@sunshineco.com> wrote:
> These tests intentionally break the &&-chain to manually check the exit
> code of invoked commands which they expect to fail, and invert that
> local expected failure into a successful exit code for the test overall.
> Such manual exit code manipulation predates the invention of
> test_must_fail().
>
> An upcoming change will teach --chain-lint to check the &&-chain inside
> subshells. This sort of manual exit code checking will trip up
> --chain-lint due to the intentional break in the &&-chain. Therefore,
> replace the manual exit code management with test_must_fail() and a
> normal &&-chain.
>
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> ---
>  t/t5405-send-pack-rewind.sh |  3 +--
>  t/t9814-git-p4-rename.sh    | 16 ++--------------
>  2 files changed, 3 insertions(+), 16 deletions(-)
>
> diff --git a/t/t5405-send-pack-rewind.sh b/t/t5405-send-pack-rewind.sh
> index 4bda18a662..235fb7686a 100755
> --- a/t/t5405-send-pack-rewind.sh
> +++ b/t/t5405-send-pack-rewind.sh
> @@ -25,8 +25,7 @@ test_expect_success 'non forced push should die not segfault' '
>
>         (
>                 cd another &&
> -               git push .. master:master
> -               test $? = 1
> +               test_must_fail git push .. master:master
>         )
>
>  '
> diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh
> index e7e0268e98..80aac5ab16 100755
> --- a/t/t9814-git-p4-rename.sh
> +++ b/t/t9814-git-p4-rename.sh
> @@ -12,20 +12,8 @@ test_expect_success 'start p4d' '
>  test_expect_success 'p4 help unknown returns 1' '
>         (
>                 cd "$cli" &&
> -               (
> -                       p4 help client >errs 2>&1
> -                       echo $? >retval
> -               )
> -               echo 0 >expected &&
> -               test_cmp expected retval &&
> -               rm retval &&
> -               (
> -                       p4 help nosuchcommand >errs 2>&1
> -                       echo $? >retval
> -               )
> -               echo 1 >expected &&
> -               test_cmp expected retval &&
> -               rm retval
> +               p4 help client &&
> +               test_must_fail p4 help nosuchcommand

This seems a lot more sensible. It works fine in my tests.

Thanks,
Luke

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 06/29] t6036: fix broken "merge fails but has appropriate contents" tests
  2018-06-26  7:29 ` [PATCH 06/29] t6036: fix broken "merge fails but has appropriate contents" tests Eric Sunshine
@ 2018-06-26  8:44   ` Elijah Newren
  0 siblings, 0 replies; 82+ messages in thread
From: Elijah Newren @ 2018-06-26  8:44 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git Mailing List, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Jonathan Tan

On Tue, Jun 26, 2018 at 12:29 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> These tests reference non-existent object "c" when they really mean to
> be referencing "C", however, this error went unnoticed due to a broken
> &&-chain later in the test. Fix these errors, as well as the broken
> &&-chains behind which they hid.
>
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> ---
>  t/t6036-recursive-corner-cases.sh | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh
> index b5621303d6..b32ff8e1db 100755
> --- a/t/t6036-recursive-corner-cases.sh
> +++ b/t/t6036-recursive-corner-cases.sh
> @@ -506,10 +506,10 @@ test_expect_success 'merge of D & E2 fails but has appropriate contents' '
>                 test_line_count = 2 out &&
>
>                 git rev-parse >expect    \
> -                       B:a   E2:a/file  c:a/file   A:ignore-me &&
> +                       B:a   E2:a/file  C:a/file   A:ignore-me &&
>                 git rev-parse   >actual   \
>                         :2:a  :3:a/file  :1:a/file  :0:ignore-me &&
> -               test_cmp expect actual
> +               test_cmp expect actual &&
>
>                 test_path_is_file a~HEAD
>         )
> @@ -533,10 +533,10 @@ test_expect_success 'merge of E2 & D fails but has appropriate contents' '
>                 test_line_count = 2 out &&
>
>                 git rev-parse >expect    \
> -                       B:a   E2:a/file  c:a/file   A:ignore-me &&
> +                       B:a   E2:a/file  C:a/file   A:ignore-me &&
>                 git rev-parse   >actual   \
>                         :3:a  :2:a/file  :1:a/file  :0:ignore-me &&
> -               test_cmp expect actual
> +               test_cmp expect actual &&
>
>                 test_path_is_file a~D^0
>         )

Eek, how did that become c:a/file when it was originally C:a/file?
Thanks for spotting the regression and fixing.

Reviewed-by: Elijah Newren <newren@gmail.com>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 17/29] t: use test_must_fail() instead of checking exit code manually
  2018-06-26  7:29 ` [PATCH 17/29] t: use test_must_fail() instead of checking " Eric Sunshine
  2018-06-26  7:59   ` Luke Diamand
@ 2018-06-26  8:58   ` Elijah Newren
  2018-06-26  9:21     ` Eric Sunshine
  1 sibling, 1 reply; 82+ messages in thread
From: Elijah Newren @ 2018-06-26  8:58 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git Mailing List, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Jonathan Tan

On Tue, Jun 26, 2018 at 12:29 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> These tests intentionally break the &&-chain to manually check the exit
> code of invoked commands which they expect to fail, and invert that
> local expected failure into a successful exit code for the test overall.
> Such manual exit code manipulation predates the invention of
> test_must_fail().
>
> An upcoming change will teach --chain-lint to check the &&-chain inside
> subshells. This sort of manual exit code checking will trip up
> --chain-lint due to the intentional break in the &&-chain. Therefore,
> replace the manual exit code management with test_must_fail() and a
> normal &&-chain.
>
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> ---
>  t/t5405-send-pack-rewind.sh |  3 +--
>  t/t9814-git-p4-rename.sh    | 16 ++--------------
>  2 files changed, 3 insertions(+), 16 deletions(-)
>
> diff --git a/t/t5405-send-pack-rewind.sh b/t/t5405-send-pack-rewind.sh
> index 4bda18a662..235fb7686a 100755
> --- a/t/t5405-send-pack-rewind.sh
> +++ b/t/t5405-send-pack-rewind.sh
> @@ -25,8 +25,7 @@ test_expect_success 'non forced push should die not segfault' '
>
>         (
>                 cd another &&
> -               git push .. master:master
> -               test $? = 1
> +               test_must_fail git push .. master:master

test_must_fail or test_expect_code 1?

>         )
>
>  '
> diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh
> index e7e0268e98..80aac5ab16 100755
> --- a/t/t9814-git-p4-rename.sh
> +++ b/t/t9814-git-p4-rename.sh
> @@ -12,20 +12,8 @@ test_expect_success 'start p4d' '
>  test_expect_success 'p4 help unknown returns 1' '
>         (
>                 cd "$cli" &&
> -               (
> -                       p4 help client >errs 2>&1
> -                       echo $? >retval
> -               )
> -               echo 0 >expected &&
> -               test_cmp expected retval &&
> -               rm retval &&
> -               (
> -                       p4 help nosuchcommand >errs 2>&1
> -                       echo $? >retval
> -               )
> -               echo 1 >expected &&
> -               test_cmp expected retval &&
> -               rm retval
> +               p4 help client &&
> +               test_must_fail p4 help nosuchcommand

same question?

>         )
>  '

Overall, looks much nicer.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/29] t: detect and fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (28 preceding siblings ...)
  2018-06-26  7:30 ` [PATCH 29/29] t/test-lib: teach --chain-lint to detect " Eric Sunshine
@ 2018-06-26  9:20 ` " Elijah Newren
  2018-06-26  9:31   ` Eric Sunshine
  2018-06-26 19:38 ` Junio C Hamano
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
  31 siblings, 1 reply; 82+ messages in thread
From: Elijah Newren @ 2018-06-26  9:20 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git Mailing List, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Jonathan Tan

On Tue, Jun 26, 2018 at 12:29 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> The --chain-lint[1] option detects breakage in the top-level &&-chain of
> tests. This series undertakes the more complex task of teaching it to
> also detect &&-chain breakage within subshells. See patch 29/29 for the
> gory details of how that's done.

This is awesome.  It'll replace a hacky script I had that attempted to
remind me when I messed up, and fix its false positives to boot.
Plus, I won't forget to run it.

> Aside from identifying a rather significant number of &&-chain breaks,
> repairing those broken chains uncovered genuine bugs in several tests
> which were hidden by missing &&-chain links. Those bugs are also fixed
> by this series. I would appreciate if the following people would
> double-check my fixes:
>
> Stefan Bellar - 8/29 "t7400" and (especially) 13/29 "lib-submodule-update"
> Jonathan Tan - 10/29 "t9001"
> Elijah Newren - 6/29 "t6036"

Commented on the patch in question; 6/29 looks good.

I also looked over the rest of the series.  Apart from the ones you
specifically called out as needing review by others besides me, and
the final patch which makes me feel like a sed neophyte, all but one
patch looked good to me.  I just have a small question for that
remaining patch, which I posted there.

Thanks,
Elijah

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 17/29] t: use test_must_fail() instead of checking exit code manually
  2018-06-26  8:58   ` Elijah Newren
@ 2018-06-26  9:21     ` Eric Sunshine
  2018-06-26 18:05       ` Johannes Sixt
  0 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  9:21 UTC (permalink / raw)
  To: Elijah Newren
  Cc: Git List, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Jonathan Tan

On Tue, Jun 26, 2018 at 4:58 AM Elijah Newren <newren@gmail.com> wrote:
> On Tue, Jun 26, 2018 at 12:29 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> > [...] Therefore,
> > replace the manual exit code management with test_must_fail() and a
> > normal &&-chain.
> >
> > Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> > ---
> > diff --git a/t/t5405-send-pack-rewind.sh b/t/t5405-send-pack-rewind.sh
> > @@ -25,8 +25,7 @@ test_expect_success 'non forced push should die not segfault' '> > -               git push .. master:master
> > -               test $? = 1
> > +               test_must_fail git push .. master:master
>
> test_must_fail or test_expect_code 1?

A legitimate question, and the answer is that it's a judgment call
based upon the spirit of the test.

Although test_expect_code() would make for a faithful literal
conversion, I don't think it agrees with the spirit of this test,
which wants to verify that the command correctly exits with an error
(in the general sense), as opposed to outright crashing (which it did
at one time). test_must_fail() is tailor-made for this use case.

Contrast this with patch 09/29 "t7810: use test_expect_code() instead
of hand-rolled comparison". Different exit codes from git-grep have
genuine different meanings, and that test is checking for a very
specific exit code, for which test_expect_code() is tailor-made.

> > diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh
> > @@ -12,20 +12,8 @@ test_expect_success 'start p4d' '
> >  test_expect_success 'p4 help unknown returns 1' '
> >         (
> >                 cd "$cli" &&
> > -               (
> > -                       p4 help client >errs 2>&1
> > -                       echo $? >retval
> > -               )
> > -               echo 0 >expected &&
> > -               test_cmp expected retval &&
> > -               rm retval &&
> > -               (
> > -                       p4 help nosuchcommand >errs 2>&1
> > -                       echo $? >retval
> > -               )
> > -               echo 1 >expected &&
> > -               test_cmp expected retval &&
> > -               rm retval
> > +               p4 help client &&
> > +               test_must_fail p4 help nosuchcommand
>
> same question?

Same answer. Not shown in this patch, but just above the context lines
you will find this comment in the file:

    # We rely on this behavior to detect for p4 move availability.

which means that the test is really interested in being able to
reliably detect if a sub-command is or is not available. So, despite
the (somewhat) misleading test title, this test doesn't care about the
exact error code but rather cares only that "p4 help nosuchcommand"
errors out, period. Hence, test_must_fail() again agrees with the
spirit of the test.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/29] t: detect and fix broken &&-chains in subshells
  2018-06-26  9:20 ` [PATCH 00/29] t: detect and fix " Elijah Newren
@ 2018-06-26  9:31   ` Eric Sunshine
  2018-06-26 15:34     ` Elijah Newren
  0 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26  9:31 UTC (permalink / raw)
  To: Elijah Newren
  Cc: Git List, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Jonathan Tan

On Tue, Jun 26, 2018 at 5:20 AM Elijah Newren <newren@gmail.com> wrote:
> On Tue, Jun 26, 2018 at 12:29 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> > Aside from identifying a rather significant number of &&-chain breaks,
> > repairing those broken chains uncovered genuine bugs in several tests
> > which were hidden by missing &&-chain links. Those bugs are also fixed
> > by this series. I would appreciate if the following people would
> > double-check my fixes:
> >
> > Stefan Bellar - 8/29 "t7400" and (especially) 13/29 "lib-submodule-update"
> > Jonathan Tan - 10/29 "t9001"
> > Elijah Newren - 6/29 "t6036"
>
> Commented on the patch in question; 6/29 looks good.
>
> I also looked over the rest of the series.  Apart from the ones you
> specifically called out as needing review by others besides me, and
> the final patch which makes me feel like a sed neophyte, all but one
> patch looked good to me.  I just have a small question for that
> remaining patch, which I posted there.

I guess you refer to your question[1] about whether test_must_fail()
is the correct choice over test_expect_code(). I just responded[2]
with a hopefully satisfactory answer.

[1]: https://public-inbox.org/git/CABPp-BFmfN6=E+3BAKt-NH5hmU-368shgDnrnkrnMRvKnx07BQ@mail.gmail.com/
[2]: https://public-inbox.org/git/CAPig+cRTG625H3CF1Zw30vQt2W8uKf1xLxVaQni2YbJ=xAif2g@mail.gmail.com/

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/29] t: detect and fix broken &&-chains in subshells
  2018-06-26  9:31   ` Eric Sunshine
@ 2018-06-26 15:34     ` Elijah Newren
  0 siblings, 0 replies; 82+ messages in thread
From: Elijah Newren @ 2018-06-26 15:34 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git Mailing List, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Jonathan Tan

Hi Eric,

On Tue, Jun 26, 2018, 2:31 AM Eric Sunshine <sunshine@sunshineco.com> wrote:
>
> On Tue, Jun 26, 2018 at 5:20 AM Elijah Newren <newren@gmail.com> wrote:
> > On Tue, Jun 26, 2018 at 12:29 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> > > Aside from identifying a rather significant number of &&-chain breaks,
> > > repairing those broken chains uncovered genuine bugs in several tests
> > > which were hidden by missing &&-chain links. Those bugs are also fixed
> > > by this series. I would appreciate if the following people would
> > > double-check my fixes:
> > >
> > > Stefan Bellar - 8/29 "t7400" and (especially) 13/29 "lib-submodule-update"
> > > Jonathan Tan - 10/29 "t9001"
> > > Elijah Newren - 6/29 "t6036"
> >
> > Commented on the patch in question; 6/29 looks good.
> >
> > I also looked over the rest of the series.  Apart from the ones you
> > specifically called out as needing review by others besides me, and
> > the final patch which makes me feel like a sed neophyte, all but one
> > patch looked good to me.  I just have a small question for that
> > remaining patch, which I posted there.
>
> I guess you refer to your question[1] about whether test_must_fail()
> is the correct choice over test_expect_code(). I just responded[2]
> with a hopefully satisfactory answer.

Yes, it does.  Thanks!

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 10/29] t9001: fix broken "invoke hook" test
  2018-06-26  7:29 ` [PATCH 10/29] t9001: fix broken "invoke hook" test Eric Sunshine
@ 2018-06-26 17:07   ` Jonathan Tan
  0 siblings, 0 replies; 82+ messages in thread
From: Jonathan Tan @ 2018-06-26 17:07 UTC (permalink / raw)
  To: sunshine; +Cc: git, peff, jrnieder, szeder, sbeller, newren, jonathantanmy

> diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
> index e80eacbb1b..776769fe0d 100755
> --- a/t/t9001-send-email.sh
> +++ b/t/t9001-send-email.sh
> @@ -1966,11 +1966,11 @@ test_expect_success $PREREQ 'invoke hook' '
>  
>  		# Verify error message when a patch is rejected by the hook
>  		sed -e "s/add master/x/" ../0001-add-master.patch >../another.patch &&
> -		git send-email \
> +		test_must_fail git send-email \
>  			--from="Example <nobody@example.com>" \
>  			--to=nobody@example.com \
>  			--smtp-server="$(pwd)/../fake.sendmail" \
> -			../another.patch 2>err
> +			../another.patch 2>err &&
>  		test_i18ngrep "rejected by sendemail-validate hook" err

Thanks for catching this. Indeed, "git send-email" is supposed to fail
because the validate hook greps for the string "add master", which does
not exist in the e-mail to be sent. (Above this is a test that shows
that the same validate hook succeeds if the e-mail contains "add
master".) This looks correct to me.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 17/29] t: use test_must_fail() instead of checking exit code manually
  2018-06-26  9:21     ` Eric Sunshine
@ 2018-06-26 18:05       ` Johannes Sixt
  2018-06-26 18:14         ` Eric Sunshine
  0 siblings, 1 reply; 82+ messages in thread
From: Johannes Sixt @ 2018-06-26 18:05 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Elijah Newren, Git List, Jeff King, Jonathan Nieder,
	SZEDER Gábor, Stefan Beller, Jonathan Tan

Am 26.06.2018 um 11:21 schrieb Eric Sunshine:
> On Tue, Jun 26, 2018 at 4:58 AM Elijah Newren <newren@gmail.com> wrote:
>> On Tue, Jun 26, 2018 at 12:29 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>>> +               p4 help client &&
>>> +               test_must_fail p4 help nosuchcommand
>>
>> same question?
> 
> Same answer. Not shown in this patch, but just above the context lines
> you will find this comment in the file:
> 
>      # We rely on this behavior to detect for p4 move availability.
> 
> which means that the test is really interested in being able to
> reliably detect if a sub-command is or is not available. So, despite
> the (somewhat) misleading test title, this test doesn't care about the
> exact error code but rather cares only that "p4 help nosuchcommand"
> errors out, period. Hence, test_must_fail() again agrees with the
> spirit of the test.

test_must_fail ensures that only "proper" failures are diagnosed as 
expected; failures due to signals such as SEGV are not expected failures.

In the test suite we expect all programs that are not our "git" to work 
correctly; in particular, that they do not crash on anything that we ask 
them to operate on. Under this assumption, the protection given by 
test_must_fail is not needed.

Hence, these lines should actually be

		p4 help client &&
		! p4 help nosuchcommand

-- Hannes

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 17/29] t: use test_must_fail() instead of checking exit code manually
  2018-06-26 18:05       ` Johannes Sixt
@ 2018-06-26 18:14         ` Eric Sunshine
  2018-06-26 21:00           ` Johannes Sixt
  0 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26 18:14 UTC (permalink / raw)
  To: Johannes Sixt
  Cc: Elijah Newren, Git List, Jeff King, Jonathan Nieder,
	SZEDER Gábor, Stefan Beller, Jonathan Tan

On Tue, Jun 26, 2018 at 2:06 PM Johannes Sixt <j6t@kdbg.org> wrote:
> Am 26.06.2018 um 11:21 schrieb Eric Sunshine:
> >> On Tue, Jun 26, 2018 at 12:29 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> >>> +               p4 help client &&
> >>> +               test_must_fail p4 help nosuchcommand
> > [...] So, despite
> > the (somewhat) misleading test title, this test doesn't care about the
> > exact error code but rather cares only that "p4 help nosuchcommand"
> > errors out, period. Hence, test_must_fail() again agrees with the
> > spirit of the test.
>
> test_must_fail ensures that only "proper" failures are diagnosed as
> expected; failures due to signals such as SEGV are not expected failures.
>
> In the test suite we expect all programs that are not our "git" to work
> correctly; in particular, that they do not crash on anything that we ask
> them to operate on. Under this assumption, the protection given by
> test_must_fail is not needed.
>
> Hence, these lines should actually be
>
>                 p4 help client &&
>                 ! p4 help nosuchcommand

Thanks for the comment; you're right, of course. I'll certainly make
this change if I have to re-roll for some other reason, but do you
feel that this itself is worth a re-roll?

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26  7:30 ` [PATCH 29/29] t/test-lib: teach --chain-lint to detect " Eric Sunshine
@ 2018-06-26 19:15   ` Junio C Hamano
  2018-06-26 19:52     ` Eric Sunshine
  0 siblings, 1 reply; 82+ messages in thread
From: Junio C Hamano @ 2018-06-26 19:15 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: git, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Elijah Newren, Jonathan Tan

Eric Sunshine <sunshine@sunshineco.com> writes:

> The --chain-lint option detects broken &&-chains by forcing the test to
> exit early (as the very first step) with a sentinel value. If that
> sentinel is the test's overall exit code, then the &&-chain is intact;
> if not, then the chain is broken. Unfortunately, this detection does not
> extend to &&-chains within subshells even when the subshell itself is
> properly linked into the outer &&-chain.
>
> Address this shortcoming by eliminating the subshell during the
> "linting" phase and incorporating its body directly into the surrounding
> &&-chain. To keep this transformation cheap, no attempt is made at
> properly parsing shell code. Instead, the manipulations are purely
> textual. For example:
>
>     statement1 &&
>     (
>         statement2 &&
>         statement3
>     ) &&
>     statement4
>
> is transformed to:
>
>     statement1 &&
>         statement2 &&
>         statement3 &&
>     statement4

so, with --chain-lint, we would transform this

	mkdir -p a/b/c &&
	(
		cd a/b/c
		rm -fr ../../*
	) &&
	statement 4

into this sequence

	(exit $sentinel) &&
	mkdir -p a/b/c &&
		cd a/b/c
		rm -fr ../../* &&
	statement 4

and then rely on the non-zero exit to cancel all the remainder?

We didn't create nor cd to the t/trash$num/a/b/c thanks to the &&
chain, and end up running rm -fr ../../* from inside t/trash$num?

Hmmmmm....

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 14/29] t: drop subshell with missing &&-chain in favor of simpler construct
  2018-06-26  7:29 ` [PATCH 14/29] t: drop subshell with missing &&-chain in favor of simpler construct Eric Sunshine
@ 2018-06-26 19:31   ` Junio C Hamano
  2018-06-26 20:06     ` Eric Sunshine
  0 siblings, 1 reply; 82+ messages in thread
From: Junio C Hamano @ 2018-06-26 19:31 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: git, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Elijah Newren, Jonathan Tan

Eric Sunshine <sunshine@sunshineco.com> writes:

> These tests employ a noisy subshell (with missing &&-chain) to feed
> input into Git commands:
>
>     (echo a; echo b; echo c) | git some-command ...
>
> Drop the subshell in favor of a simple 'printf':
>
>     printf "%s\n" a b c | git some-command ...

That's called test_write_lines, I think.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/29] t: detect and fix broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (29 preceding siblings ...)
  2018-06-26  9:20 ` [PATCH 00/29] t: detect and fix " Elijah Newren
@ 2018-06-26 19:38 ` Junio C Hamano
  2018-06-26 21:25   ` Eric Sunshine
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
  31 siblings, 1 reply; 82+ messages in thread
From: Junio C Hamano @ 2018-06-26 19:38 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: git, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Elijah Newren, Jonathan Tan

Eric Sunshine <sunshine@sunshineco.com> writes:

> The --chain-lint[1] option detects breakage in the top-level &&-chain of
> tests. This series undertakes the more complex task of teaching it to
> also detect &&-chain breakage within subshells. See patch 29/29 for the
> gory details of how that's done.

I first looked at 29/29 and got heavily inclined to reject that
step, and then continued reading from 1/29 to around 15/29.  

I like these earlier changes that fix existing breakage, of course.
I also like many of the changes that simplify and/or modernise the
test scripts very much, but they are unusable as-is as long as their
justification is "chain-lint will start barfing on these constructs".

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 19:15   ` Junio C Hamano
@ 2018-06-26 19:52     ` Eric Sunshine
  2018-06-26 20:17       ` Jeff King
  0 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26 19:52 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git List, Jeff King, Jonathan Nieder, Stefan Beller,
	Elijah Newren, Jonathan Tan

On Tue, Jun 26, 2018 at 3:15 PM Junio C Hamano <gitster@pobox.com> wrote:
> so, with --chain-lint, we would transform this
>
>         mkdir -p a/b/c &&
>         (
>                 cd a/b/c
>                 rm -fr ../../*
>         ) &&
>         statement 4
>
> into this sequence
>
>         (exit $sentinel) &&
>         mkdir -p a/b/c &&
>                 cd a/b/c
>                 rm -fr ../../* &&
>         statement 4
>
> and then rely on the non-zero exit to cancel all the remainder?
>
> We didn't create nor cd to the t/trash$num/a/b/c thanks to the &&
> chain, and end up running rm -fr ../../* from inside t/trash$num?

Yes, I did take that into account and, no, I don't have a good answer
to the issue.

The existing --chain-lint already suffers the same shortcoming. Older
(or even new poorly-written) tests, even without subshells, can fall
victim already:

    (exit $sentinel) &&
    mkdir -p a/b/c &&
    cd a/b/c
    rm -fr ../../* &&
    cd ../../.. &&
    statement4

As in your example, 'mkdir' and 'cd' are skipped, but 'rm -fr ../../*' is not.

This snippet from the commit message of bb79af9d09 (t/test-lib:
introduce --chain-lint option, 2015-03-20):

    When we encounter a failure of this check, we abort the test
    script entirely. For one thing, we have no clue which subset
    of the commands in the test snippet were actually run.

suggests that the issue was considered, in some form, even then
(though, it doesn't say explicitly that Peff had the 'rm -fr' case in
mind).

So, this isn't a new problem introduced by this series, though this
series may exacerbate it.

Thanks for thinking critically about it.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 14/29] t: drop subshell with missing &&-chain in favor of simpler construct
  2018-06-26 19:31   ` Junio C Hamano
@ 2018-06-26 20:06     ` Eric Sunshine
  0 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26 20:06 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git List, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Elijah Newren, Jonathan Tan

On Tue, Jun 26, 2018 at 3:31 PM Junio C Hamano <gitster@pobox.com> wrote:
> Eric Sunshine <sunshine@sunshineco.com> writes:
> > These tests employ a noisy subshell (with missing &&-chain) to feed
> > input into Git commands:
> >
> >     (echo a; echo b; echo c) | git some-command ...
> >
> > Drop the subshell in favor of a simple 'printf':
> >
> >     printf "%s\n" a b c | git some-command ...
>
> That's called test_write_lines, I think.

Yep, that's better. Thanks.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 19:52     ` Eric Sunshine
@ 2018-06-26 20:17       ` Jeff King
  2018-06-26 20:22         ` Jeff King
                           ` (2 more replies)
  0 siblings, 3 replies; 82+ messages in thread
From: Jeff King @ 2018-06-26 20:17 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Junio C Hamano, Git List, Jonathan Nieder, Stefan Beller,
	Elijah Newren, Jonathan Tan

On Tue, Jun 26, 2018 at 03:52:54PM -0400, Eric Sunshine wrote:

> The existing --chain-lint already suffers the same shortcoming. Older
> (or even new poorly-written) tests, even without subshells, can fall
> victim already:
> 
>     (exit $sentinel) &&
>     mkdir -p a/b/c &&
>     cd a/b/c
>     rm -fr ../../* &&
>     cd ../../.. &&
>     statement4
> 
> As in your example, 'mkdir' and 'cd' are skipped, but 'rm -fr ../../*' is not.
> 
> This snippet from the commit message of bb79af9d09 (t/test-lib:
> introduce --chain-lint option, 2015-03-20):
> 
>     When we encounter a failure of this check, we abort the test
>     script entirely. For one thing, we have no clue which subset
>     of the commands in the test snippet were actually run.
> 
> suggests that the issue was considered, in some form, even then
> (though, it doesn't say explicitly that Peff had the 'rm -fr' case in
> mind).
>
> So, this isn't a new problem introduced by this series, though this
> series may exacerbate it.

One way this series might be worse in practice is that we tend not to
change process state too much outside of the subshells. So if we skip
some early commands and execute a later "rm", for example, it tends to
be in the same directory (and I think as time goes on we have been
cleaning up old tests which did a "cd foo && bar && cd .." into using a
subshell).

Whereas once you start collapsing subshells into the main logic chain,
there's a very high chance that the subshell is doing a "cd", since
that's typically the main reason for the subshell in the first place.
And with the current --chain-lint logic, that subshell is either
executed or not executed as a unit.

Obviously that's a bit of a hand-waving argument. If you've fixed all of
the existing cases without accidentally deleting your home directory,
then maybe it's not so likely to be a problem after all.

I'm not sure if there's a good solution, though. Even if you retained
the subshells and instead did a chain-lint inside each subshell, like
this:

  (exit 117) &&
  one &&
  (
	(exit 117) &&
	cd foo
	two
  ) &&
  three


that doesn't really help. The fundamental issue is that we may skip the
"cd" inside the subshell. Whether it's in a subshell or not, that's
dangerous. True, we don't run "three" in this case, which is slightly
better. But it didn't expect to be in a different directory anyway. It's
running "two" that is dangerous.

-Peff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 20:17       ` Jeff King
@ 2018-06-26 20:22         ` Jeff King
  2018-06-26 20:59           ` Eric Sunshine
  2018-06-26 21:33           ` Elijah Newren
  2018-06-26 20:46         ` Eric Sunshine
  2018-06-26 21:09         ` Junio C Hamano
  2 siblings, 2 replies; 82+ messages in thread
From: Jeff King @ 2018-06-26 20:22 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Junio C Hamano, Git List, Jonathan Nieder, Stefan Beller,
	Elijah Newren, Jonathan Tan

On Tue, Jun 26, 2018 at 04:17:08PM -0400, Jeff King wrote:

> I'm not sure if there's a good solution, though. Even if you retained
> the subshells and instead did a chain-lint inside each subshell, like
> this:

So obviously that means "I don't think there's a good solution with this
approach".

That whole final patch simultaneously impresses and nauseates me. Your
commit message says "no attempt is made at properly parsing shell code",
but we come pretty darn close. I almost wonder if we'd be better off
just parsing some heuristic subset and making sure (via review or
linting) that our tests conform.

Another option is to not enable this slightly-more-dangerous linting by
default. But that would probably rob it of its usefulness, since it
would just fall to some brave soul to later crank up the linting and fix
everybody else's mistakes.

-Peff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 20:17       ` Jeff King
  2018-06-26 20:22         ` Jeff King
@ 2018-06-26 20:46         ` Eric Sunshine
  2018-06-26 21:01           ` Jeff King
  2018-06-26 21:09         ` Junio C Hamano
  2 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26 20:46 UTC (permalink / raw)
  To: Jeff King
  Cc: Junio C Hamano, Git List, Jonathan Nieder, Stefan Beller,
	Elijah Newren, Jonathan Tan

On Tue, Jun 26, 2018 at 4:17 PM Jeff King <peff@peff.net> wrote:
> On Tue, Jun 26, 2018 at 03:52:54PM -0400, Eric Sunshine wrote:
> > So, this isn't a new problem introduced by this series, though this
> > series may exacerbate it.
>
> Whereas once you start collapsing subshells into the main logic chain,
> there's a very high chance that the subshell is doing a "cd", since
> that's typically the main reason for the subshell in the first place.
> And with the current --chain-lint logic, that subshell is either
> executed or not executed as a unit.
>
> Obviously that's a bit of a hand-waving argument. If you've fixed all of
> the existing cases without accidentally deleting your home directory,
> then maybe it's not so likely to be a problem after all.

Indeed, it could be that the "rm -fr" worry is tending toward the
hypothetical. Seasoned developers tend to be pretty careful and
usually avoid indiscriminately loose "rm -fr" invocations, so I'm
somewhat less worried about them. I do share the concern, though, that
newcomers crafting or extending tests could shoot themselves in the
foot with this. However, newcomers are also the ones most likely to
use the "cd foo && bar && cd .." idiom, so they are already at risk.

(As for not blasting my home directory when fixing all the existing
tests, I did run into a few cases where one or two "foreign" files
were deposited into the "t/" directory, but nothing was deleted or
overwritten.)

> I'm not sure if there's a good solution, though. Even if you retained
> the subshells and instead did a chain-lint inside each subshell, like
> this:
>
>   (exit 117) &&
>   one &&
>   (
>         (exit 117) &&
>         cd foo
>         two
>   ) &&
>   three

I thought of that too, but the inner (exit 117) doesn't even get
invoked unless there is &&-chain breakage somewhere above that point
(for instance, if "one" lacks "&&"), so the inner (exit 117) doesn't
participate in the linting process at all.

> that doesn't really help. The fundamental issue is that we may skip the
> "cd" inside the subshell. Whether it's in a subshell or not, that's
> dangerous. True, we don't run "three" in this case, which is slightly
> better. But it didn't expect to be in a different directory anyway. It's
> running "two" that is dangerous.

Just thinking aloud...

Aside from "rm -fr", there are numerous ways to clobber files
unexpectedly when the "cd" is skipped:

    echo x >../git.c
    cp x ../git.c
    mv x ../git.c
    ln [-s] x ../git.c
    /bin/rm ../git.c
    some-cmd -o ../git.c

Some of these dangers can be de-thoothed during the linting phase by
defining do-nothing shell functions:

    cp () { :; }
    mv () { :; }
    ln () { :; }

That, at least, makes the scariest case ("rm") much less so.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 20:22         ` Jeff King
@ 2018-06-26 20:59           ` Eric Sunshine
  2018-06-26 21:33           ` Elijah Newren
  1 sibling, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26 20:59 UTC (permalink / raw)
  To: Jeff King
  Cc: Junio C Hamano, Git List, Jonathan Nieder, Stefan Beller,
	Elijah Newren, Jonathan Tan

On Tue, Jun 26, 2018 at 4:22 PM Jeff King <peff@peff.net> wrote:
> So obviously that means "I don't think there's a good solution with this
> approach".
>
> That whole final patch simultaneously impresses and nauseates me. Your
> commit message says "no attempt is made at properly parsing shell code",
> but we come pretty darn close. I almost wonder if we'd be better off
> just parsing some heuristic subset and making sure (via review or
> linting) that our tests conform.

I'm not sure I agree with "come pretty darn close", but your idea is
an interesting one. It would sidestep the concern with "rm -fr" and
friends (though it will probably still nauseate you). Let me cogitate
about it a bit...

> Another option is to not enable this slightly-more-dangerous linting by
> default. But that would probably rob it of its usefulness, since it
> would just fall to some brave soul to later crank up the linting and fix
> everybody else's mistakes.

I considered that, as well, and came to the same conclusion.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 17/29] t: use test_must_fail() instead of checking exit code manually
  2018-06-26 18:14         ` Eric Sunshine
@ 2018-06-26 21:00           ` Johannes Sixt
  0 siblings, 0 replies; 82+ messages in thread
From: Johannes Sixt @ 2018-06-26 21:00 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Elijah Newren, Git List, Jeff King, Jonathan Nieder,
	SZEDER Gábor, Stefan Beller, Jonathan Tan

Am 26.06.2018 um 20:14 schrieb Eric Sunshine:
> On Tue, Jun 26, 2018 at 2:06 PM Johannes Sixt <j6t@kdbg.org> wrote:
>> Hence, these lines should actually be
>>
>>                  p4 help client &&
>>                  ! p4 help nosuchcommand
> 
> Thanks for the comment; you're right, of course. I'll certainly make
> this change if I have to re-roll for some other reason, but do you
> feel that this itself is worth a re-roll?

Not worth a re-roll IMO.

-- Hannes

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 20:46         ` Eric Sunshine
@ 2018-06-26 21:01           ` Jeff King
  2018-06-26 21:13             ` Eric Sunshine
  2018-06-27  2:15             ` Elijah Newren
  0 siblings, 2 replies; 82+ messages in thread
From: Jeff King @ 2018-06-26 21:01 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Junio C Hamano, Git List, Jonathan Nieder, Stefan Beller,
	Elijah Newren, Jonathan Tan

On Tue, Jun 26, 2018 at 04:46:18PM -0400, Eric Sunshine wrote:

> > I'm not sure if there's a good solution, though. Even if you retained
> > the subshells and instead did a chain-lint inside each subshell, like
> > this:
> >
> >   (exit 117) &&
> >   one &&
> >   (
> >         (exit 117) &&
> >         cd foo
> >         two
> >   ) &&
> >   three
> 
> I thought of that too, but the inner (exit 117) doesn't even get
> invoked unless there is &&-chain breakage somewhere above that point
> (for instance, if "one" lacks "&&"), so the inner (exit 117) doesn't
> participate in the linting process at all.

Oh, right. Not only does it not fix the problem, it's totally
unworkable. :)

> Some of these dangers can be de-thoothed during the linting phase by
> defining do-nothing shell functions:
> 
>     cp () { :; }
>     mv () { :; }
>     ln () { :; }
> 
> That, at least, makes the scariest case ("rm") much less so.

Now that's an interesting idea. We can't catch every dangerous action
(notably ">" would be hard to override), but it should be pretty cheap
to cover some obvious ones.

-Peff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 20:17       ` Jeff King
  2018-06-26 20:22         ` Jeff King
  2018-06-26 20:46         ` Eric Sunshine
@ 2018-06-26 21:09         ` Junio C Hamano
  2 siblings, 0 replies; 82+ messages in thread
From: Junio C Hamano @ 2018-06-26 21:09 UTC (permalink / raw)
  To: Jeff King
  Cc: Eric Sunshine, Git List, Jonathan Nieder, Stefan Beller,
	Elijah Newren, Jonathan Tan

Jeff King <peff@peff.net> writes:

> One way this series might be worse in practice is that we tend not to
> change process state too much outside of the subshells.
> ...
> Whereas once you start collapsing subshells into the main logic chain,
> there's a very high chance that the subshell is doing a "cd", since
> that's typically the main reason for the subshell in the first place.

Exactly.  I should have mentioned this when I responded to save a
round-trip.


^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 21:01           ` Jeff King
@ 2018-06-26 21:13             ` Eric Sunshine
  2018-06-28 14:35               ` Jeff King
  2018-06-27  2:15             ` Elijah Newren
  1 sibling, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26 21:13 UTC (permalink / raw)
  To: Jeff King
  Cc: Junio C Hamano, Git List, Jonathan Nieder, Stefan Beller,
	Elijah Newren, Jonathan Tan

On Tue, Jun 26, 2018 at 5:01 PM Jeff King <peff@peff.net> wrote:
> On Tue, Jun 26, 2018 at 04:46:18PM -0400, Eric Sunshine wrote:
> > Some of these dangers can be de-thoothed during the linting phase by
> > defining do-nothing shell functions:
> >
> >     cp () { :; }
> >     mv () { :; }
> >     ln () { :; }
> >
> > That, at least, makes the scariest case ("rm") much less so.
>
> Now that's an interesting idea. We can't catch every dangerous action
> (notably ">" would be hard to override), but it should be pretty cheap
> to cover some obvious ones.

Taking the idea a bit further, the 'sed' script could also throw away
strings of "../" inside subshells, which would help defang the more
difficult cases, like "echo x >../git.c". There are pathological
cases, of course, which it wouldn't catch:

    P=../git.c
    test_expect_success 'foo' '
        (
            cd dir &&
            echo x >$P
        )
    '

but it does help mitigate the issue for the most typical cases.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/29] t: detect and fix broken &&-chains in subshells
  2018-06-26 19:38 ` Junio C Hamano
@ 2018-06-26 21:25   ` Eric Sunshine
  2018-06-26 22:31     ` Junio C Hamano
  0 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26 21:25 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git List, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Elijah Newren, Jonathan Tan

On Tue, Jun 26, 2018 at 3:38 PM Junio C Hamano <gitster@pobox.com> wrote:
> I first looked at 29/29 and got heavily inclined to reject that
> step, and then continued reading from 1/29 to around 15/29.
>
> I like these earlier changes that fix existing breakage, of course.
> I also like many of the changes that simplify and/or modernise the
> test scripts very much, but they are unusable as-is as long as their
> justification is "chain-lint will start barfing on these constructs".

Sorry, I'm having difficulty understanding.

Are you saying that you don't want patches which exist merely to
pacify --chain-lint? (For instance, 2/29 "t0001: use "{...}" block
around "||" expression rather than subshell".)

Or are you saying that you don't like how the commit messages are
worded, and that they should instead emphasize that the change is good
for its own sake, without mentioning --chain-lint?

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 20:22         ` Jeff King
  2018-06-26 20:59           ` Eric Sunshine
@ 2018-06-26 21:33           ` Elijah Newren
  2018-06-26 21:42             ` Eric Sunshine
  1 sibling, 1 reply; 82+ messages in thread
From: Elijah Newren @ 2018-06-26 21:33 UTC (permalink / raw)
  To: Jeff King
  Cc: Eric Sunshine, Junio C Hamano, Git List, Jonathan Nieder,
	Stefan Beller, Jonathan Tan

On Tue, Jun 26, 2018 at 1:22 PM, Jeff King <peff@peff.net> wrote:
> On Tue, Jun 26, 2018 at 04:17:08PM -0400, Jeff King wrote:
>
>> I'm not sure if there's a good solution, though. Even if you retained
>> the subshells and instead did a chain-lint inside each subshell, like
>> this:
>
> So obviously that means "I don't think there's a good solution with this
> approach".
>
> That whole final patch simultaneously impresses and nauseates me. Your
> commit message says "no attempt is made at properly parsing shell code",
> but we come pretty darn close. I almost wonder if we'd be better off
> just parsing some heuristic subset and making sure (via review or
> linting) that our tests conform.
>
> Another option is to not enable this slightly-more-dangerous linting by
> default. But that would probably rob it of its usefulness, since it
> would just fall to some brave soul to later crank up the linting and fix
> everybody else's mistakes.

This may be a dumb question, but why can't we run under errexit?  If
we could do that, we wouldn't need the &&-chaining, and bash would
parse the shell for us and exit whenever one command failed.  (Is the
reason for this documented somewhere?  I couldn't find it...)

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 21:33           ` Elijah Newren
@ 2018-06-26 21:42             ` Eric Sunshine
  0 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-26 21:42 UTC (permalink / raw)
  To: Elijah Newren
  Cc: Jeff King, Junio C Hamano, Git List, Jonathan Nieder,
	Stefan Beller, Jonathan Tan

On Tue, Jun 26, 2018 at 5:33 PM Elijah Newren <newren@gmail.com> wrote:
> On Tue, Jun 26, 2018 at 1:22 PM, Jeff King <peff@peff.net> wrote:
> > Another option is to not enable this slightly-more-dangerous linting by
> > default. But that would probably rob it of its usefulness, since it
> > would just fall to some brave soul to later crank up the linting and fix
> > everybody else's mistakes.
>
> This may be a dumb question, but why can't we run under errexit?  If
> we could do that, we wouldn't need the &&-chaining, and bash would
> parse the shell for us and exit whenever one command failed.  (Is the
> reason for this documented somewhere?  I couldn't find it...)

I'm not sure if it's documented anywhere, but it has been discussed.
In particular, see [1], especially [2], and [3]. Peff summed up by
saying:

    So I dunno. I think "set -e" is kind of a dangerous lure. It works
    so well _most_ of the time that you start to rely on it, but it
    really does have some funny corner cases (even on modern shells,
    and for all I know, the behavior above is mandated by POSIX).

[1]: https://public-inbox.org/git/xmqq384zha6s.fsf@gitster.dls.corp.google.com/
[2]: https://public-inbox.org/git/20150320172406.GA15172@peff.net/
[3]: https://public-inbox.org/git/xmqqoannfu84.fsf@gitster.dls.corp.google.com/

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/29] t: detect and fix broken &&-chains in subshells
  2018-06-26 21:25   ` Eric Sunshine
@ 2018-06-26 22:31     ` Junio C Hamano
  2018-06-27  0:22       ` Jonathan Nieder
  0 siblings, 1 reply; 82+ messages in thread
From: Junio C Hamano @ 2018-06-26 22:31 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git List, Jeff King, Jonathan Nieder, SZEDER Gábor,
	Stefan Beller, Elijah Newren, Jonathan Tan

Eric Sunshine <sunshine@sunshineco.com> writes:

> On Tue, Jun 26, 2018 at 3:38 PM Junio C Hamano <gitster@pobox.com> wrote:
>> I first looked at 29/29 and got heavily inclined to reject that
>> step, and then continued reading from 1/29 to around 15/29.
>>
>> I like these earlier changes that fix existing breakage, of course.
>> I also like many of the changes that simplify and/or modernise the
>> test scripts very much, but they are unusable as-is as long as their
>> justification is "chain-lint will start barfing on these constructs".
>
> Sorry, I'm having difficulty understanding.
>
> Are you saying that you don't want patches which exist merely to
> pacify --chain-lint? (For instance, 2/29 "t0001: use "{...}" block
> around "||" expression rather than subshell".)

Yes.

> Or are you saying that you don't like how the commit messages are
> worded, and that they should instead emphasize that the change is good
> for its own sake, without mentioning --chain-lint?

Yes, too.

For example, 03/29 is a good clean-up, and its value is not
diminished even if we reject the subprocess munging --chain-lint in
29/29.

As opposed to 02/29 which mostly is about appeasing the "shell
parser" in 29/29 (or you could justify it saying "one less fork and
process" if that gives us a measurable benefit).

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/29] t: detect and fix broken &&-chains in subshells
  2018-06-26 22:31     ` Junio C Hamano
@ 2018-06-27  0:22       ` Jonathan Nieder
  0 siblings, 0 replies; 82+ messages in thread
From: Jonathan Nieder @ 2018-06-27  0:22 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Eric Sunshine, Git List, Jeff King, SZEDER Gábor,
	Stefan Beller, Elijah Newren, Jonathan Tan

Jun 26, 2018 at 03:31:11PM -0700, Junio C Hamano wrote:
> Eric Sunshine <sunshine@sunshineco.com> writes:
>> On Tue, Jun 26, 2018 at 3:38 PM Junio C Hamano <gitster@pobox.com> wrote:

>>> I like these earlier changes that fix existing breakage, of course.
>>> I also like many of the changes that simplify and/or modernise the
>>> test scripts very much, but they are unusable as-is as long as their
>>> justification is "chain-lint will start barfing on these constructs".
>>
>> Sorry, I'm having difficulty understanding.
>>
>> Are you saying that you don't want patches which exist merely to
>> pacify --chain-lint? (For instance, 2/29 "t0001: use "{...}" block
>> around "||" expression rather than subshell".)
>
> Yes.
>
>> Or are you saying that you don't like how the commit messages are
>> worded, and that they should instead emphasize that the change is good
>> for its own sake, without mentioning --chain-lint?
>
> Yes, too.
>
> For example, 03/29 is a good clean-up, and its value is not
> diminished even if we reject the subprocess munging --chain-lint in
> 29/29.
>
> As opposed to 02/29 which mostly is about appeasing the "shell
> parser" in 29/29 (or you could justify it saying "one less fork and
> process" if that gives us a measurable benefit).

This is a lighter-weight example of the practice described at
https://lkml.kernel.org/r/alpine.LFD.2.00.1001251002430.3574@localhost.localdomain/.
In my opinion it's good advice, often worth repeating.

Thanks,
Jonathan

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 21:01           ` Jeff King
  2018-06-26 21:13             ` Eric Sunshine
@ 2018-06-27  2:15             ` Elijah Newren
  2018-06-27  6:27               ` Johannes Sixt
  2018-06-28 14:37               ` Jeff King
  1 sibling, 2 replies; 82+ messages in thread
From: Elijah Newren @ 2018-06-27  2:15 UTC (permalink / raw)
  To: Jeff King
  Cc: Eric Sunshine, Junio C Hamano, Git List, Jonathan Nieder,
	Stefan Beller, Jonathan Tan

On Tue, Jun 26, 2018 at 2:01 PM, Jeff King <peff@peff.net> wrote:
> On Tue, Jun 26, 2018 at 04:46:18PM -0400, Eric Sunshine wrote:

>> Some of these dangers can be de-thoothed during the linting phase by
>> defining do-nothing shell functions:
>>
>>     cp () { :; }
>>     mv () { :; }
>>     ln () { :; }
>>
>> That, at least, makes the scariest case ("rm") much less so.
>
> Now that's an interesting idea. We can't catch every dangerous action
> (notably ">" would be hard to override), but it should be pretty cheap
> to cover some obvious ones.
>
> -Peff

Crazy idea: maybe we could defang it a little more thoroughly with
something like the following (apologies in advance if gmail whitespace
damages this):

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 28315706be..7fda08a90a 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -675,7 +675,7 @@ test_run_ () {
                trace=
                # 117 is magic because it is unlikely to match the exit
                # code of other programs
-               if test "OK-117" != "$(test_eval_ "(exit 117) &&
$1${LF}${LF}echo OK-\$?" 3>&1)"
+               if test "OK-117" != "$(test_eval_ "cd() { return 0; }
&& PATH=/dev/null && export PATH && (exit 117) && $1${LF}${LF}echo
OK-\$?" 3>&1)"
                then
                        error "bug in the test script: broken &&-chain
or run-away HERE-DOC: $1"
                fi

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-27  2:15             ` Elijah Newren
@ 2018-06-27  6:27               ` Johannes Sixt
  2018-06-27  6:48                 ` Eric Sunshine
  2018-06-28 14:37               ` Jeff King
  1 sibling, 1 reply; 82+ messages in thread
From: Johannes Sixt @ 2018-06-27  6:27 UTC (permalink / raw)
  To: Elijah Newren, Jeff King
  Cc: Eric Sunshine, Junio C Hamano, Git List, Jonathan Nieder,
	Stefan Beller, Jonathan Tan

Am 27.06.2018 um 04:15 schrieb Elijah Newren:
> On Tue, Jun 26, 2018 at 2:01 PM, Jeff King <peff@peff.net> wrote:
>> On Tue, Jun 26, 2018 at 04:46:18PM -0400, Eric Sunshine wrote:
> 
>>> Some of these dangers can be de-thoothed during the linting phase by
>>> defining do-nothing shell functions:
>>>
>>>      cp () { :; }
>>>      mv () { :; }
>>>      ln () { :; }
>>>
>>> That, at least, makes the scariest case ("rm") much less so.
>>
>> Now that's an interesting idea. We can't catch every dangerous action
>> (notably ">" would be hard to override), but it should be pretty cheap
>> to cover some obvious ones.
>>
>> -Peff
> 
> Crazy idea: maybe we could defang it a little more thoroughly with
> something like the following (apologies in advance if gmail whitespace
> damages this):
> 
> diff --git a/t/test-lib.sh b/t/test-lib.sh
> index 28315706be..7fda08a90a 100644
> --- a/t/test-lib.sh
> +++ b/t/test-lib.sh
> @@ -675,7 +675,7 @@ test_run_ () {
>                  trace=
>                  # 117 is magic because it is unlikely to match the exit
>                  # code of other programs
> -               if test "OK-117" != "$(test_eval_ "(exit 117) &&
> $1${LF}${LF}echo OK-\$?" 3>&1)"
> +               if test "OK-117" != "$(test_eval_ "cd() { return 0; }
> && PATH=/dev/null && export PATH && (exit 117) && $1${LF}${LF}echo
> OK-\$?" 3>&1)"
>                  then
>                          error "bug in the test script: broken &&-chain
> or run-away HERE-DOC: $1"
>                  fi

I'd define all these functions as { return 1; } because we want to stop 
any && chain as early as possible (and with an exit code that is not the 
sentinel value).

-- Hannes

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-27  6:27               ` Johannes Sixt
@ 2018-06-27  6:48                 ` Eric Sunshine
  0 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-27  6:48 UTC (permalink / raw)
  To: Johannes Sixt
  Cc: Elijah Newren, Jeff King, Junio C Hamano, Git List,
	Jonathan Nieder, Stefan Beller, Jonathan Tan

On Wed, Jun 27, 2018 at 2:27 AM Johannes Sixt <j6t@kdbg.org> wrote:
> Am 27.06.2018 um 04:15 schrieb Elijah Newren:
> > On Tue, Jun 26, 2018 at 2:01 PM, Jeff King <peff@peff.net> wrote:
> >> On Tue, Jun 26, 2018 at 04:46:18PM -0400, Eric Sunshine wrote:
> >>> Some of these dangers can be de-thoothed during the linting phase by
> >>> defining do-nothing shell functions:
> >>>      cp () { :; }
> >>> That, at least, makes the scariest case ("rm") much less so.
> >>
> >> Now that's an interesting idea. We can't catch every dangerous action
> >> (notably ">" would be hard to override), but it should be pretty cheap
> >> to cover some obvious ones.
> >
> > Crazy idea: maybe we could defang it a little more thoroughly with
> > something like the following (apologies in advance if gmail whitespace
> > damages this):
> >
> > -               if test "OK-117" != "$(test_eval_ "(exit 117) &&
> > $1${LF}${LF}echo OK-\$?" 3>&1)"
> > +               if test "OK-117" != "$(test_eval_ "cd() { return 0; }
> > && PATH=/dev/null && export PATH && (exit 117) && $1${LF}${LF}echo
> > OK-\$?" 3>&1)"

Interesting idea (coupled with Hannes's point below)...

> I'd define all these functions as { return 1; } because we want to stop
> any && chain as early as possible (and with an exit code that is not the
> sentinel value).

A very sensible suggestion.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 08/29] t7400: fix broken "submodule add/reconfigure --force" test
  2018-06-26  7:29 ` [PATCH 08/29] t7400: fix broken "submodule add/reconfigure --force" test Eric Sunshine
@ 2018-06-27 18:04   ` Stefan Beller
  0 siblings, 0 replies; 82+ messages in thread
From: Stefan Beller @ 2018-06-27 18:04 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: git, Jeff King, Jonathan Nieder, szeder, Elijah Newren, Jonathan Tan

On Tue, Jun 26, 2018 at 12:30 AM Eric Sunshine <sunshine@sunshineco.com> wrote:
>
> This test has been dysfunctional since it was added by 619acfc78c
> (submodule add: extend force flag to add existing repos, 2016-10-06),
> however, two problems early in the test went unnoticed due to a broken
> &&-chain later in the test.
>
> First, it tries configuring the submodule with repository "bogus-url",
> however, "git submodule add" insists that the repository be either an
> absolute URL or a relative pathname requiring prefix "./" or "../" (this
> is true even with --force), but "bogus-url" does not meet those
> criteria, thus the command fails.
>
> Second, it then tries configuring a submodule with a path which is
> .gitignore'd, which is disallowed. This restriction can be overridden
> with --force, but the test neglects to use that option.
>
> Fix both problems, as well as the broken &&-chain behind which they hid.
>
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>

This patch is
Reviewed-by: Stefan Beller <sbeller@google.com>

Thanks for this whole series (I just read the cover letter) and I think
detecting broken && chains is a valuable part in the test suite.

Thanks,
Stefan

> ---
>  t/t7400-submodule-basic.sh | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
> index 812db137b8..401adaed32 100755
> --- a/t/t7400-submodule-basic.sh
> +++ b/t/t7400-submodule-basic.sh
> @@ -171,12 +171,12 @@ test_expect_success 'submodule add to .gitignored path with --force' '
>  test_expect_success 'submodule add to reconfigure existing submodule with --force' '
>         (
>                 cd addtest-ignore &&
> -               git submodule add --force bogus-url submod &&
> -               git submodule add -b initial "$submodurl" submod-branch &&
> -               test "bogus-url" = "$(git config -f .gitmodules submodule.submod.url)" &&
> -               test "bogus-url" = "$(git config submodule.submod.url)" &&
> +               git submodule add --force /bogus-url submod &&
> +               git submodule add --force -b initial "$submodurl" submod-branch &&
> +               test "/bogus-url" = "$(git config -f .gitmodules submodule.submod.url)" &&
> +               test "/bogus-url" = "$(git config submodule.submod.url)" &&
>                 # Restore the url
> -               git submodule add --force "$submodurl" submod
> +               git submodule add --force "$submodurl" submod &&
>                 test "$submodurl" = "$(git config -f .gitmodules submodule.submod.url)" &&
>                 test "$submodurl" = "$(git config submodule.submod.url)"
>         )
> --
> 2.18.0.419.gfe4b301394
>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH] t/lib-submodule-update: fix absorbing test
  2018-06-26  7:29 ` [PATCH 13/29] t/lib-submodule-update: fix broken "replace submodule must-fail" test Eric Sunshine
@ 2018-06-27 18:30   ` Stefan Beller
  2018-06-27 18:38     ` Eric Sunshine
  0 siblings, 1 reply; 82+ messages in thread
From: Stefan Beller @ 2018-06-27 18:30 UTC (permalink / raw)
  To: sunshine; +Cc: git, jonathantanmy, jrnieder, newren, peff, sbeller, szeder

From: Eric Sunshine <sunshine@sunshineco.com>

This test has been dysfunctional since it was added by 259f3ee296
(lib-submodule-update.sh: define tests for recursing into submodules,
2017-03-14), however, problems went unnoticed due to a broken &&-chain
toward the end of the test.

The test wants to verify that replacing a submodule containing a .git
directory would absorb the .git directory into the .git/modules/ of the
superproject, and then replace the working tree content with the liking of
the superproject. The check if submodule content is around is wrong as
the submodule should have been replaced by the content of the superproject.

Delete the submodule content check, which also fixes the && chain in the
test.

While at it, fix broken &&-chains in a couple neighboring tests.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---

> The test wants to verify that replacing a submodule containing a .git
> directory must fail. All other "must fail" tests in this script invoke
> the supplied command as 'test_must_fail', however, this test neglects to
> do so.

In an ideal world the commands would not fail, but absorb the git directory
of the submodule. I manually tested that it is absorbed and not data from
a git directory is lost.

I would propose to replace that patch with the patch below; I hope
the wording did not add more confusion than there is already.

Thanks,
Stefan


 t/lib-submodule-update.sh | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
index 1f38a85371a..e90ec790877 100755
--- a/t/lib-submodule-update.sh
+++ b/t/lib-submodule-update.sh
@@ -755,7 +755,7 @@ test_submodule_recursing_with_args_common() {
 			: >sub1/untrackedfile &&
 			test_must_fail $command replace_sub1_with_file &&
 			test_superproject_content origin/add_sub1 &&
-			test_submodule_content sub1 origin/add_sub1
+			test_submodule_content sub1 origin/add_sub1 &&
 			test -f sub1/untracked_file
 		)
 	'
@@ -842,7 +842,7 @@ test_submodule_switch_recursing_with_args () {
 			cd submodule_update &&
 			git branch -t add_sub1 origin/add_sub1 &&
 			: >sub1 &&
-			echo sub1 >.git/info/exclude
+			echo sub1 >.git/info/exclude &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -969,7 +969,6 @@ test_submodule_forced_switch_recursing_with_args () {
 			rm -rf .git/modules/sub1 &&
 			$command replace_sub1_with_directory &&
 			test_superproject_content origin/replace_sub1_with_directory &&
-			test_submodule_content sub1 origin/modify_sub1
 			test_git_directory_exists sub1
 		)
 	'
-- 
2.18.0.399.gad0ab374a1-goog


^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH] t/lib-submodule-update: fix absorbing test
  2018-06-27 18:30   ` [PATCH] t/lib-submodule-update: fix absorbing test Stefan Beller
@ 2018-06-27 18:38     ` Eric Sunshine
  0 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-06-27 18:38 UTC (permalink / raw)
  To: Stefan Beller
  Cc: Git List, Jonathan Tan, Jonathan Nieder, Elijah Newren,
	Jeff King, SZEDER Gábor

On Wed, Jun 27, 2018 at 2:31 PM Stefan Beller <sbeller@google.com> wrote:
> From: Eric Sunshine <sunshine@sunshineco.com>
>
> This test has been dysfunctional since it was added by 259f3ee296
> (lib-submodule-update.sh: define tests for recursing into submodules,
> 2017-03-14), however, problems went unnoticed due to a broken &&-chain
> toward the end of the test.
> [...]
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> Signed-off-by: Stefan Beller <sbeller@google.com>
> ---
> In an ideal world the commands would not fail, but absorb the git directory
> of the submodule. I manually tested that it is absorbed and not data from
> a git directory is lost.
>
> I would propose to replace that patch with the patch below; I hope
> the wording did not add more confusion than there is already.

Thanks for diagnosing the problem, Stefan. I'm not a submodule user
and was not at all confident that I had interpreted the test breakage
correctly or that my fix was appropriate, so I'm happy to have a
diagnosis and fix from the person who actually wrote the test.

I'll also add a Helped-by: when re-posting.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-26 21:13             ` Eric Sunshine
@ 2018-06-28 14:35               ` Jeff King
  0 siblings, 0 replies; 82+ messages in thread
From: Jeff King @ 2018-06-28 14:35 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Junio C Hamano, Git List, Jonathan Nieder, Stefan Beller,
	Elijah Newren, Jonathan Tan

On Tue, Jun 26, 2018 at 05:13:05PM -0400, Eric Sunshine wrote:

> On Tue, Jun 26, 2018 at 5:01 PM Jeff King <peff@peff.net> wrote:
> > On Tue, Jun 26, 2018 at 04:46:18PM -0400, Eric Sunshine wrote:
> > > Some of these dangers can be de-thoothed during the linting phase by
> > > defining do-nothing shell functions:
> > >
> > >     cp () { :; }
> > >     mv () { :; }
> > >     ln () { :; }
> > >
> > > That, at least, makes the scariest case ("rm") much less so.
> >
> > Now that's an interesting idea. We can't catch every dangerous action
> > (notably ">" would be hard to override), but it should be pretty cheap
> > to cover some obvious ones.
> 
> Taking the idea a bit further, the 'sed' script could also throw away
> strings of "../" inside subshells, which would help defang the more
> difficult cases, like "echo x >../git.c". There are pathological
> cases, of course, which it wouldn't catch:
> 
>     P=../git.c
>     test_expect_success 'foo' '
>         (
>             cd dir &&
>             echo x >$P
>         )
>     '
> 
> but it does help mitigate the issue for the most typical cases.

It seems like the dangerous thing there is ">", not necessarily "..".
Could we just s/>/x/g ?

That "breaks" the commands in a sense, but the whole point is that these
commands shouldn't ever be run in the first place.

-Peff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 29/29] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-06-27  2:15             ` Elijah Newren
  2018-06-27  6:27               ` Johannes Sixt
@ 2018-06-28 14:37               ` Jeff King
  1 sibling, 0 replies; 82+ messages in thread
From: Jeff King @ 2018-06-28 14:37 UTC (permalink / raw)
  To: Elijah Newren
  Cc: Eric Sunshine, Junio C Hamano, Git List, Jonathan Nieder,
	Stefan Beller, Jonathan Tan

On Tue, Jun 26, 2018 at 07:15:45PM -0700, Elijah Newren wrote:

> Crazy idea: maybe we could defang it a little more thoroughly with
> something like the following (apologies in advance if gmail whitespace
> damages this):
> 
> diff --git a/t/test-lib.sh b/t/test-lib.sh
> index 28315706be..7fda08a90a 100644
> --- a/t/test-lib.sh
> +++ b/t/test-lib.sh
> @@ -675,7 +675,7 @@ test_run_ () {
>                 trace=
>                 # 117 is magic because it is unlikely to match the exit
>                 # code of other programs
> -               if test "OK-117" != "$(test_eval_ "(exit 117) &&
> $1${LF}${LF}echo OK-\$?" 3>&1)"
> +               if test "OK-117" != "$(test_eval_ "cd() { return 0; }
> && PATH=/dev/null && export PATH && (exit 117) && $1${LF}${LF}echo
> OK-\$?" 3>&1)"

Clever. We'd still run shell builtins, which is why you need the cd()
above. There may be others, but at least it narrows things down. Unless
the shell is busybox or something, and implements everything as a
builtin. :)

I agree on the point elsewhere of returning non-zero (and the items
missing from PATH should do that, which is good).

-Peff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v2 00/10] detect broken &&-chains in subshells
  2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
                   ` (30 preceding siblings ...)
  2018-06-26 19:38 ` Junio C Hamano
@ 2018-07-11  6:46 ` " Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 01/10] t/test-lib: teach --chain-lint to " Eric Sunshine
                     ` (9 more replies)
  31 siblings, 10 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-07-11  6:46 UTC (permalink / raw)
  To: git
  Cc: Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Junio C Hamano, Luke Diamand, Jeff King,
	Eric Sunshine

This is a re-roll of [1] which teaches --chain-lint to detect broken
&&-chains in subshells since the existing implementation[2] detects
breakage only at the top-level. It is built atop 'es/test-fixes', which
was split off of [1] and submitted separately[3], and which fixes many
broken &&-chains.

The major difference since v1 is that broken &&-chains in subshells are
now detected by pure textual inspection rather than by merging subshell
commands into the top-level &&-chain. Thus, v2 entirely sidesteps the
primary objection[4] raised during v1 review of possible unintended
side-effects of test code executing outside of the intended directory.
The pure textual detection implemented by v2 can have no such
side-effects.

A second important difference since v1 is that the "linter" itself, a
complex 'sed' script, now has its own tests to ensure correct behavior.
Not only do the tests protect against regressions, but they help to
document (for humans) expected behavior, which is important since 'sed'
scripts can seem rather inscrutable due to looking like line-noise and
due to the 'sed' "language" being stack-oriented (albeit with a very
tiny stack) which, like other stack-oriented languages (Forth,
Postscript, etc.) can be difficult to reason about.

Although the 'sed' script in v1 was already well-commented, the comments
have been improved in v2. More importantly, a high-level overview of the
script's operation has been added at the top of the file to aid
comprehension.

Thanks to Elijah, Hannes, Jonathan Nieder, Jonathan Tan, Junio, Luke,
Peff, and Stefan for comments on v1.

[1]: https://public-inbox.org/git/20180626073001.6555-1-sunshine@sunshineco.com/
[2]: https://public-inbox.org/git/20150320100429.GA17354@peff.net/
[3]: https://public-inbox.org/git/20180702002405.3042-1-sunshine@sunshineco.com/
[4]: https://public-inbox.org/git/xmqqwouljr5e.fsf@gitster-ct.c.googlers.com/

Eric Sunshine (10):
  t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  t/Makefile: add machinery to check correctness of chainlint.sed
  t/chainlint: add chainlint "basic" test cases
  t/chainlint: add chainlint "whitespace" test cases
  t/chainlint: add chainlint "one-liner" test cases
  t/chainlint: add chainlint "nested subshell" test cases
  t/chainlint: add chainlint "loop" and "conditional" test cases
  t/chainlint: add chainlint "cuddled" test cases
  t/chainlint: add chainlint "complex" test cases
  t/chainlint: add chainlint "specialized" test cases

 t/.gitignore                                  |   1 +
 t/Makefile                                    |  25 +-
 t/chainlint.sed                               | 346 ++++++++++++++++++
 t/chainlint/arithmetic-expansion.expect       |   9 +
 t/chainlint/arithmetic-expansion.test         |  11 +
 t/chainlint/bash-array.expect                 |  10 +
 t/chainlint/bash-array.test                   |  12 +
 t/chainlint/blank-line.expect                 |   4 +
 t/chainlint/blank-line.test                   |  10 +
 t/chainlint/block.expect                      |  12 +
 t/chainlint/block.test                        |  15 +
 t/chainlint/broken-chain.expect               |   6 +
 t/chainlint/broken-chain.test                 |   8 +
 t/chainlint/case.expect                       |  19 +
 t/chainlint/case.test                         |  23 ++
 .../close-nested-and-parent-together.expect   |   4 +
 .../close-nested-and-parent-together.test     |   3 +
 t/chainlint/close-subshell.expect             |  25 ++
 t/chainlint/close-subshell.test               |  27 ++
 t/chainlint/command-substitution.expect       |   9 +
 t/chainlint/command-substitution.test         |  11 +
 t/chainlint/comment.expect                    |   4 +
 t/chainlint/comment.test                      |  11 +
 t/chainlint/complex-if-in-cuddled-loop.expect |  10 +
 t/chainlint/complex-if-in-cuddled-loop.test   |  11 +
 t/chainlint/cuddled-if-then-else.expect       |   7 +
 t/chainlint/cuddled-if-then-else.test         |   7 +
 t/chainlint/cuddled-loop.expect               |   5 +
 t/chainlint/cuddled-loop.test                 |   7 +
 t/chainlint/cuddled.expect                    |  21 ++
 t/chainlint/cuddled.test                      |  23 ++
 t/chainlint/exit-loop.expect                  |  24 ++
 t/chainlint/exit-loop.test                    |  27 ++
 t/chainlint/exit-subshell.expect              |   5 +
 t/chainlint/exit-subshell.test                |   6 +
 t/chainlint/for-loop.expect                   |  11 +
 t/chainlint/for-loop.test                     |  19 +
 t/chainlint/here-doc.expect                   |   3 +
 t/chainlint/here-doc.test                     |  16 +
 t/chainlint/if-in-loop.expect                 |  12 +
 t/chainlint/if-in-loop.test                   |  15 +
 t/chainlint/if-then-else.expect               |  19 +
 t/chainlint/if-then-else.test                 |  28 ++
 t/chainlint/incomplete-line.expect            |   4 +
 t/chainlint/incomplete-line.test              |  12 +
 t/chainlint/inline-comment.expect             |   9 +
 t/chainlint/inline-comment.test               |  12 +
 t/chainlint/loop-in-if.expect                 |  12 +
 t/chainlint/loop-in-if.test                   |  15 +
 ...ti-line-nested-command-substitution.expect |   9 +
 ...ulti-line-nested-command-substitution.test |   9 +
 t/chainlint/multi-line-string.expect          |   9 +
 t/chainlint/multi-line-string.test            |  15 +
 t/chainlint/negated-one-liner.expect          |   5 +
 t/chainlint/negated-one-liner.test            |   7 +
 t/chainlint/nested-cuddled-subshell.expect    |  19 +
 t/chainlint/nested-cuddled-subshell.test      |  31 ++
 t/chainlint/nested-here-doc.expect            |   5 +
 t/chainlint/nested-here-doc.test              |  23 ++
 t/chainlint/nested-subshell-comment.expect    |  11 +
 t/chainlint/nested-subshell-comment.test      |  13 +
 t/chainlint/nested-subshell.expect            |  12 +
 t/chainlint/nested-subshell.test              |  14 +
 t/chainlint/one-liner.expect                  |   9 +
 t/chainlint/one-liner.test                    |  12 +
 t/chainlint/p4-filespec.expect                |   4 +
 t/chainlint/p4-filespec.test                  |   5 +
 t/chainlint/pipe.expect                       |   8 +
 t/chainlint/pipe.test                         |  12 +
 t/chainlint/semicolon.expect                  |  20 +
 t/chainlint/semicolon.test                    |  25 ++
 t/chainlint/subshell-here-doc.expect          |   5 +
 t/chainlint/subshell-here-doc.test            |  23 ++
 t/chainlint/subshell-one-liner.expect         |  14 +
 t/chainlint/subshell-one-liner.test           |  24 ++
 t/chainlint/while-loop.expect                 |  11 +
 t/chainlint/while-loop.test                   |  19 +
 t/test-lib.sh                                 |   3 +-
 78 files changed, 1316 insertions(+), 5 deletions(-)
 create mode 100644 t/chainlint.sed
 create mode 100644 t/chainlint/arithmetic-expansion.expect
 create mode 100644 t/chainlint/arithmetic-expansion.test
 create mode 100644 t/chainlint/bash-array.expect
 create mode 100644 t/chainlint/bash-array.test
 create mode 100644 t/chainlint/blank-line.expect
 create mode 100644 t/chainlint/blank-line.test
 create mode 100644 t/chainlint/block.expect
 create mode 100644 t/chainlint/block.test
 create mode 100644 t/chainlint/broken-chain.expect
 create mode 100644 t/chainlint/broken-chain.test
 create mode 100644 t/chainlint/case.expect
 create mode 100644 t/chainlint/case.test
 create mode 100644 t/chainlint/close-nested-and-parent-together.expect
 create mode 100644 t/chainlint/close-nested-and-parent-together.test
 create mode 100644 t/chainlint/close-subshell.expect
 create mode 100644 t/chainlint/close-subshell.test
 create mode 100644 t/chainlint/command-substitution.expect
 create mode 100644 t/chainlint/command-substitution.test
 create mode 100644 t/chainlint/comment.expect
 create mode 100644 t/chainlint/comment.test
 create mode 100644 t/chainlint/complex-if-in-cuddled-loop.expect
 create mode 100644 t/chainlint/complex-if-in-cuddled-loop.test
 create mode 100644 t/chainlint/cuddled-if-then-else.expect
 create mode 100644 t/chainlint/cuddled-if-then-else.test
 create mode 100644 t/chainlint/cuddled-loop.expect
 create mode 100644 t/chainlint/cuddled-loop.test
 create mode 100644 t/chainlint/cuddled.expect
 create mode 100644 t/chainlint/cuddled.test
 create mode 100644 t/chainlint/exit-loop.expect
 create mode 100644 t/chainlint/exit-loop.test
 create mode 100644 t/chainlint/exit-subshell.expect
 create mode 100644 t/chainlint/exit-subshell.test
 create mode 100644 t/chainlint/for-loop.expect
 create mode 100644 t/chainlint/for-loop.test
 create mode 100644 t/chainlint/here-doc.expect
 create mode 100644 t/chainlint/here-doc.test
 create mode 100644 t/chainlint/if-in-loop.expect
 create mode 100644 t/chainlint/if-in-loop.test
 create mode 100644 t/chainlint/if-then-else.expect
 create mode 100644 t/chainlint/if-then-else.test
 create mode 100644 t/chainlint/incomplete-line.expect
 create mode 100644 t/chainlint/incomplete-line.test
 create mode 100644 t/chainlint/inline-comment.expect
 create mode 100644 t/chainlint/inline-comment.test
 create mode 100644 t/chainlint/loop-in-if.expect
 create mode 100644 t/chainlint/loop-in-if.test
 create mode 100644 t/chainlint/multi-line-nested-command-substitution.expect
 create mode 100644 t/chainlint/multi-line-nested-command-substitution.test
 create mode 100644 t/chainlint/multi-line-string.expect
 create mode 100644 t/chainlint/multi-line-string.test
 create mode 100644 t/chainlint/negated-one-liner.expect
 create mode 100644 t/chainlint/negated-one-liner.test
 create mode 100644 t/chainlint/nested-cuddled-subshell.expect
 create mode 100644 t/chainlint/nested-cuddled-subshell.test
 create mode 100644 t/chainlint/nested-here-doc.expect
 create mode 100644 t/chainlint/nested-here-doc.test
 create mode 100644 t/chainlint/nested-subshell-comment.expect
 create mode 100644 t/chainlint/nested-subshell-comment.test
 create mode 100644 t/chainlint/nested-subshell.expect
 create mode 100644 t/chainlint/nested-subshell.test
 create mode 100644 t/chainlint/one-liner.expect
 create mode 100644 t/chainlint/one-liner.test
 create mode 100644 t/chainlint/p4-filespec.expect
 create mode 100644 t/chainlint/p4-filespec.test
 create mode 100644 t/chainlint/pipe.expect
 create mode 100644 t/chainlint/pipe.test
 create mode 100644 t/chainlint/semicolon.expect
 create mode 100644 t/chainlint/semicolon.test
 create mode 100644 t/chainlint/subshell-here-doc.expect
 create mode 100644 t/chainlint/subshell-here-doc.test
 create mode 100644 t/chainlint/subshell-one-liner.expect
 create mode 100644 t/chainlint/subshell-one-liner.test
 create mode 100644 t/chainlint/while-loop.expect
 create mode 100644 t/chainlint/while-loop.test

-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v2 01/10] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
@ 2018-07-11  6:46   ` " Eric Sunshine
  2018-07-11 21:37     ` Junio C Hamano
  2018-07-11  6:46   ` [PATCH v2 02/10] t/Makefile: add machinery to check correctness of chainlint.sed Eric Sunshine
                     ` (8 subsequent siblings)
  9 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-07-11  6:46 UTC (permalink / raw)
  To: git
  Cc: Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Junio C Hamano, Luke Diamand, Jeff King,
	Eric Sunshine

The --chain-lint option detects broken &&-chains by forcing the test to
exit early (as the very first step) with a sentinel value. If that
sentinel is the test's overall exit code, then the &&-chain is intact;
if not, then the chain is broken. Unfortunately, this detection does not
extend to &&-chains within subshells even when the subshell itself is
properly linked into the outer &&-chain.

Address this shortcoming by feeding the body of the test to a
lightweight "linter" which can peer inside subshells and identify broken
&&-chains by pure textual inspection. Although the linter does not
actually parse shell scripts, it has enough knowledge of shell syntax to
reliably deal with formatting style variations (as evolved over the
years) and to avoid being fooled by non-shell content (such as inside
here-docs and multi-line strings). It recognizes modern subshell
formatting:

    statement1 &&
    (
        statement2 &&
        statement3
    ) &&
    statement4

as well as old-style:

    statement1 &&
    (statement2 &&
     statement3) &&
    statement4

Heuristics are employed to properly identify the extent of a subshell
formatted in the old-style since a number of legitimate constructs may
superficially appear to close the subshell even though they don't. For
example, it understands that neither "x=$(command)" nor "case $x in *)"
end a subshell, despite the ")" at the end of line.

Due to limitations of the tool used ('sed') and its inherent
line-by-line processing, only subshells one level deep are handled, as
well as one-liner subshells one level below that. Subshells deeper than
that or multi-line subshells at level two are passed through as-is, thus
&&-chains in their bodies are not checked.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/chainlint.sed | 346 ++++++++++++++++++++++++++++++++++++++++++++++++
 t/test-lib.sh   |   3 +-
 2 files changed, 348 insertions(+), 1 deletion(-)
 create mode 100644 t/chainlint.sed

diff --git a/t/chainlint.sed b/t/chainlint.sed
new file mode 100644
index 0000000000..a0de8a3882
--- /dev/null
+++ b/t/chainlint.sed
@@ -0,0 +1,346 @@
+#------------------------------------------------------------------------------
+# Detect broken &&-chains in tests.
+#
+# At present, only &&-chains in subshells are examined by this linter;
+# top-level &&-chains are instead checked directly by the test framework. Like
+# the top-level &&-chain linter, the subshell linter (intentionally) does not
+# check &&-chains within {...} blocks.
+#
+# Checking for &&-chain breakage is done line-by-line by pure textual
+# inspection.
+#
+# Incomplete lines (those ending with "\") are stitched together with following
+# lines to simplify processing, particularly of "one-liner" statements.
+# Top-level here-docs are swallowed to avoid false positives within the
+# here-doc body, although the statement to which the here-doc is attached is
+# retained.
+#
+# Heuristics are used to detect end-of-subshell when the closing ")" is cuddled
+# with the final subshell statement on the same line:
+#
+#    (cd foo &&
+#        bar)
+#
+# in order to avoid misinterpreting the ")" in constructs such as "x=$(...)"
+# and "case $x in *)" as ending the subshell.
+#
+# Lines missing a final "&&" are flagged with "?!AMP?!", and lines which chain
+# commands with ";" internally rather than "&&" are flagged "?!SEMI?!". A line
+# may be flagged for both violations.
+#
+# Detection of a missing &&-link in a multi-line subshell is complicated by the
+# fact that the last statement before the closing ")" must not end with "&&".
+# Since processing is line-by-line, it is not known whether a missing "&&" is
+# legitimate or not until the _next_ line is seen. To accommodate this, within
+# multi-line subshells, each line is stored in sed's "hold" area until after
+# the next line is seen and processed. If the next line is a stand-alone ")",
+# then a missing "&&" on the previous line is legitimate; otherwise a missing
+# "&&" is a break in the &&-chain.
+#
+#    (
+#         cd foo &&
+#         bar
+#    )
+#
+# In practical terms, when "bar" is encountered, it is flagged with "?!AMP?!",
+# but when the stand-alone ")" line is seen which closes the subshell, the
+# "?!AMP?!" violation is removed from the "bar" line (retrieved from the "hold"
+# area) since the final statement of a subshell must not end with "&&". The
+# final line of a subshell may still break the &&-chain by using ";" internally
+# to chain commands together rather than "&&", so "?!SEMI?!" is never removed
+# from a line (even though "?!AMP?!" might be).
+#
+# Care is taken to recognize the last _statement_ of a multi-line subshell, not
+# necessarily the last textual _line_ within the subshell, since &&-chaining
+# applies to statements, not to lines. Consequently, blank lines, comment
+# lines, and here-docs are swallowed (but not the command to which the here-doc
+# is attached), leaving the last statement in the "hold" area, not the last
+# line, thus simplifying &&-link checking.
+#
+# The final statement before "done" in for- and while-loops, and before "elif",
+# "else", and "fi" in if-then-else likewise must not end with "&&", thus
+# receives similar treatment.
+#
+# To facilitate regression testing (and manual debugging), a ">" annotation is
+# applied to the line containing ")" which closes a subshell, ">>" to a line
+# closing a nested subshell, and ">>>" to a line closing both at once. This
+# makes it easy to detect whether the heuristics correctly identify
+# end-of-subshell.
+#------------------------------------------------------------------------------
+
+# incomplete line -- slurp up next line
+:squash
+/\\$/ {
+      N
+      s/\\\n//
+      bsquash
+}
+
+# here-doc -- swallow it to avoid false hits within its body (but keep the
+# command to which it was attached)
+/<<[ 	]*[-\\]*EOF[ 	]*/ {
+	s/[ 	]*<<[ 	]*[-\\]*EOF//
+	h
+	:hereslurp
+	N
+	s/.*\n//
+	/^[ 	]*EOF[ 	]*$/!bhereslurp
+	x
+}
+
+# one-liner "(...) &&"
+/^[ 	]*!*[ 	]*(..*)[ 	]*&&[ 	]*$/boneline
+
+# same as above but without trailing "&&"
+/^[ 	]*!*[ 	]*(..*)[ 	]*$/boneline
+
+# one-liner "(...) >x" (or "2>x" or "<x" or "|x" or "&"
+/^[ 	]*!*[ 	]*(..*)[ 	]*[0-9]*[<>|&]/boneline
+
+# multi-line "(...\n...)"
+/^[ 	]*(/bsubshell
+
+# innocuous line -- print it and advance to next line
+b
+
+# found one-liner "(...)" -- mark suspect if it uses ";" internally rather than
+# "&&" (but not ";" in a string)
+:oneline
+/;/{
+	/"[^"]*;[^"]*"/!s/^/?!SEMI?!/
+}
+b
+
+:subshell
+# bare "(" line?
+/^[ 	]*([	]*$/ {
+	# stash for later printing
+	h
+	bnextline
+}
+# "(..." line -- split off and stash "(", then process "..." as its own line
+x
+s/.*/(/
+x
+s/(//
+bslurp
+
+:nextline
+N
+s/.*\n//
+
+:slurp
+# incomplete line "...\"
+/\\$/bincomplete
+# multi-line quoted string "...\n..."
+/^[^"]*"[^"]*$/bdqstring
+# multi-line quoted string '...\n...' (but not contraction in string "it's so")
+/^[^']*'[^']*$/{
+	/"[^'"]*'[^'"]*"/!bsqstring
+}
+# here-doc -- swallow it
+/<<[ 	]*[-\\]*EOF/bheredoc
+/<<[ 	]*[-\\]*EOT/bheredoc
+/<<[ 	]*[-\\]*INPUT_END/bheredoc
+# comment or empty line -- discard since final non-comment, non-empty line
+# before closing ")", "done", "elsif", "else", or "fi" will need to be
+# re-visited to drop "suspect" marking since final line of those constructs
+# legitimately lacks "&&", so "suspect" mark must be removed
+/^[ 	]*#/bnextline
+/^[ 	]*$/bnextline
+# in-line comment -- strip it (but not "#" in a string, Bash ${#...} array
+# length, or Perforce "//depot/path#42" revision in filespec)
+/[ 	]#/{
+	/"[^"]*#[^"]*"/!s/[ 	]#.*$//
+}
+# one-liner "case ... esac"
+/^[ 	]*case[ 	]*..*esac/bcheckchain
+# multi-line "case ... esac"
+/^[ 	]*case[ 	]..*[ 	]in/bcase
+# multi-line "for ... done" or "while ... done"
+/^[ 	]*for[ 	]..*[ 	]in/bcontinue
+/^[ 	]*while[ 	]/bcontinue
+/^[ 	]*do[ 	]/bcontinue
+/^[ 	]*do[ 	]*$/bcontinue
+/;[ 	]*do/bcontinue
+/^[ 	]*done[ 	]*&&[ 	]*$/bdone
+/^[ 	]*done[ 	]*$/bdone
+/^[ 	]*done[ 	]*[<>|]/bdone
+/^[ 	]*done[ 	]*)/bdone
+/||[ 	]*exit[ 	]/bcontinue
+/||[ 	]*exit[ 	]*$/bcontinue
+# multi-line "if...elsif...else...fi"
+/^[ 	]*if[ 	]/bcontinue
+/^[ 	]*then[ 	]/bcontinue
+/^[ 	]*then[ 	]*$/bcontinue
+/;[ 	]*then/bcontinue
+/^[ 	]*elif[ 	]/belse
+/^[ 	]*elif[ 	]*$/belse
+/^[ 	]*else[ 	]/belse
+/^[ 	]*else[ 	]*$/belse
+/^[ 	]*fi[ 	]*&&[ 	]*$/bdone
+/^[ 	]*fi[ 	]*$/bdone
+/^[ 	]*fi[ 	]*[<>|]/bdone
+/^[ 	]*fi[ 	]*)/bdone
+# nested one-liner "(...) &&"
+/^[ 	]*(.*)[ 	]*&&[ 	]*$/bcheckchain
+# nested one-liner "(...)"
+/^[ 	]*(.*)[ 	]*$/bcheckchain
+# nested one-liner "(...) >x" (or "2>x" or "<x" or "|x")
+/^[ 	]*(.*)[ 	]*[0-9]*[<>|]/bcheckchain
+# nested multi-line "(...\n...)"
+/^[ 	]*(/bnest
+# multi-line "{...\n...}"
+/^[ 	]*{/bblock
+# closing ")" on own line -- exit subshell
+/^[ 	]*)/bclosesolo
+# "$((...))" -- arithmetic expansion; not closing ")"
+/\$(([^)][^)]*))[^)]*$/bcheckchain
+# "$(...)" -- command substitution; not closing ")"
+/\$([^)][^)]*)[^)]*$/bcheckchain
+# multi-line "$(...\n...)" -- command substitution; treat as nested subshell
+/\$([ 	     ]*$/bnest
+# "=(...)" -- Bash array assignment; not closing ")"
+/=(/bcheckchain
+# closing "...) &&"
+/)[ 	]*&&[ 	]*$/bclose
+# closing "...)"
+/)[ 	]*$/bclose
+# closing "...) >x" (or "2>x" or "<x" or "|x")
+/)[ 	]*[<>|]/bclose
+:checkchain
+# mark suspect if line uses ";" internally rather than "&&" (but not ";" in a
+# string and not ";;" in one-liner "case...esac")
+/;/{
+	/;;/!{
+		/"[^"]*;[^"]*"/!s/^/?!SEMI?!/
+	}
+}
+# line ends with pipe "...|" -- valid; not missing "&&"
+/|[ 	]*$/bcontinue
+# missing end-of-line "&&" -- mark suspect
+/&&[ 	]*$/!s/^/?!AMP?!/
+:continue
+# retrieve and print previous line
+x
+n
+bslurp
+
+# found incomplete line "...\" -- slurp up next line
+:incomplete
+N
+s/\\\n//
+bslurp
+
+# found multi-line double-quoted string "...\n..." -- slurp until end of string
+:dqstring
+s/"//g
+N
+s/\n//
+/"/!bdqstring
+bcheckchain
+
+# found multi-line single-quoted string '...\n...' -- slurp until end of string
+:sqstring
+s/'//g
+N
+s/\n//
+/'/!bsqstring
+bcheckchain
+
+# found here-doc -- swallow it to avoid false hits within its body (but keep
+# the command to which it was attached); take care to handle here-docs nested
+# within here-docs by only recognizing closing tag matching outer here-doc
+# opening tag
+:heredoc
+/EOF/{ s/[ 	]*<<[ 	]*[-\\]*EOF//; s/^/EOF/; }
+/EOT/{ s/[ 	]*<<[ 	]*[-\\]*EOT//; s/^/EOT/; }
+/INPUT_END/{ s/[ 	]*<<[ 	]*[-\\]*INPUT_END//; s/^/INPUT_END/; }
+:hereslurpsub
+N
+/^EOF.*\n[ 	]*EOF[ 	]*$/bhereclose
+/^EOT.*\n[ 	]*EOT[ 	]*$/bhereclose
+/^INPUT_END.*\n[ 	]*INPUT_END[ 	]*$/bhereclose
+bhereslurpsub
+:hereclose
+s/^EOF//
+s/^EOT//
+s/^INPUT_END//
+s/\n.*$//
+bcheckchain
+
+# found "case ... in" -- pass through untouched
+:case
+x
+n
+/^[ 	]*esac/bslurp
+bcase
+
+# found "else" or "elif" -- drop "suspect" from final line before "else" since
+# that line legitimately lacks "&&"
+:else
+x
+s/?!AMP?!//
+x
+bcontinue
+
+# found "done" closing for-loop or while-loop, or "fi" closing if-then -- drop
+# "suspect" from final contained line since that line legitimately lacks "&&"
+:done
+x
+s/?!AMP?!//
+x
+# is 'done' or 'fi' cuddled with ")" to close subshell?
+/done.*)/bclose
+/fi.*)/bclose
+bcheckchain
+
+# found nested multi-line "(...\n...)" -- pass through untouched
+:nest
+x
+:nestslurp
+n
+# closing ")" on own line -- stop nested slurp
+/^[ 	]*)/bnestclose
+# comment -- not closing ")" if in comment
+/^[ 	]*#/bnestcontinue
+# "$((...))" -- arithmetic expansion; not closing ")"
+/\$(([^)][^)]*))[^)]*$/bnestcontinue
+# "$(...)" -- command substitution; not closing ")"
+/\$([^)][^)]*)[^)]*$/bnestcontinue
+# closing "...)" -- stop nested slurp
+/)/bnestclose
+:nestcontinue
+x
+bnestslurp
+:nestclose
+s/^/>>/
+# is it "))" which closes nested and parent subshells?
+/)[ 	]*)/bslurp
+bcheckchain
+
+# found multi-line "{...\n...}" block -- pass through untouched
+:block
+x
+n
+# closing "}" -- stop block slurp
+/}/bcheckchain
+bblock
+
+# found closing ")" on own line -- drop "suspect" from final line of subshell
+# since that line legitimately lacks "&&" and exit subshell loop
+:closesolo
+x
+s/?!AMP?!//
+p
+x
+s/^/>/
+b
+
+# found closing "...)" -- exit subshell loop
+:close
+x
+p
+x
+s/^/>/
+b
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 28315706be..78f7097746 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -675,7 +675,8 @@ test_run_ () {
 		trace=
 		# 117 is magic because it is unlikely to match the exit
 		# code of other programs
-		if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)"
+		if $(printf '%s\n' "$1" | sed -f "$GIT_BUILD_DIR/t/chainlint.sed" | grep -q '?![A-Z][A-Z]*?!') ||
+			test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)"
 		then
 			error "bug in the test script: broken &&-chain or run-away HERE-DOC: $1"
 		fi
-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v2 02/10] t/Makefile: add machinery to check correctness of chainlint.sed
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 01/10] t/test-lib: teach --chain-lint to " Eric Sunshine
@ 2018-07-11  6:46   ` Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 03/10] t/chainlint: add chainlint "basic" test cases Eric Sunshine
                     ` (7 subsequent siblings)
  9 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-07-11  6:46 UTC (permalink / raw)
  To: git
  Cc: Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Junio C Hamano, Luke Diamand, Jeff King,
	Eric Sunshine

The --chain-lint option uses heuristics and knowledge of shell syntax to
detect broken &&-chains in subshells by pure textual inspection.
Although the heuristics work well, they are still best-guesses and
future changes could accidentally break assumptions upon which they are
based. To protect against this possibility, tests checking correctness
of the linter itself will be added. As preparation, add a new makefile
"check-chainlint" target and associated machinery.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/.gitignore |  1 +
 t/Makefile   | 25 +++++++++++++++++++++----
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/t/.gitignore b/t/.gitignore
index 4e731dc1e3..348715f0e4 100644
--- a/t/.gitignore
+++ b/t/.gitignore
@@ -1,3 +1,4 @@
 /trash directory*
 /test-results
 /.prove
+/chainlinttmp
diff --git a/t/Makefile b/t/Makefile
index 96317a35f4..c83fd18861 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -18,8 +18,10 @@ TEST_LINT ?= test-lint
 
 ifdef TEST_OUTPUT_DIRECTORY
 TEST_RESULTS_DIRECTORY = $(TEST_OUTPUT_DIRECTORY)/test-results
+CHAINLINTTMP = $(TEST_OUTPUT_DIRECTORY)/chainlinttmp
 else
 TEST_RESULTS_DIRECTORY = test-results
+CHAINLINTTMP = chainlinttmp
 endif
 
 # Shell quote;
@@ -27,14 +29,17 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
 TEST_SHELL_PATH_SQ = $(subst ','\'',$(TEST_SHELL_PATH))
 PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
 TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY))
+CHAINLINTTMP_SQ = $(subst ','\'',$(CHAINLINTTMP))
 
 T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh))
 TGITWEB = $(sort $(wildcard t95[0-9][0-9]-*.sh))
 THELPERS = $(sort $(filter-out $(T),$(wildcard *.sh)))
+CHAINLINTTESTS = $(sort $(patsubst chainlint/%.test,%,$(wildcard chainlint/*.test)))
+CHAINLINT = sed -f chainlint.sed
 
 all: $(DEFAULT_TEST_TARGET)
 
-test: pre-clean $(TEST_LINT)
+test: pre-clean check-chainlint $(TEST_LINT)
 	$(MAKE) aggregate-results-and-cleanup
 
 failed:
@@ -43,7 +48,7 @@ failed:
 		sed -n 's/\.counts$$/.sh/p') && \
 	test -z "$$failed" || $(MAKE) $$failed
 
-prove: pre-clean $(TEST_LINT)
+prove: pre-clean check-chainlint $(TEST_LINT)
 	@echo "*** prove ***"; $(PROVE) --exec '$(TEST_SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS)
 	$(MAKE) clean-except-prove-cache
 
@@ -53,13 +58,25 @@ $(T):
 pre-clean:
 	$(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)'
 
-clean-except-prove-cache:
+clean-except-prove-cache: clean-chainlint
 	$(RM) -r 'trash directory'.* '$(TEST_RESULTS_DIRECTORY_SQ)'
 	$(RM) -r valgrind/bin
 
 clean: clean-except-prove-cache
 	$(RM) .prove
 
+clean-chainlint:
+	$(RM) -r '$(CHAINLINTTMP_SQ)'
+
+check-chainlint:
+	@mkdir -p '$(CHAINLINTTMP_SQ)' && \
+	err=0 && \
+	for i in $(CHAINLINTTESTS); do \
+		$(CHAINLINT) <chainlint/$$i.test | \
+		sed -e '/^# LINT: /d' >'$(CHAINLINTTMP_SQ)'/$$i.actual && \
+		diff -u chainlint/$$i.expect '$(CHAINLINTTMP_SQ)'/$$i.actual || err=1; \
+	done && exit $$err
+
 test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \
 	test-lint-filenames
 
@@ -102,4 +119,4 @@ valgrind:
 perf:
 	$(MAKE) -C perf/ all
 
-.PHONY: pre-clean $(T) aggregate-results clean valgrind perf
+.PHONY: pre-clean $(T) aggregate-results clean valgrind perf check-chainlint clean-chainlint
-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v2 03/10] t/chainlint: add chainlint "basic" test cases
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 01/10] t/test-lib: teach --chain-lint to " Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 02/10] t/Makefile: add machinery to check correctness of chainlint.sed Eric Sunshine
@ 2018-07-11  6:46   ` Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 04/10] t/chainlint: add chainlint "whitespace" " Eric Sunshine
                     ` (6 subsequent siblings)
  9 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-07-11  6:46 UTC (permalink / raw)
  To: git
  Cc: Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Junio C Hamano, Luke Diamand, Jeff King,
	Eric Sunshine

The --chain-lint option uses heuristics and knowledge of shell syntax to
detect broken &&-chains in subshells by pure textual inspection. The
heuristics handle a range of stylistic variations in existing tests
(evolved over the years), however, they are still best-guesses. As such,
it is possible for future changes to accidentally break assumptions upon
which the heuristics are based. Protect against this possibility by
adding tests which check the linter itself for correctness.

In addition to protecting against regressions, these tests help document
(for humans) expected behavior, which is important since the linter's
implementation language ('sed') does not necessarily lend itself to easy
comprehension.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/chainlint/arithmetic-expansion.expect |  9 +++++++++
 t/chainlint/arithmetic-expansion.test   | 11 ++++++++++
 t/chainlint/broken-chain.expect         |  6 ++++++
 t/chainlint/broken-chain.test           |  8 ++++++++
 t/chainlint/close-subshell.expect       | 25 +++++++++++++++++++++++
 t/chainlint/close-subshell.test         | 27 +++++++++++++++++++++++++
 t/chainlint/command-substitution.expect |  9 +++++++++
 t/chainlint/command-substitution.test   | 11 ++++++++++
 t/chainlint/exit-subshell.expect        |  5 +++++
 t/chainlint/exit-subshell.test          |  6 ++++++
 t/chainlint/multi-line-string.expect    |  9 +++++++++
 t/chainlint/multi-line-string.test      | 15 ++++++++++++++
 t/chainlint/pipe.expect                 |  8 ++++++++
 t/chainlint/pipe.test                   | 12 +++++++++++
 t/chainlint/semicolon.expect            | 20 ++++++++++++++++++
 t/chainlint/semicolon.test              | 25 +++++++++++++++++++++++
 16 files changed, 206 insertions(+)
 create mode 100644 t/chainlint/arithmetic-expansion.expect
 create mode 100644 t/chainlint/arithmetic-expansion.test
 create mode 100644 t/chainlint/broken-chain.expect
 create mode 100644 t/chainlint/broken-chain.test
 create mode 100644 t/chainlint/close-subshell.expect
 create mode 100644 t/chainlint/close-subshell.test
 create mode 100644 t/chainlint/command-substitution.expect
 create mode 100644 t/chainlint/command-substitution.test
 create mode 100644 t/chainlint/exit-subshell.expect
 create mode 100644 t/chainlint/exit-subshell.test
 create mode 100644 t/chainlint/multi-line-string.expect
 create mode 100644 t/chainlint/multi-line-string.test
 create mode 100644 t/chainlint/pipe.expect
 create mode 100644 t/chainlint/pipe.test
 create mode 100644 t/chainlint/semicolon.expect
 create mode 100644 t/chainlint/semicolon.test

diff --git a/t/chainlint/arithmetic-expansion.expect b/t/chainlint/arithmetic-expansion.expect
new file mode 100644
index 0000000000..09457d3196
--- /dev/null
+++ b/t/chainlint/arithmetic-expansion.expect
@@ -0,0 +1,9 @@
+(
+	foo &&
+	bar=$((42 + 1)) &&
+	baz
+>) &&
+(
+?!AMP?!	bar=$((42 + 1))
+	baz
+>)
diff --git a/t/chainlint/arithmetic-expansion.test b/t/chainlint/arithmetic-expansion.test
new file mode 100644
index 0000000000..16206960d8
--- /dev/null
+++ b/t/chainlint/arithmetic-expansion.test
@@ -0,0 +1,11 @@
+(
+	foo &&
+# LINT: closing ")" of $((...)) not misinterpreted as subshell-closing ")"
+	bar=$((42 + 1)) &&
+	baz
+) &&
+(
+# LINT: missing "&&" on $((...))
+	bar=$((42 + 1))
+	baz
+)
diff --git a/t/chainlint/broken-chain.expect b/t/chainlint/broken-chain.expect
new file mode 100644
index 0000000000..55b0f42a53
--- /dev/null
+++ b/t/chainlint/broken-chain.expect
@@ -0,0 +1,6 @@
+(
+	foo &&
+?!AMP?!	bar
+	baz &&
+	wop
+>)
diff --git a/t/chainlint/broken-chain.test b/t/chainlint/broken-chain.test
new file mode 100644
index 0000000000..3cc67b65d0
--- /dev/null
+++ b/t/chainlint/broken-chain.test
@@ -0,0 +1,8 @@
+(
+	foo &&
+# LINT: missing "&&" from 'bar'
+	bar
+	baz &&
+# LINT: final statement before closing ")" legitimately lacks "&&"
+	wop
+)
diff --git a/t/chainlint/close-subshell.expect b/t/chainlint/close-subshell.expect
new file mode 100644
index 0000000000..184688718a
--- /dev/null
+++ b/t/chainlint/close-subshell.expect
@@ -0,0 +1,25 @@
+(
+	foo
+>) &&
+(
+	bar
+>) >out &&
+(
+	baz
+>) 2>err &&
+(
+	boo
+>) <input &&
+(
+	bip
+>) | wuzzle &&
+(
+	bop
+>) | fazz 	fozz &&
+(
+	bup
+>) |
+fuzzle &&
+(
+	yop
+>)
diff --git a/t/chainlint/close-subshell.test b/t/chainlint/close-subshell.test
new file mode 100644
index 0000000000..508ca447fd
--- /dev/null
+++ b/t/chainlint/close-subshell.test
@@ -0,0 +1,27 @@
+# LINT: closing ")" with various decorations ("&&", ">", "|", etc.)
+(
+	foo
+) &&
+(
+	bar
+) >out &&
+(
+	baz
+) 2>err &&
+(
+	boo
+) <input &&
+(
+	bip
+) | wuzzle &&
+(
+	bop
+) | fazz \
+	fozz &&
+(
+	bup
+) |
+fuzzle &&
+(
+	yop
+)
diff --git a/t/chainlint/command-substitution.expect b/t/chainlint/command-substitution.expect
new file mode 100644
index 0000000000..ad4118e537
--- /dev/null
+++ b/t/chainlint/command-substitution.expect
@@ -0,0 +1,9 @@
+(
+	foo &&
+	bar=$(gobble) &&
+	baz
+>) &&
+(
+?!AMP?!	bar=$(gobble blocks)
+	baz
+>)
diff --git a/t/chainlint/command-substitution.test b/t/chainlint/command-substitution.test
new file mode 100644
index 0000000000..3bbb002a4c
--- /dev/null
+++ b/t/chainlint/command-substitution.test
@@ -0,0 +1,11 @@
+(
+	foo &&
+# LINT: closing ")" of $(...) not misinterpreted as subshell-closing ")"
+	bar=$(gobble) &&
+	baz
+) &&
+(
+# LINT: missing "&&" on $(...)
+	bar=$(gobble blocks)
+	baz
+)
diff --git a/t/chainlint/exit-subshell.expect b/t/chainlint/exit-subshell.expect
new file mode 100644
index 0000000000..bf78454f74
--- /dev/null
+++ b/t/chainlint/exit-subshell.expect
@@ -0,0 +1,5 @@
+(
+	foo || exit 1
+	bar &&
+	baz
+>)
diff --git a/t/chainlint/exit-subshell.test b/t/chainlint/exit-subshell.test
new file mode 100644
index 0000000000..4e6ab69b88
--- /dev/null
+++ b/t/chainlint/exit-subshell.test
@@ -0,0 +1,6 @@
+(
+# LINT: "|| exit {n}" valid subshell escape without hurting &&-chain
+	foo || exit 1
+	bar &&
+	baz
+)
diff --git a/t/chainlint/multi-line-string.expect b/t/chainlint/multi-line-string.expect
new file mode 100644
index 0000000000..8334c4cc8e
--- /dev/null
+++ b/t/chainlint/multi-line-string.expect
@@ -0,0 +1,9 @@
+(
+	x=line 1		line 2		line 3" &&
+?!AMP?!	y=line 1		line2'
+	foobar
+>) &&
+(
+	echo "there's nothing to see here" &&
+	exit
+>)
diff --git a/t/chainlint/multi-line-string.test b/t/chainlint/multi-line-string.test
new file mode 100644
index 0000000000..14cb44d51c
--- /dev/null
+++ b/t/chainlint/multi-line-string.test
@@ -0,0 +1,15 @@
+(
+	x="line 1
+		line 2
+		line 3" &&
+# LINT: missing "&&" on assignment
+	y='line 1
+		line2'
+	foobar
+) &&
+(
+# LINT: apostrophe (in a contraction) within string not misinterpreted as
+# LINT: starting multi-line single-quoted string
+	echo "there's nothing to see here" &&
+	exit
+)
diff --git a/t/chainlint/pipe.expect b/t/chainlint/pipe.expect
new file mode 100644
index 0000000000..211b901dbc
--- /dev/null
+++ b/t/chainlint/pipe.expect
@@ -0,0 +1,8 @@
+(
+	foo |
+	bar |
+	baz &&
+	fish |
+?!AMP?!	cow
+	sunder
+>)
diff --git a/t/chainlint/pipe.test b/t/chainlint/pipe.test
new file mode 100644
index 0000000000..e6af4de916
--- /dev/null
+++ b/t/chainlint/pipe.test
@@ -0,0 +1,12 @@
+(
+# LINT: no "&&" needed on line ending with "|"
+	foo |
+	bar |
+	baz &&
+
+# LINT: final line of pipe sequence ('cow') lacking "&&"
+	fish |
+	cow
+
+	sunder
+)
diff --git a/t/chainlint/semicolon.expect b/t/chainlint/semicolon.expect
new file mode 100644
index 0000000000..1d79384606
--- /dev/null
+++ b/t/chainlint/semicolon.expect
@@ -0,0 +1,20 @@
+(
+?!AMP?!?!SEMI?!	cat foo ; echo bar
+?!SEMI?!	cat foo ; echo bar
+>) &&
+(
+?!SEMI?!	cat foo ; echo bar &&
+?!SEMI?!	cat foo ; echo bar
+>) &&
+(
+	echo "foo; bar" &&
+?!SEMI?!	cat foo; echo bar
+>) &&
+(
+?!SEMI?!	foo;
+>) &&
+(
+cd foo &&
+	for i in a b c; do
+?!SEMI?!		echo;
+>	done)
diff --git a/t/chainlint/semicolon.test b/t/chainlint/semicolon.test
new file mode 100644
index 0000000000..d82c8ebbc0
--- /dev/null
+++ b/t/chainlint/semicolon.test
@@ -0,0 +1,25 @@
+(
+# LINT: missing internal "&&" and ending "&&"
+	cat foo ; echo bar
+# LINT: final statement before ")" only missing internal "&&"
+	cat foo ; echo bar
+) &&
+(
+# LINT: missing internal "&&"
+	cat foo ; echo bar &&
+	cat foo ; echo bar
+) &&
+(
+# LINT: not fooled by semicolon in string
+	echo "foo; bar" &&
+	cat foo; echo bar
+) &&
+(
+# LINT: unnecessary terminating semicolon
+	foo;
+) &&
+(cd foo &&
+	for i in a b c; do
+# LINT: unnecessary terminating semicolon
+		echo;
+	done)
-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v2 04/10] t/chainlint: add chainlint "whitespace" test cases
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
                     ` (2 preceding siblings ...)
  2018-07-11  6:46   ` [PATCH v2 03/10] t/chainlint: add chainlint "basic" test cases Eric Sunshine
@ 2018-07-11  6:46   ` " Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 05/10] t/chainlint: add chainlint "one-liner" " Eric Sunshine
                     ` (5 subsequent siblings)
  9 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-07-11  6:46 UTC (permalink / raw)
  To: git
  Cc: Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Junio C Hamano, Luke Diamand, Jeff King,
	Eric Sunshine

The --chain-lint option uses heuristics and knowledge of shell syntax to
detect broken &&-chains in subshells by pure textual inspection. The
heuristics handle a range of stylistic variations in existing tests
(evolved over the years), however, they are still best-guesses. As such,
it is possible for future changes to accidentally break assumptions upon
which the heuristics are based. Protect against this possibility by
adding tests which check the linter itself for correctness.

In addition to protecting against regressions, these tests help document
(for humans) expected behavior, which is important since the linter's
implementation language ('sed') does not necessarily lend itself to easy
comprehension.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/chainlint/blank-line.expect        |  4 ++++
 t/chainlint/blank-line.test          | 10 ++++++++++
 t/chainlint/comment.expect           |  4 ++++
 t/chainlint/comment.test             | 11 +++++++++++
 t/chainlint/here-doc.expect          |  3 +++
 t/chainlint/here-doc.test            | 16 ++++++++++++++++
 t/chainlint/incomplete-line.expect   |  4 ++++
 t/chainlint/incomplete-line.test     | 12 ++++++++++++
 t/chainlint/inline-comment.expect    |  9 +++++++++
 t/chainlint/inline-comment.test      | 12 ++++++++++++
 t/chainlint/subshell-here-doc.expect |  5 +++++
 t/chainlint/subshell-here-doc.test   | 23 +++++++++++++++++++++++
 12 files changed, 113 insertions(+)
 create mode 100644 t/chainlint/blank-line.expect
 create mode 100644 t/chainlint/blank-line.test
 create mode 100644 t/chainlint/comment.expect
 create mode 100644 t/chainlint/comment.test
 create mode 100644 t/chainlint/here-doc.expect
 create mode 100644 t/chainlint/here-doc.test
 create mode 100644 t/chainlint/incomplete-line.expect
 create mode 100644 t/chainlint/incomplete-line.test
 create mode 100644 t/chainlint/inline-comment.expect
 create mode 100644 t/chainlint/inline-comment.test
 create mode 100644 t/chainlint/subshell-here-doc.expect
 create mode 100644 t/chainlint/subshell-here-doc.test

diff --git a/t/chainlint/blank-line.expect b/t/chainlint/blank-line.expect
new file mode 100644
index 0000000000..3be939ed38
--- /dev/null
+++ b/t/chainlint/blank-line.expect
@@ -0,0 +1,4 @@
+(
+	nothing &&
+	something
+>)
diff --git a/t/chainlint/blank-line.test b/t/chainlint/blank-line.test
new file mode 100644
index 0000000000..f6dd14302b
--- /dev/null
+++ b/t/chainlint/blank-line.test
@@ -0,0 +1,10 @@
+(
+
+	nothing &&
+
+	something
+# LINT: swallow blank lines since final _statement_ before subshell end is
+# LINT: significant to "&&"-check, not final _line_ (which might be blank)
+
+
+)
diff --git a/t/chainlint/comment.expect b/t/chainlint/comment.expect
new file mode 100644
index 0000000000..3be939ed38
--- /dev/null
+++ b/t/chainlint/comment.expect
@@ -0,0 +1,4 @@
+(
+	nothing &&
+	something
+>)
diff --git a/t/chainlint/comment.test b/t/chainlint/comment.test
new file mode 100644
index 0000000000..113c0c466f
--- /dev/null
+++ b/t/chainlint/comment.test
@@ -0,0 +1,11 @@
+(
+# LINT: swallow comment lines
+	# comment 1
+	nothing &&
+	# comment 2
+	something
+# LINT: swallow comment lines since final _statement_ before subshell end is
+# LINT: significant to "&&"-check, not final _line_ (which might be comment)
+	# comment 3
+	# comment 4
+)
diff --git a/t/chainlint/here-doc.expect b/t/chainlint/here-doc.expect
new file mode 100644
index 0000000000..2328fe7753
--- /dev/null
+++ b/t/chainlint/here-doc.expect
@@ -0,0 +1,3 @@
+boodle wobba        gorgo snoot        wafta snurb &&
+
+horticulture
diff --git a/t/chainlint/here-doc.test b/t/chainlint/here-doc.test
new file mode 100644
index 0000000000..bd36f6e1d3
--- /dev/null
+++ b/t/chainlint/here-doc.test
@@ -0,0 +1,16 @@
+# LINT: stitch together incomplete \-ending lines
+# LINT: swallow here-doc to avoid false positives in content
+boodle wobba \
+       gorgo snoot \
+       wafta snurb <<EOF &&
+quoth the raven,
+nevermore...
+EOF
+
+# LINT: swallow here-doc (EOF is last line of test)
+horticulture <<\EOF
+gomez
+morticia
+wednesday
+pugsly
+EOF
diff --git a/t/chainlint/incomplete-line.expect b/t/chainlint/incomplete-line.expect
new file mode 100644
index 0000000000..2f3ebabdc2
--- /dev/null
+++ b/t/chainlint/incomplete-line.expect
@@ -0,0 +1,4 @@
+line 1 line 2 line 3 line 4 &&
+(
+	line 5 	line 6 	line 7 	line 8
+>)
diff --git a/t/chainlint/incomplete-line.test b/t/chainlint/incomplete-line.test
new file mode 100644
index 0000000000..d856658083
--- /dev/null
+++ b/t/chainlint/incomplete-line.test
@@ -0,0 +1,12 @@
+# LINT: stitch together all incomplete \-ending lines
+line 1 \
+line 2 \
+line 3 \
+line 4 &&
+(
+# LINT: stitch together all incomplete \-ending lines (subshell)
+	line 5 \
+	line 6 \
+	line 7 \
+	line 8
+)
diff --git a/t/chainlint/inline-comment.expect b/t/chainlint/inline-comment.expect
new file mode 100644
index 0000000000..fc9f250ac4
--- /dev/null
+++ b/t/chainlint/inline-comment.expect
@@ -0,0 +1,9 @@
+(
+	foobar &&
+?!AMP?!	barfoo
+	flibble "not a # comment"
+>) &&
+
+(
+cd foo &&
+>	flibble "not a # comment")
diff --git a/t/chainlint/inline-comment.test b/t/chainlint/inline-comment.test
new file mode 100644
index 0000000000..8f26856e77
--- /dev/null
+++ b/t/chainlint/inline-comment.test
@@ -0,0 +1,12 @@
+(
+# LINT: swallow inline comment (leaving command intact)
+	foobar && # comment 1
+# LINT: mispositioned "&&" (correctly) swallowed with comment
+	barfoo # wrong position for &&
+# LINT: "#" in string not misinterpreted as comment
+	flibble "not a # comment"
+) &&
+
+# LINT: "#" in string in cuddled subshell not misinterpreted as comment
+(cd foo &&
+	flibble "not a # comment")
diff --git a/t/chainlint/subshell-here-doc.expect b/t/chainlint/subshell-here-doc.expect
new file mode 100644
index 0000000000..19d5aff233
--- /dev/null
+++ b/t/chainlint/subshell-here-doc.expect
@@ -0,0 +1,5 @@
+(
+	echo wobba 	       gorgo snoot 	       wafta snurb &&
+?!AMP?!	cat >bip
+	echo >bop
+>)
diff --git a/t/chainlint/subshell-here-doc.test b/t/chainlint/subshell-here-doc.test
new file mode 100644
index 0000000000..9c3564c247
--- /dev/null
+++ b/t/chainlint/subshell-here-doc.test
@@ -0,0 +1,23 @@
+(
+# LINT: stitch together incomplete \-ending lines
+# LINT: swallow here-doc to avoid false positives in content
+	echo wobba \
+	       gorgo snoot \
+	       wafta snurb <<-EOF &&
+	quoth the raven,
+	nevermore...
+	EOF
+
+# LINT: missing "&&" on 'cat'
+	cat <<EOF >bip
+	fish fly high
+	EOF
+
+# LINT: swallow here-doc (EOF is last line of subshell)
+	echo <<-\EOF >bop
+	gomez
+	morticia
+	wednesday
+	pugsly
+	EOF
+)
-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v2 05/10] t/chainlint: add chainlint "one-liner" test cases
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
                     ` (3 preceding siblings ...)
  2018-07-11  6:46   ` [PATCH v2 04/10] t/chainlint: add chainlint "whitespace" " Eric Sunshine
@ 2018-07-11  6:46   ` " Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 06/10] t/chainlint: add chainlint "nested subshell" " Eric Sunshine
                     ` (4 subsequent siblings)
  9 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-07-11  6:46 UTC (permalink / raw)
  To: git
  Cc: Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Junio C Hamano, Luke Diamand, Jeff King,
	Eric Sunshine

The --chain-lint option uses heuristics and knowledge of shell syntax to
detect broken &&-chains in subshells by pure textual inspection. The
heuristics handle a range of stylistic variations in existing tests
(evolved over the years), however, they are still best-guesses. As such,
it is possible for future changes to accidentally break assumptions upon
which the heuristics are based. Protect against this possibility by
adding tests which check the linter itself for correctness.

In addition to protecting against regressions, these tests help document
(for humans) expected behavior, which is important since the linter's
implementation language ('sed') does not necessarily lend itself to easy
comprehension.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/chainlint/negated-one-liner.expect  |  5 +++++
 t/chainlint/negated-one-liner.test    |  7 +++++++
 t/chainlint/one-liner.expect          |  9 +++++++++
 t/chainlint/one-liner.test            | 12 ++++++++++++
 t/chainlint/subshell-one-liner.expect | 14 ++++++++++++++
 t/chainlint/subshell-one-liner.test   | 24 ++++++++++++++++++++++++
 6 files changed, 71 insertions(+)
 create mode 100644 t/chainlint/negated-one-liner.expect
 create mode 100644 t/chainlint/negated-one-liner.test
 create mode 100644 t/chainlint/one-liner.expect
 create mode 100644 t/chainlint/one-liner.test
 create mode 100644 t/chainlint/subshell-one-liner.expect
 create mode 100644 t/chainlint/subshell-one-liner.test

diff --git a/t/chainlint/negated-one-liner.expect b/t/chainlint/negated-one-liner.expect
new file mode 100644
index 0000000000..cf18429d03
--- /dev/null
+++ b/t/chainlint/negated-one-liner.expect
@@ -0,0 +1,5 @@
+! (foo && bar) &&
+! (foo && bar) >baz &&
+
+?!SEMI?!! (foo; bar) &&
+?!SEMI?!! (foo; bar) >baz
diff --git a/t/chainlint/negated-one-liner.test b/t/chainlint/negated-one-liner.test
new file mode 100644
index 0000000000..c9598e9153
--- /dev/null
+++ b/t/chainlint/negated-one-liner.test
@@ -0,0 +1,7 @@
+# LINT: top-level one-liner subshell
+! (foo && bar) &&
+! (foo && bar) >baz &&
+
+# LINT: top-level one-liner subshell missing internal "&&"
+! (foo; bar) &&
+! (foo; bar) >baz
diff --git a/t/chainlint/one-liner.expect b/t/chainlint/one-liner.expect
new file mode 100644
index 0000000000..237f227349
--- /dev/null
+++ b/t/chainlint/one-liner.expect
@@ -0,0 +1,9 @@
+(foo && bar) &&
+(foo && bar) |
+(foo && bar) >baz &&
+
+?!SEMI?!(foo; bar) &&
+?!SEMI?!(foo; bar) |
+?!SEMI?!(foo; bar) >baz
+
+(foo "bar; baz")
diff --git a/t/chainlint/one-liner.test b/t/chainlint/one-liner.test
new file mode 100644
index 0000000000..ec9acb9825
--- /dev/null
+++ b/t/chainlint/one-liner.test
@@ -0,0 +1,12 @@
+# LINT: top-level one-liner subshell
+(foo && bar) &&
+(foo && bar) |
+(foo && bar) >baz &&
+
+# LINT: top-level one-liner subshell missing internal "&&"
+(foo; bar) &&
+(foo; bar) |
+(foo; bar) >baz
+
+# LINT: ";" in string not misinterpreted as broken &&-chain
+(foo "bar; baz")
diff --git a/t/chainlint/subshell-one-liner.expect b/t/chainlint/subshell-one-liner.expect
new file mode 100644
index 0000000000..51162821d7
--- /dev/null
+++ b/t/chainlint/subshell-one-liner.expect
@@ -0,0 +1,14 @@
+(
+	(foo && bar) &&
+	(foo && bar) |
+	(foo && bar) >baz &&
+?!SEMI?!	(foo; bar) &&
+?!SEMI?!	(foo; bar) |
+?!SEMI?!	(foo; bar) >baz &&
+	(foo || exit 1) &&
+	(foo || exit 1) |
+	(foo || exit 1) >baz &&
+?!AMP?!	(foo && bar)
+?!AMP?!?!SEMI?!	(foo && bar; baz)
+	foobar
+>)
diff --git a/t/chainlint/subshell-one-liner.test b/t/chainlint/subshell-one-liner.test
new file mode 100644
index 0000000000..37fa643c20
--- /dev/null
+++ b/t/chainlint/subshell-one-liner.test
@@ -0,0 +1,24 @@
+(
+# LINT: nested one-liner subshell
+	(foo && bar) &&
+	(foo && bar) |
+	(foo && bar) >baz &&
+
+# LINT: nested one-liner subshell missing internal "&&"
+	(foo; bar) &&
+	(foo; bar) |
+	(foo; bar) >baz &&
+
+# LINT: nested one-liner subshell with "|| exit"
+	(foo || exit 1) &&
+	(foo || exit 1) |
+	(foo || exit 1) >baz &&
+
+# LINT: nested one-liner subshell lacking ending "&&"
+	(foo && bar)
+
+# LINT: nested one-liner subshell missing internal "&&" and lacking ending "&&"
+	(foo && bar; baz)
+
+	foobar
+)
-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v2 06/10] t/chainlint: add chainlint "nested subshell" test cases
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
                     ` (4 preceding siblings ...)
  2018-07-11  6:46   ` [PATCH v2 05/10] t/chainlint: add chainlint "one-liner" " Eric Sunshine
@ 2018-07-11  6:46   ` " Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 07/10] t/chainlint: add chainlint "loop" and "conditional" " Eric Sunshine
                     ` (3 subsequent siblings)
  9 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-07-11  6:46 UTC (permalink / raw)
  To: git
  Cc: Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Junio C Hamano, Luke Diamand, Jeff King,
	Eric Sunshine

The --chain-lint option uses heuristics and knowledge of shell syntax to
detect broken &&-chains in subshells by pure textual inspection. The
heuristics handle a range of stylistic variations in existing tests
(evolved over the years), however, they are still best-guesses. As such,
it is possible for future changes to accidentally break assumptions upon
which the heuristics are based. Protect against this possibility by
adding tests which check the linter itself for correctness.

In addition to protecting against regressions, these tests help document
(for humans) expected behavior, which is important since the linter's
implementation language ('sed') does not necessarily lend itself to easy
comprehension.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/chainlint/block.expect                      | 12 +++++++
 t/chainlint/block.test                        | 15 +++++++++
 ...ti-line-nested-command-substitution.expect |  9 ++++++
 ...ulti-line-nested-command-substitution.test |  9 ++++++
 t/chainlint/nested-cuddled-subshell.expect    | 19 ++++++++++++
 t/chainlint/nested-cuddled-subshell.test      | 31 +++++++++++++++++++
 t/chainlint/nested-here-doc.expect            |  5 +++
 t/chainlint/nested-here-doc.test              | 23 ++++++++++++++
 t/chainlint/nested-subshell-comment.expect    | 11 +++++++
 t/chainlint/nested-subshell-comment.test      | 13 ++++++++
 t/chainlint/nested-subshell.expect            | 12 +++++++
 t/chainlint/nested-subshell.test              | 14 +++++++++
 12 files changed, 173 insertions(+)
 create mode 100644 t/chainlint/block.expect
 create mode 100644 t/chainlint/block.test
 create mode 100644 t/chainlint/multi-line-nested-command-substitution.expect
 create mode 100644 t/chainlint/multi-line-nested-command-substitution.test
 create mode 100644 t/chainlint/nested-cuddled-subshell.expect
 create mode 100644 t/chainlint/nested-cuddled-subshell.test
 create mode 100644 t/chainlint/nested-here-doc.expect
 create mode 100644 t/chainlint/nested-here-doc.test
 create mode 100644 t/chainlint/nested-subshell-comment.expect
 create mode 100644 t/chainlint/nested-subshell-comment.test
 create mode 100644 t/chainlint/nested-subshell.expect
 create mode 100644 t/chainlint/nested-subshell.test

diff --git a/t/chainlint/block.expect b/t/chainlint/block.expect
new file mode 100644
index 0000000000..fed7e89ae8
--- /dev/null
+++ b/t/chainlint/block.expect
@@ -0,0 +1,12 @@
+(
+	foo &&
+	{
+		echo a
+		echo b
+	} &&
+	bar &&
+	{
+		echo c
+?!AMP?!	}
+	baz
+>)
diff --git a/t/chainlint/block.test b/t/chainlint/block.test
new file mode 100644
index 0000000000..d859151af1
--- /dev/null
+++ b/t/chainlint/block.test
@@ -0,0 +1,15 @@
+(
+# LINT: missing "&&" in block not currently detected (for consistency with
+# LINT: --chain-lint at top level and to provide escape hatch if needed)
+	foo &&
+	{
+		echo a
+		echo b
+	} &&
+	bar &&
+# LINT: missing "&&" at closing "}"
+	{
+		echo c
+	}
+	baz
+)
diff --git a/t/chainlint/multi-line-nested-command-substitution.expect b/t/chainlint/multi-line-nested-command-substitution.expect
new file mode 100644
index 0000000000..19c023b1c8
--- /dev/null
+++ b/t/chainlint/multi-line-nested-command-substitution.expect
@@ -0,0 +1,9 @@
+(
+	foo &&
+	x=$(
+		echo bar |
+		cat
+>>	) &&
+	echo ok
+>) |
+sort
diff --git a/t/chainlint/multi-line-nested-command-substitution.test b/t/chainlint/multi-line-nested-command-substitution.test
new file mode 100644
index 0000000000..ca0620ab6b
--- /dev/null
+++ b/t/chainlint/multi-line-nested-command-substitution.test
@@ -0,0 +1,9 @@
+(
+	foo &&
+	x=$(
+		echo bar |
+		cat
+	) &&
+	echo ok
+) |
+sort
diff --git a/t/chainlint/nested-cuddled-subshell.expect b/t/chainlint/nested-cuddled-subshell.expect
new file mode 100644
index 0000000000..c2a59ffc33
--- /dev/null
+++ b/t/chainlint/nested-cuddled-subshell.expect
@@ -0,0 +1,19 @@
+(
+	(cd foo &&
+		bar
+>>	) &&
+	(cd foo &&
+		bar
+?!AMP?!>>	)
+	(
+		cd foo &&
+>>		bar) &&
+	(
+		cd foo &&
+?!AMP?!>>		bar)
+	(cd foo &&
+>>		bar) &&
+	(cd foo &&
+?!AMP?!>>		bar)
+	foobar
+>)
diff --git a/t/chainlint/nested-cuddled-subshell.test b/t/chainlint/nested-cuddled-subshell.test
new file mode 100644
index 0000000000..8fd656c7b5
--- /dev/null
+++ b/t/chainlint/nested-cuddled-subshell.test
@@ -0,0 +1,31 @@
+(
+# LINT: opening "(" cuddled with first nested subshell statement
+	(cd foo &&
+		bar
+	) &&
+
+# LINT: same but "&&" missing
+	(cd foo &&
+		bar
+	)
+
+# LINT: closing ")" cuddled with final nested subshell statement
+	(
+		cd foo &&
+		bar) &&
+
+# LINT: same but "&&" missing
+	(
+		cd foo &&
+		bar)
+
+# LINT: "(" and ")" cuddled with first and final subshell statements
+	(cd foo &&
+		bar) &&
+
+# LINT: same but "&&" missing
+	(cd foo &&
+		bar)
+
+	foobar
+)
diff --git a/t/chainlint/nested-here-doc.expect b/t/chainlint/nested-here-doc.expect
new file mode 100644
index 0000000000..559301e005
--- /dev/null
+++ b/t/chainlint/nested-here-doc.expect
@@ -0,0 +1,5 @@
+(
+	cat &&
+?!AMP?!	cat
+	foobar
+>)
diff --git a/t/chainlint/nested-here-doc.test b/t/chainlint/nested-here-doc.test
new file mode 100644
index 0000000000..027e0bb3ff
--- /dev/null
+++ b/t/chainlint/nested-here-doc.test
@@ -0,0 +1,23 @@
+(
+# LINT: inner "EOF" not misintrepreted as closing INPUT_END here-doc
+	cat <<-\INPUT_END &&
+	fish are mice
+	but geese go slow
+	data <<EOF
+		perl is lerp
+		and nothing else
+	EOF
+	toink
+	INPUT_END
+
+# LINT: same but missing "&&"
+	cat <<-\EOT
+	text goes here
+	data <<EOF
+		data goes here
+	EOF
+	more test here
+	EOT
+
+	foobar
+)
diff --git a/t/chainlint/nested-subshell-comment.expect b/t/chainlint/nested-subshell-comment.expect
new file mode 100644
index 0000000000..15b68d4373
--- /dev/null
+++ b/t/chainlint/nested-subshell-comment.expect
@@ -0,0 +1,11 @@
+(
+	foo &&
+	(
+		bar &&
+		# bottles wobble while fiddles gobble
+		# minor numbers of cows (or do they?)
+		baz &&
+		snaff
+?!AMP?!>>	)
+	fuzzy
+>)
diff --git a/t/chainlint/nested-subshell-comment.test b/t/chainlint/nested-subshell-comment.test
new file mode 100644
index 0000000000..0ff136ab3c
--- /dev/null
+++ b/t/chainlint/nested-subshell-comment.test
@@ -0,0 +1,13 @@
+(
+	foo &&
+	(
+		bar &&
+# LINT: ")" in comment in nested subshell not misinterpreted as closing ")"
+		# bottles wobble while fiddles gobble
+		# minor numbers of cows (or do they?)
+		baz &&
+		snaff
+# LINT: missing "&&" on ')'
+	)
+	fuzzy
+)
diff --git a/t/chainlint/nested-subshell.expect b/t/chainlint/nested-subshell.expect
new file mode 100644
index 0000000000..c8165ad19e
--- /dev/null
+++ b/t/chainlint/nested-subshell.expect
@@ -0,0 +1,12 @@
+(
+	cd foo &&
+	(
+		echo a &&
+		echo b
+>>	) >file &&
+	cd foo &&
+	(
+		echo a
+		echo b
+>>	) >file
+>)
diff --git a/t/chainlint/nested-subshell.test b/t/chainlint/nested-subshell.test
new file mode 100644
index 0000000000..998b05a47d
--- /dev/null
+++ b/t/chainlint/nested-subshell.test
@@ -0,0 +1,14 @@
+(
+	cd foo &&
+	(
+		echo a &&
+		echo b
+	) >file &&
+
+	cd foo &&
+	(
+# LINT: nested multi-line subshell not presently checked for missing "&&"
+		echo a
+		echo b
+	) >file
+)
-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v2 07/10] t/chainlint: add chainlint "loop" and "conditional" test cases
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
                     ` (5 preceding siblings ...)
  2018-07-11  6:46   ` [PATCH v2 06/10] t/chainlint: add chainlint "nested subshell" " Eric Sunshine
@ 2018-07-11  6:46   ` " Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 08/10] t/chainlint: add chainlint "cuddled" " Eric Sunshine
                     ` (2 subsequent siblings)
  9 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-07-11  6:46 UTC (permalink / raw)
  To: git
  Cc: Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Junio C Hamano, Luke Diamand, Jeff King,
	Eric Sunshine

The --chain-lint option uses heuristics and knowledge of shell syntax to
detect broken &&-chains in subshells by pure textual inspection. The
heuristics handle a range of stylistic variations in existing tests
(evolved over the years), however, they are still best-guesses. As such,
it is possible for future changes to accidentally break assumptions upon
which the heuristics are based. Protect against this possibility by
adding tests which check the linter itself for correctness.

In addition to protecting against regressions, these tests help document
(for humans) expected behavior, which is important since the linter's
implementation language ('sed') does not necessarily lend itself to easy
comprehension.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/chainlint/case.expect         | 19 +++++++++++++++++++
 t/chainlint/case.test           | 23 +++++++++++++++++++++++
 t/chainlint/exit-loop.expect    | 24 ++++++++++++++++++++++++
 t/chainlint/exit-loop.test      | 27 +++++++++++++++++++++++++++
 t/chainlint/for-loop.expect     | 11 +++++++++++
 t/chainlint/for-loop.test       | 19 +++++++++++++++++++
 t/chainlint/if-then-else.expect | 19 +++++++++++++++++++
 t/chainlint/if-then-else.test   | 28 ++++++++++++++++++++++++++++
 t/chainlint/while-loop.expect   | 11 +++++++++++
 t/chainlint/while-loop.test     | 19 +++++++++++++++++++
 10 files changed, 200 insertions(+)
 create mode 100644 t/chainlint/case.expect
 create mode 100644 t/chainlint/case.test
 create mode 100644 t/chainlint/exit-loop.expect
 create mode 100644 t/chainlint/exit-loop.test
 create mode 100644 t/chainlint/for-loop.expect
 create mode 100644 t/chainlint/for-loop.test
 create mode 100644 t/chainlint/if-then-else.expect
 create mode 100644 t/chainlint/if-then-else.test
 create mode 100644 t/chainlint/while-loop.expect
 create mode 100644 t/chainlint/while-loop.test

diff --git a/t/chainlint/case.expect b/t/chainlint/case.expect
new file mode 100644
index 0000000000..41f121fbbf
--- /dev/null
+++ b/t/chainlint/case.expect
@@ -0,0 +1,19 @@
+(
+	case "$x" in
+	x) foo ;;
+	*) bar ;;
+	esac &&
+	foobar
+>) &&
+(
+	case "$x" in
+	x) foo ;;
+	*) bar ;;
+?!AMP?!	esac
+	foobar
+>) &&
+(
+	case "$x" in 1) true;; esac &&
+?!AMP?!	case "$y" in 2) false;; esac
+	foobar
+>)
diff --git a/t/chainlint/case.test b/t/chainlint/case.test
new file mode 100644
index 0000000000..5ef6ff7db5
--- /dev/null
+++ b/t/chainlint/case.test
@@ -0,0 +1,23 @@
+(
+# LINT: "...)" arms in 'case' not misinterpreted as subshell-closing ")"
+	case "$x" in
+	x) foo ;;
+	*) bar ;;
+	esac &&
+	foobar
+) &&
+(
+# LINT: missing "&&" on 'esac'
+	case "$x" in
+	x) foo ;;
+	*) bar ;;
+	esac
+	foobar
+) &&
+(
+# LINT: "...)" arm in one-liner 'case' not misinterpreted as closing ")"
+	case "$x" in 1) true;; esac &&
+# LINT: same but missing "&&"
+	case "$y" in 2) false;; esac
+	foobar
+)
diff --git a/t/chainlint/exit-loop.expect b/t/chainlint/exit-loop.expect
new file mode 100644
index 0000000000..84d8bdebc0
--- /dev/null
+++ b/t/chainlint/exit-loop.expect
@@ -0,0 +1,24 @@
+(
+	for i in a b c
+	do
+		foo || exit 1
+		bar &&
+		baz
+	done
+>) &&
+(
+	while true
+	do
+		foo || exit 1
+		bar &&
+		baz
+	done
+>) &&
+(
+	i=0 &&
+	while test $i -lt 10
+	do
+		echo $i || exit
+		i=$(($i + 1))
+	done
+>)
diff --git a/t/chainlint/exit-loop.test b/t/chainlint/exit-loop.test
new file mode 100644
index 0000000000..2f038207e1
--- /dev/null
+++ b/t/chainlint/exit-loop.test
@@ -0,0 +1,27 @@
+(
+	for i in a b c
+	do
+# LINT: "|| exit {n}" valid for-loop escape in subshell; no "&&" needed
+		foo || exit 1
+		bar &&
+		baz
+	done
+) &&
+(
+	while true
+	do
+# LINT: "|| exit {n}" valid while-loop escape in subshell; no "&&" needed
+		foo || exit 1
+		bar &&
+		baz
+	done
+) &&
+(
+	i=0 &&
+	while test $i -lt 10
+	do
+# LINT: "|| exit" (sans exit code) valid escape in subshell; no "&&" needed
+		echo $i || exit
+		i=$(($i + 1))
+	done
+)
diff --git a/t/chainlint/for-loop.expect b/t/chainlint/for-loop.expect
new file mode 100644
index 0000000000..c33cf56ee7
--- /dev/null
+++ b/t/chainlint/for-loop.expect
@@ -0,0 +1,11 @@
+(
+	for i in a b c
+	do
+?!AMP?!		echo $i
+		cat
+?!AMP?!	done
+	for i in a b c; do
+		echo $i &&
+		cat $i
+	done
+>)
diff --git a/t/chainlint/for-loop.test b/t/chainlint/for-loop.test
new file mode 100644
index 0000000000..7db76262bc
--- /dev/null
+++ b/t/chainlint/for-loop.test
@@ -0,0 +1,19 @@
+(
+# LINT: 'for', 'do', 'done' do not need "&&"
+	for i in a b c
+	do
+# LINT: missing "&&" on 'echo'
+		echo $i
+# LINT: last statement of while does not need "&&"
+		cat <<-\EOF
+		bar
+		EOF
+# LINT: missing "&&" on 'done'
+	done
+
+# LINT: 'do' on same line as 'for'
+	for i in a b c; do
+		echo $i &&
+		cat $i
+	done
+)
diff --git a/t/chainlint/if-then-else.expect b/t/chainlint/if-then-else.expect
new file mode 100644
index 0000000000..5953c7bfbc
--- /dev/null
+++ b/t/chainlint/if-then-else.expect
@@ -0,0 +1,19 @@
+(
+	if test -n ""
+	then
+?!AMP?!		echo very
+		echo empty
+	elif test -z ""
+		echo foo
+	else
+		echo foo &&
+		cat
+?!AMP?!	fi
+	echo poodle
+>) &&
+(
+	if test -n ""; then
+		echo very &&
+?!AMP?!		echo empty
+	if
+>)
diff --git a/t/chainlint/if-then-else.test b/t/chainlint/if-then-else.test
new file mode 100644
index 0000000000..9bd8e9a4c6
--- /dev/null
+++ b/t/chainlint/if-then-else.test
@@ -0,0 +1,28 @@
+(
+# LINT: 'if', 'then', 'elif', 'else', 'fi' do not need "&&"
+	if test -n ""
+	then
+# LINT: missing "&&" on 'echo'
+		echo very
+# LINT: last statement before 'elif' does not need "&&"
+		echo empty
+	elif test -z ""
+# LINT: last statement before 'else' does not need "&&"
+		echo foo
+	else
+		echo foo &&
+# LINT: last statement before 'fi' does not need "&&"
+		cat <<-\EOF
+		bar
+		EOF
+# LINT: missing "&&" on 'fi'
+	fi
+	echo poodle
+) &&
+(
+# LINT: 'then' on same line as 'if'
+	if test -n ""; then
+		echo very &&
+		echo empty
+	if
+)
diff --git a/t/chainlint/while-loop.expect b/t/chainlint/while-loop.expect
new file mode 100644
index 0000000000..13cff2c0a5
--- /dev/null
+++ b/t/chainlint/while-loop.expect
@@ -0,0 +1,11 @@
+(
+	while true
+	do
+?!AMP?!		echo foo
+		cat
+?!AMP?!	done
+	while true; do
+		echo foo &&
+		cat bar
+	done
+>)
diff --git a/t/chainlint/while-loop.test b/t/chainlint/while-loop.test
new file mode 100644
index 0000000000..f1df085bf0
--- /dev/null
+++ b/t/chainlint/while-loop.test
@@ -0,0 +1,19 @@
+(
+# LINT: 'while, 'do', 'done' do not need "&&"
+	while true
+	do
+# LINT: missing "&&" on 'echo'
+		echo foo
+# LINT: last statement of while does not need "&&"
+		cat <<-\EOF
+		bar
+		EOF
+# LINT: missing "&&" on 'done'
+	done
+
+# LINT: 'do' on same line as 'while'
+	while true; do
+		echo foo &&
+		cat bar
+	done
+)
-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v2 08/10] t/chainlint: add chainlint "cuddled" test cases
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
                     ` (6 preceding siblings ...)
  2018-07-11  6:46   ` [PATCH v2 07/10] t/chainlint: add chainlint "loop" and "conditional" " Eric Sunshine
@ 2018-07-11  6:46   ` " Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 09/10] t/chainlint: add chainlint "complex" " Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 10/10] t/chainlint: add chainlint "specialized" " Eric Sunshine
  9 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-07-11  6:46 UTC (permalink / raw)
  To: git
  Cc: Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Junio C Hamano, Luke Diamand, Jeff King,
	Eric Sunshine

The --chain-lint option uses heuristics and knowledge of shell syntax to
detect broken &&-chains in subshells by pure textual inspection. The
heuristics handle a range of stylistic variations in existing tests
(evolved over the years), however, they are still best-guesses. As such,
it is possible for future changes to accidentally break assumptions upon
which the heuristics are based. Protect against this possibility by
adding tests which check the linter itself for correctness.

In addition to protecting against regressions, these tests help document
(for humans) expected behavior, which is important since the linter's
implementation language ('sed') does not necessarily lend itself to easy
comprehension.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/chainlint/cuddled-if-then-else.expect |  7 +++++++
 t/chainlint/cuddled-if-then-else.test   |  7 +++++++
 t/chainlint/cuddled-loop.expect         |  5 +++++
 t/chainlint/cuddled-loop.test           |  7 +++++++
 t/chainlint/cuddled.expect              | 21 +++++++++++++++++++++
 t/chainlint/cuddled.test                | 23 +++++++++++++++++++++++
 6 files changed, 70 insertions(+)
 create mode 100644 t/chainlint/cuddled-if-then-else.expect
 create mode 100644 t/chainlint/cuddled-if-then-else.test
 create mode 100644 t/chainlint/cuddled-loop.expect
 create mode 100644 t/chainlint/cuddled-loop.test
 create mode 100644 t/chainlint/cuddled.expect
 create mode 100644 t/chainlint/cuddled.test

diff --git a/t/chainlint/cuddled-if-then-else.expect b/t/chainlint/cuddled-if-then-else.expect
new file mode 100644
index 0000000000..ab2a026fbc
--- /dev/null
+++ b/t/chainlint/cuddled-if-then-else.expect
@@ -0,0 +1,7 @@
+(
+if test -z ""; then
+    echo empty
+ else
+    echo bizzy
+> fi) &&
+echo foobar
diff --git a/t/chainlint/cuddled-if-then-else.test b/t/chainlint/cuddled-if-then-else.test
new file mode 100644
index 0000000000..eed774a9d6
--- /dev/null
+++ b/t/chainlint/cuddled-if-then-else.test
@@ -0,0 +1,7 @@
+# LINT: 'if' cuddled with "(" and ")"; indented with spaces, not tabs
+(if test -z ""; then
+    echo empty
+ else
+    echo bizzy
+ fi) &&
+echo foobar
diff --git a/t/chainlint/cuddled-loop.expect b/t/chainlint/cuddled-loop.expect
new file mode 100644
index 0000000000..8c0260d7f1
--- /dev/null
+++ b/t/chainlint/cuddled-loop.expect
@@ -0,0 +1,5 @@
+(
+ while read x
+  do foobar bop || exit 1
+>  done <file ) &&
+outside subshell
diff --git a/t/chainlint/cuddled-loop.test b/t/chainlint/cuddled-loop.test
new file mode 100644
index 0000000000..a841d781f0
--- /dev/null
+++ b/t/chainlint/cuddled-loop.test
@@ -0,0 +1,7 @@
+# LINT: 'while' loop cuddled with "(" and ")", with embedded (allowed)
+# LINT: "|| exit {n}" to exit loop early, and using redirection "<" to feed
+# LINT: loop; indented with spaces, not tabs
+( while read x
+  do foobar bop || exit 1
+  done <file ) &&
+outside subshell
diff --git a/t/chainlint/cuddled.expect b/t/chainlint/cuddled.expect
new file mode 100644
index 0000000000..b506d46221
--- /dev/null
+++ b/t/chainlint/cuddled.expect
@@ -0,0 +1,21 @@
+(
+cd foo &&
+	bar
+>) &&
+
+(
+?!AMP?!cd foo
+	bar
+>) &&
+
+(
+	cd foo &&
+>	bar) &&
+
+(
+cd foo &&
+>	bar) &&
+
+(
+?!AMP?!cd foo
+>	bar)
diff --git a/t/chainlint/cuddled.test b/t/chainlint/cuddled.test
new file mode 100644
index 0000000000..0499fa4180
--- /dev/null
+++ b/t/chainlint/cuddled.test
@@ -0,0 +1,23 @@
+# LINT: first subshell statement cuddled with opening "("; for implementation
+# LINT: simplicity, "(..." is split into two lines, "(" and "..."
+(cd foo &&
+	bar
+) &&
+
+# LINT: same with missing "&&"
+(cd foo
+	bar
+) &&
+
+# LINT: closing ")" cuddled with final subshell statement
+(
+	cd foo &&
+	bar) &&
+
+# LINT: "(" and ")" cuddled with first and final subshell statements
+(cd foo &&
+	bar) &&
+
+# LINT: same with missing "&&"
+(cd foo
+	bar)
-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v2 09/10] t/chainlint: add chainlint "complex" test cases
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
                     ` (7 preceding siblings ...)
  2018-07-11  6:46   ` [PATCH v2 08/10] t/chainlint: add chainlint "cuddled" " Eric Sunshine
@ 2018-07-11  6:46   ` " Eric Sunshine
  2018-07-11  6:46   ` [PATCH v2 10/10] t/chainlint: add chainlint "specialized" " Eric Sunshine
  9 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-07-11  6:46 UTC (permalink / raw)
  To: git
  Cc: Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Junio C Hamano, Luke Diamand, Jeff King,
	Eric Sunshine

The --chain-lint option uses heuristics and knowledge of shell syntax to
detect broken &&-chains in subshells by pure textual inspection. The
heuristics handle a range of stylistic variations in existing tests
(evolved over the years), however, they are still best-guesses. As such,
it is possible for future changes to accidentally break assumptions upon
which the heuristics are based. Protect against this possibility by
adding tests which check the linter itself for correctness.

In addition to protecting against regressions, these tests help document
(for humans) expected behavior, which is important since the linter's
implementation language ('sed') does not necessarily lend itself to easy
comprehension.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 .../close-nested-and-parent-together.expect       |  4 ++++
 t/chainlint/close-nested-and-parent-together.test |  3 +++
 t/chainlint/complex-if-in-cuddled-loop.expect     | 10 ++++++++++
 t/chainlint/complex-if-in-cuddled-loop.test       | 11 +++++++++++
 t/chainlint/if-in-loop.expect                     | 12 ++++++++++++
 t/chainlint/if-in-loop.test                       | 15 +++++++++++++++
 t/chainlint/loop-in-if.expect                     | 12 ++++++++++++
 t/chainlint/loop-in-if.test                       | 15 +++++++++++++++
 8 files changed, 82 insertions(+)
 create mode 100644 t/chainlint/close-nested-and-parent-together.expect
 create mode 100644 t/chainlint/close-nested-and-parent-together.test
 create mode 100644 t/chainlint/complex-if-in-cuddled-loop.expect
 create mode 100644 t/chainlint/complex-if-in-cuddled-loop.test
 create mode 100644 t/chainlint/if-in-loop.expect
 create mode 100644 t/chainlint/if-in-loop.test
 create mode 100644 t/chainlint/loop-in-if.expect
 create mode 100644 t/chainlint/loop-in-if.test

diff --git a/t/chainlint/close-nested-and-parent-together.expect b/t/chainlint/close-nested-and-parent-together.expect
new file mode 100644
index 0000000000..2a910f9d66
--- /dev/null
+++ b/t/chainlint/close-nested-and-parent-together.expect
@@ -0,0 +1,4 @@
+(
+cd foo &&
+	(bar &&
+>>>		baz))
diff --git a/t/chainlint/close-nested-and-parent-together.test b/t/chainlint/close-nested-and-parent-together.test
new file mode 100644
index 0000000000..72d482f76d
--- /dev/null
+++ b/t/chainlint/close-nested-and-parent-together.test
@@ -0,0 +1,3 @@
+(cd foo &&
+	(bar &&
+		baz))
diff --git a/t/chainlint/complex-if-in-cuddled-loop.expect b/t/chainlint/complex-if-in-cuddled-loop.expect
new file mode 100644
index 0000000000..9674b88cf2
--- /dev/null
+++ b/t/chainlint/complex-if-in-cuddled-loop.expect
@@ -0,0 +1,10 @@
+(
+for i in a b c; do
+   if test "$(echo $(waffle bat))" = "eleventeen" &&
+     test "$x" = "$y"; then
+     :
+   else
+     echo >file
+   fi
+> done) &&
+test ! -f file
diff --git a/t/chainlint/complex-if-in-cuddled-loop.test b/t/chainlint/complex-if-in-cuddled-loop.test
new file mode 100644
index 0000000000..571bbd85cd
--- /dev/null
+++ b/t/chainlint/complex-if-in-cuddled-loop.test
@@ -0,0 +1,11 @@
+# LINT: 'for' loop cuddled with "(" and ")" and nested 'if' with complex
+# LINT: multi-line condition; indented with spaces, not tabs
+(for i in a b c; do
+   if test "$(echo $(waffle bat))" = "eleventeen" &&
+     test "$x" = "$y"; then
+     :
+   else
+     echo >file
+   fi
+ done) &&
+test ! -f file
diff --git a/t/chainlint/if-in-loop.expect b/t/chainlint/if-in-loop.expect
new file mode 100644
index 0000000000..03d3ceb22d
--- /dev/null
+++ b/t/chainlint/if-in-loop.expect
@@ -0,0 +1,12 @@
+(
+	for i in a b c
+	do
+		if false
+		then
+?!AMP?!			echo "err"
+			exit 1
+?!AMP?!		fi
+		foo
+?!AMP?!	done
+	bar
+>)
diff --git a/t/chainlint/if-in-loop.test b/t/chainlint/if-in-loop.test
new file mode 100644
index 0000000000..daf22da164
--- /dev/null
+++ b/t/chainlint/if-in-loop.test
@@ -0,0 +1,15 @@
+(
+	for i in a b c
+	do
+		if false
+		then
+# LINT: missing "&&" on 'echo'
+			echo "err"
+			exit 1
+# LINT: missing "&&" on 'fi'
+		fi
+		foo
+# LINT: missing "&&" on 'done'
+	done
+	bar
+)
diff --git a/t/chainlint/loop-in-if.expect b/t/chainlint/loop-in-if.expect
new file mode 100644
index 0000000000..088e622c31
--- /dev/null
+++ b/t/chainlint/loop-in-if.expect
@@ -0,0 +1,12 @@
+(
+	if true
+	then
+		while true
+		do
+?!AMP?!			echo "pop"
+			echo "glup"
+?!AMP?!		done
+		foo
+?!AMP?!	fi
+	bar
+>)
diff --git a/t/chainlint/loop-in-if.test b/t/chainlint/loop-in-if.test
new file mode 100644
index 0000000000..93e8ba8e4d
--- /dev/null
+++ b/t/chainlint/loop-in-if.test
@@ -0,0 +1,15 @@
+(
+	if true
+	then
+		while true
+		do
+# LINT: missing "&&" on 'echo'
+			echo "pop"
+			echo "glup"
+# LINT: missing "&&" on 'done'
+		done
+		foo
+# LINT: missing "&&" on 'fi'
+	fi
+	bar
+)
-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v2 10/10] t/chainlint: add chainlint "specialized" test cases
  2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
                     ` (8 preceding siblings ...)
  2018-07-11  6:46   ` [PATCH v2 09/10] t/chainlint: add chainlint "complex" " Eric Sunshine
@ 2018-07-11  6:46   ` " Eric Sunshine
  9 siblings, 0 replies; 82+ messages in thread
From: Eric Sunshine @ 2018-07-11  6:46 UTC (permalink / raw)
  To: git
  Cc: Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Junio C Hamano, Luke Diamand, Jeff King,
	Eric Sunshine

The --chain-lint option uses heuristics and knowledge of shell syntax to
detect broken &&-chains in subshells by pure textual inspection. The
heuristics handle a range of stylistic variations in existing tests
(evolved over the years), however, they are still best-guesses. As such,
it is possible for future changes to accidentally break assumptions upon
which the heuristics are based. Protect against this possibility by
adding tests which check the linter itself for correctness.

In addition to protecting against regressions, these tests help document
(for humans) expected behavior, which is important since the linter's
implementation language ('sed') does not necessarily lend itself to easy
comprehension.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/chainlint/bash-array.expect  | 10 ++++++++++
 t/chainlint/bash-array.test    | 12 ++++++++++++
 t/chainlint/p4-filespec.expect |  4 ++++
 t/chainlint/p4-filespec.test   |  5 +++++
 4 files changed, 31 insertions(+)
 create mode 100644 t/chainlint/bash-array.expect
 create mode 100644 t/chainlint/bash-array.test
 create mode 100644 t/chainlint/p4-filespec.expect
 create mode 100644 t/chainlint/p4-filespec.test

diff --git a/t/chainlint/bash-array.expect b/t/chainlint/bash-array.expect
new file mode 100644
index 0000000000..c4a830d1c1
--- /dev/null
+++ b/t/chainlint/bash-array.expect
@@ -0,0 +1,10 @@
+(
+	foo &&
+	bar=(gumbo stumbo wumbo) &&
+	baz
+>) &&
+(
+	foo &&
+	bar=${#bar[@]} &&
+	baz
+>)
diff --git a/t/chainlint/bash-array.test b/t/chainlint/bash-array.test
new file mode 100644
index 0000000000..92bbb777b8
--- /dev/null
+++ b/t/chainlint/bash-array.test
@@ -0,0 +1,12 @@
+(
+	foo &&
+# LINT: ")" in Bash array assignment not misinterpreted as subshell-closing ")"
+	bar=(gumbo stumbo wumbo) &&
+	baz
+) &&
+(
+	foo &&
+# LINT: Bash array length operator not misinterpreted as comment
+	bar=${#bar[@]} &&
+	baz
+)
diff --git a/t/chainlint/p4-filespec.expect b/t/chainlint/p4-filespec.expect
new file mode 100644
index 0000000000..98b3d881fd
--- /dev/null
+++ b/t/chainlint/p4-filespec.expect
@@ -0,0 +1,4 @@
+(
+	p4 print -1 //depot/fiddle#42 >file &&
+	foobar
+>)
diff --git a/t/chainlint/p4-filespec.test b/t/chainlint/p4-filespec.test
new file mode 100644
index 0000000000..4fd2d6e2b8
--- /dev/null
+++ b/t/chainlint/p4-filespec.test
@@ -0,0 +1,5 @@
+(
+# LINT: Perforce revspec in filespec not misinterpreted as in-line comment
+	p4 print -1 //depot/fiddle#42 >file &&
+	foobar
+)
-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v2 01/10] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-07-11  6:46   ` [PATCH v2 01/10] t/test-lib: teach --chain-lint to " Eric Sunshine
@ 2018-07-11 21:37     ` Junio C Hamano
  2018-07-12 10:50       ` Eric Sunshine
  0 siblings, 1 reply; 82+ messages in thread
From: Junio C Hamano @ 2018-07-11 21:37 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: git, Elijah Newren, Johannes Sixt, Jonathan Nieder, Jonathan Tan,
	Stefan Beller, Luke Diamand, Jeff King

Eric Sunshine <sunshine@sunshineco.com> writes:

> The --chain-lint option detects broken &&-chains by forcing the test to
> exit early (as the very first step) with a sentinel value. If that
> sentinel is the test's overall exit code, then the &&-chain is intact;
> if not, then the chain is broken. Unfortunately, this detection does not
> extend to &&-chains within subshells even when the subshell itself is
> properly linked into the outer &&-chain.
>
> Address this shortcoming by feeding the body of the test to a
> lightweight "linter" which can peer inside subshells and identify broken
> &&-chains by pure textual inspection. Although the linter does not
> ...
> Heuristics are employed to properly identify the extent of a subshell
> formatted in the old-style since a number of legitimate constructs may
> superficially appear to close the subshell even though they don't. For
> example, it understands that neither "x=$(command)" nor "case $x in *)"
> end a subshell, despite the ")" at the end of line.
>
> Due to limitations of the tool used ('sed') and its inherent
> line-by-line processing, only subshells one level deep are handled, as
> well as one-liner subshells one level below that. Subshells deeper than
> that or multi-line subshells at level two are passed through as-is, thus
> &&-chains in their bodies are not checked.
>
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> ---

As with the previous "transform the script and feed the result to
shell" approach, this risks to force us into writing our tests in a
subset of valid shell language, which is the primary reason why I
was not enthused when I saw the previous round.  The worst part of
it is that the subset is not strictly defined based on the shell
language syntax or features (e.g. we allow this and that feature but
not that other feature) but "whatever that does not cause the linter
script to trigger false positives".

So I dunno.  I haven't spent enough time to carefully look at the
actual scripts to access how serious the "problem" I perceive
actually is with this series to form a firm opinion yet.  Let me
come back to the topic after doing so.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v2 01/10] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-07-11 21:37     ` Junio C Hamano
@ 2018-07-12 10:50       ` Eric Sunshine
  2018-07-12 16:56         ` Jeff King
  0 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-07-12 10:50 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git List, Elijah Newren, Johannes Sixt, Jonathan Nieder,
	Jonathan Tan, Stefan Beller, Luke Diamand, Jeff King

On Wed, Jul 11, 2018 at 5:37 PM Junio C Hamano <gitster@pobox.com> wrote:
> As with the previous "transform the script and feed the result to
> shell" approach, this risks to force us into writing our tests in a
> subset of valid shell language, which is the primary reason why I
> was not enthused when I saw the previous round.  The worst part of
> it is that the subset is not strictly defined based on the shell
> language syntax or features (e.g. we allow this and that feature but
> not that other feature) but "whatever that does not cause the linter
> script to trigger false positives".

Some observations perhaps worth considering:

The linter is happy (no false positives) with the 13000+ existing
tests (though, of course, not all of them use subshells). Those tests,
written over many years, vary quite wildly in style and implementation
approach, so the "subset" of shell language accepted by the linter is
quite broad.

The original --chain-lint series (jk/test-chain-lint) had to make some
changes, such as wrapping code in a {...} block[1], merely to pacify
the linter. v2 of the subshell linter required no such changes.

The subshell linter was crafted to be on par with the existing
--chain-lint in terms of strictness (and looseness), so the subshell
linter is not more strict than the existing implementation. (For
instance, one can escape the strict &&-chain requirement in the
existing --chain-lint by wrapping code in a {...} block. The subshell
linter intentionally allows that escape, as well.)

And, perhaps most important: We're not tied indefinitely to the
"subset" implemented by the current linter. If it is indeed found to
be too strict or limiting, it can always be loosened or retired
altogether.

Thanks for the feedback.

[1]: bfe998fc9b (t0050: appease --chain-lint, 2015-03-20)

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v2 01/10] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-07-12 10:50       ` Eric Sunshine
@ 2018-07-12 16:56         ` Jeff King
  2018-07-12 19:32           ` Eric Sunshine
  0 siblings, 1 reply; 82+ messages in thread
From: Jeff King @ 2018-07-12 16:56 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Junio C Hamano, Git List, Elijah Newren, Johannes Sixt,
	Jonathan Nieder, Jonathan Tan, Stefan Beller, Luke Diamand

On Thu, Jul 12, 2018 at 06:50:20AM -0400, Eric Sunshine wrote:

> And, perhaps most important: We're not tied indefinitely to the
> "subset" implemented by the current linter. If it is indeed found to
> be too strict or limiting, it can always be loosened or retired
> altogether.

Yeah, I agree this is the key point.

Like Junio, I'm a little nervous that this is going to end up being a
maintenance burden. People may hit false positives and then be
confronted with this horrible mass of sed to try to figure out what went
wrong (which isn't to bust on your sed in particular; I think you made a
heroic effort in commenting).

But I came around to thinking:

  - this found and fixed real problems in the test suite, with minimal
    false positives across the existing code

  - it's being done by a long-time contributor, not somebody who is
    going to dump sed on us and leave

  - worst case is that relief is only a "git revert" away

So I'm OK with merging it, and even running it by default.

-Peff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v2 01/10] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-07-12 16:56         ` Jeff King
@ 2018-07-12 19:32           ` Eric Sunshine
  2018-07-12 19:54             ` Junio C Hamano
  0 siblings, 1 reply; 82+ messages in thread
From: Eric Sunshine @ 2018-07-12 19:32 UTC (permalink / raw)
  To: Jeff King
  Cc: Junio C Hamano, Git List, Elijah Newren, Johannes Sixt,
	Jonathan Nieder, Jonathan Tan, Stefan Beller, Luke Diamand

On Thu, Jul 12, 2018 at 12:56 PM Jeff King <peff@peff.net> wrote:
> Like Junio, I'm a little nervous that this is going to end up being a
> maintenance burden. People may hit false positives and then be
> confronted with this horrible mass of sed to try to figure out what went
> wrong [...]

A very valid concern.

> But I came around to thinking:
>   - this found and fixed real problems in the test suite, with minimal
>     false positives across the existing code

The counterargument (and arguing against my own case) is that, while
it found 3 or 4 genuine test bugs hidden by &&-breakage, they were
just that: bugs in the tests; they weren't hiding any bugs in Git
itself, which is pretty measly return for the effort invested in the
linter.

However, existing tests aside, the more important goal is detecting
problems in new or updated tests hiding genuine bugs in changes to Git
itself, so it may have some value.

>   - worst case is that relief is only a "git revert" away

Right. It's just a developer aid, not a user-facing feature which has
to be maintained in perpetuity, so retiring it is easy.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v2 01/10] t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
  2018-07-12 19:32           ` Eric Sunshine
@ 2018-07-12 19:54             ` Junio C Hamano
  0 siblings, 0 replies; 82+ messages in thread
From: Junio C Hamano @ 2018-07-12 19:54 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Jeff King, Git List, Elijah Newren, Johannes Sixt,
	Jonathan Nieder, Jonathan Tan, Stefan Beller, Luke Diamand

Eric Sunshine <sunshine@sunshineco.com> writes:

> However, existing tests aside, the more important goal is detecting
> problems in new or updated tests hiding genuine bugs in changes to Git
> itself, so it may have some value.

Yes, indeed.

^ permalink raw reply	[flat|nested] 82+ messages in thread

end of thread, back to index

Thread overview: 82+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-26  7:29 [PATCH 00/29] t: detect and fix broken &&-chains in subshells Eric Sunshine
2018-06-26  7:29 ` [PATCH 01/29] t7508: use test_when_finished() instead of managing exit code manually Eric Sunshine
2018-06-26  7:29 ` [PATCH 02/29] t0001: use "{...}" block around "||" expression rather than subshell Eric Sunshine
2018-06-26  7:29 ` [PATCH 03/29] t1300: use sane_unset() to avoid breaking &&-chain Eric Sunshine
2018-06-26  7:29 ` [PATCH 04/29] t3303: use standard here-doc tag "EOF" to avoid fooling --chain-lint Eric Sunshine
2018-06-26  7:29 ` [PATCH 05/29] t5505: modernize and simplify hard-to-digest test Eric Sunshine
2018-06-26  7:29 ` [PATCH 06/29] t6036: fix broken "merge fails but has appropriate contents" tests Eric Sunshine
2018-06-26  8:44   ` Elijah Newren
2018-06-26  7:29 ` [PATCH 07/29] t7201: drop pointless "exit 0" at end of subshell Eric Sunshine
2018-06-26  7:29 ` [PATCH 08/29] t7400: fix broken "submodule add/reconfigure --force" test Eric Sunshine
2018-06-27 18:04   ` Stefan Beller
2018-06-26  7:29 ` [PATCH 09/29] t7810: use test_expect_code() instead of hand-rolled comparison Eric Sunshine
2018-06-26  7:29 ` [PATCH 10/29] t9001: fix broken "invoke hook" test Eric Sunshine
2018-06-26 17:07   ` Jonathan Tan
2018-06-26  7:29 ` [PATCH 11/29] t9104: use "{...}" block around "||" expression rather than subshell Eric Sunshine
2018-06-26  7:29 ` [PATCH 12/29] t9401: drop unnecessary nested subshell Eric Sunshine
2018-06-26  7:29 ` [PATCH 13/29] t/lib-submodule-update: fix broken "replace submodule must-fail" test Eric Sunshine
2018-06-27 18:30   ` [PATCH] t/lib-submodule-update: fix absorbing test Stefan Beller
2018-06-27 18:38     ` Eric Sunshine
2018-06-26  7:29 ` [PATCH 14/29] t: drop subshell with missing &&-chain in favor of simpler construct Eric Sunshine
2018-06-26 19:31   ` Junio C Hamano
2018-06-26 20:06     ` Eric Sunshine
2018-06-26  7:29 ` [PATCH 15/29] t: drop unnecessary terminating semicolons in subshell Eric Sunshine
2018-06-26  7:29 ` [PATCH 16/29] t: use test_might_fail() instead of manipulating exit code manually Eric Sunshine
2018-06-26  7:29 ` [PATCH 17/29] t: use test_must_fail() instead of checking " Eric Sunshine
2018-06-26  7:59   ` Luke Diamand
2018-06-26  8:58   ` Elijah Newren
2018-06-26  9:21     ` Eric Sunshine
2018-06-26 18:05       ` Johannes Sixt
2018-06-26 18:14         ` Eric Sunshine
2018-06-26 21:00           ` Johannes Sixt
2018-06-26  7:29 ` [PATCH 18/29] t0000-t0999: fix broken &&-chains in subshells Eric Sunshine
2018-06-26  7:29 ` [PATCH 19/29] t1000-t1999: " Eric Sunshine
2018-06-26  7:29 ` [PATCH 20/29] t2000-t2999: " Eric Sunshine
2018-06-26  7:29 ` [PATCH 21/29] t3000-t3999: " Eric Sunshine
2018-06-26  7:29 ` [PATCH 22/29] t3030: " Eric Sunshine
2018-06-26  7:29 ` [PATCH 23/29] t4000-t4999: " Eric Sunshine
2018-06-26  7:29 ` [PATCH 24/29] t5000-t5999: " Eric Sunshine
2018-06-26  7:29 ` [PATCH 25/29] t6000-t6999: " Eric Sunshine
2018-06-26  7:29 ` [PATCH 26/29] t7000-t7999: " Eric Sunshine
2018-06-26  7:29 ` [PATCH 27/29] t9000-t9999: " Eric Sunshine
2018-06-26  7:30 ` [PATCH 28/29] t9119: " Eric Sunshine
2018-06-26  7:30 ` [PATCH 29/29] t/test-lib: teach --chain-lint to detect " Eric Sunshine
2018-06-26 19:15   ` Junio C Hamano
2018-06-26 19:52     ` Eric Sunshine
2018-06-26 20:17       ` Jeff King
2018-06-26 20:22         ` Jeff King
2018-06-26 20:59           ` Eric Sunshine
2018-06-26 21:33           ` Elijah Newren
2018-06-26 21:42             ` Eric Sunshine
2018-06-26 20:46         ` Eric Sunshine
2018-06-26 21:01           ` Jeff King
2018-06-26 21:13             ` Eric Sunshine
2018-06-28 14:35               ` Jeff King
2018-06-27  2:15             ` Elijah Newren
2018-06-27  6:27               ` Johannes Sixt
2018-06-27  6:48                 ` Eric Sunshine
2018-06-28 14:37               ` Jeff King
2018-06-26 21:09         ` Junio C Hamano
2018-06-26  9:20 ` [PATCH 00/29] t: detect and fix " Elijah Newren
2018-06-26  9:31   ` Eric Sunshine
2018-06-26 15:34     ` Elijah Newren
2018-06-26 19:38 ` Junio C Hamano
2018-06-26 21:25   ` Eric Sunshine
2018-06-26 22:31     ` Junio C Hamano
2018-06-27  0:22       ` Jonathan Nieder
2018-07-11  6:46 ` [PATCH v2 00/10] detect " Eric Sunshine
2018-07-11  6:46   ` [PATCH v2 01/10] t/test-lib: teach --chain-lint to " Eric Sunshine
2018-07-11 21:37     ` Junio C Hamano
2018-07-12 10:50       ` Eric Sunshine
2018-07-12 16:56         ` Jeff King
2018-07-12 19:32           ` Eric Sunshine
2018-07-12 19:54             ` Junio C Hamano
2018-07-11  6:46   ` [PATCH v2 02/10] t/Makefile: add machinery to check correctness of chainlint.sed Eric Sunshine
2018-07-11  6:46   ` [PATCH v2 03/10] t/chainlint: add chainlint "basic" test cases Eric Sunshine
2018-07-11  6:46   ` [PATCH v2 04/10] t/chainlint: add chainlint "whitespace" " Eric Sunshine
2018-07-11  6:46   ` [PATCH v2 05/10] t/chainlint: add chainlint "one-liner" " Eric Sunshine
2018-07-11  6:46   ` [PATCH v2 06/10] t/chainlint: add chainlint "nested subshell" " Eric Sunshine
2018-07-11  6:46   ` [PATCH v2 07/10] t/chainlint: add chainlint "loop" and "conditional" " Eric Sunshine
2018-07-11  6:46   ` [PATCH v2 08/10] t/chainlint: add chainlint "cuddled" " Eric Sunshine
2018-07-11  6:46   ` [PATCH v2 09/10] t/chainlint: add chainlint "complex" " Eric Sunshine
2018-07-11  6:46   ` [PATCH v2 10/10] t/chainlint: add chainlint "specialized" " Eric Sunshine

git@vger.kernel.org mailing list mirror (one of many)

Archives are clonable:
	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.org/gmane.comp.version-control.git

 note: .onion URLs require Tor: https://www.torproject.org/
       or Tor2web: https://www.tor2web.org/

AGPL code for this site: git clone https://public-inbox.org/ public-inbox