From 1ca7c581a326dab9418d3d3eb665e1f27f6ca8ed Mon Sep 17 00:00:00 2001 From: Stefan Lay Date: Wed, 9 Jan 2013 14:02:13 +0100 Subject: [PATCH] Only replace the ChangeId in the footer, not in the body Additionally expose methods to find the first footer line and to find the position of the ChangeId footer in the commit message in order to enable reuse of these methods introduced for the fix. Change-Id: I87ecca009ca3bff1ca0de3c436ebd95736bf5a10 Signed-off-by: Matthias Sohn Signed-off-by: Robin Rosenberg --- .../eclipse/jgit/util/ChangeIdUtilTest.java | 86 ++++++++++++++++- .../org/eclipse/jgit/util/ChangeIdUtil.java | 95 ++++++++++++++----- 2 files changed, 151 insertions(+), 30 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java index 4cdc02ac5..54f3114c6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java @@ -123,15 +123,65 @@ public class ChangeIdUtilTest { @Test public void testHasChangeid() throws Exception { assertEquals( - "has changeid\n\nBug: 33\nmore text\nSigned-off-by: me@you.too\nChange-Id: I0123456789012345678901234567890123456789\nAnd then some\n", - call("has changeid\n\nBug: 33\nmore text\nSigned-off-by: me@you.too\nChange-Id: I0123456789012345678901234567890123456789\nAnd then some\n")); + "has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\n", + call("has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\n")); } @Test public void testHasChangeidWithReplacement() throws Exception { assertEquals( - "has changeid\n\nBug: 33\nmore text\nSigned-off-by: me@you.too\nChange-Id: I988d2d7a6f2c0578fccabd4ebd3cec0768bc7f9f\nAnd then some\n", - call("has changeid\n\nBug: 33\nmore text\nSigned-off-by: me@you.too\nChange-Id: I0123456789012345678901234567890123456789\nAnd then some\n", + "has changeid\nmore text\n\nSigned-off-by: me@you.too\n" + + "Change-Id: I2178563fada5edb2c99a8d8c0d619471b050ec24\nBug: 33\n", + call("has changeid\nmore text\n\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\nBug: 33\n", + true)); + } + + @Test + public void testHasChangeidWithReplacementInLastLine() throws Exception { + assertEquals( + "has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I1d6578f4c96e3db4dd707705fe3d17bf658c4758\n", + call("has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\n", + true)); + } + + @Test + public void testHasChangeidWithReplacementInLastLineNoLineBreak() + throws Exception { + assertEquals( + "has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I1d6578f4c96e3db4dd707705fe3d17bf658c4758", + call("has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789", + true)); + } + + @Test + public void testHasChangeidWithSpacesBeforeId() throws Exception { + assertEquals( + "has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: Ie7575eaf450fdd0002df2e642426faf251de3ad9\n", + call("has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\n", + true)); + } + + @Test + public void testHasChangeidWithReplacementWithChangeIdInCommitMessage() + throws Exception { + assertEquals( + "has changeid\nmore text\n" + + "Change-Id: I0123456789012345678901234567890123456789\n\n" + + "Bug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: Ie48d10d59ef67995ca89688ac0171b88f10dd520\n", + call("has changeid\nmore text\n" + + "Change-Id: I0123456789012345678901234567890123456789\n\n" + + "Bug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\n", true)); } @@ -587,6 +637,34 @@ public class ChangeIdUtilTest { "git://example.com/ fixes this\n")); } + @Test + public void testIndexOfChangeId() { + assertEquals(3, ChangeIdUtil.indexOfChangeId("x\n" + "\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n", + "\n")); + assertEquals(5, ChangeIdUtil.indexOfChangeId("x\r\n" + "\r\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\r\n", + "\r\n")); + assertEquals(3, ChangeIdUtil.indexOfChangeId("x\r" + "\r" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\r", + "\r")); + assertEquals(8, ChangeIdUtil.indexOfChangeId("x\ny\n\nz\n" + "\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n", + "\n")); + } + + @Test + public void testIndexOfFirstFooterLine() { + assertEquals( + 2, + ChangeIdUtil.indexOfFirstFooterLine(new String[] { "a", "", + "Bug: 42", "Signed-Off-By: j.developer@a.com" })); + assertEquals( + 3, + ChangeIdUtil.indexOfFirstFooterLine(new String[] { "a", + "Bug: 42", "", "Signed-Off-By: j.developer@a.com" })); + } + private void hookDoesNotModify(final String in) throws Exception { assertEquals(in, call(in)); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java index a869b2bea..41bb4cc7e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java @@ -161,36 +161,26 @@ public class ChangeIdUtil { */ public static String insertId(String message, ObjectId changeId, boolean replaceExisting) { - if (message.indexOf(CHANGE_ID) > 0) { - if (replaceExisting) { - int i = message.indexOf(CHANGE_ID) + 10; - while (message.charAt(i) == ' ') - i++; - String oldId = message.length() == (i + 40) ? - message.substring(i) : message.substring(i, i + 41); - message = message.replace(oldId, "I" + changeId.getName()); //$NON-NLS-1$ + int indexOfChangeId = indexOfChangeId(message, "\n"); //$NON-NLS-1$ + if (indexOfChangeId > 0) { + if (!replaceExisting) + return message; + else { + StringBuilder ret = new StringBuilder(message.substring(0, + indexOfChangeId)); + ret.append(CHANGE_ID); + ret.append(" I"); //$NON-NLS-1$ + ret.append(ObjectId.toString(changeId)); + int indexOfNextLineBreak = message.indexOf("\n", //$NON-NLS-1$ + indexOfChangeId); + if (indexOfNextLineBreak > 0) + ret.append(message.substring(indexOfNextLineBreak)); + return ret.toString(); } - return message; } String[] lines = message.split("\n"); //$NON-NLS-1$ - int footerFirstLine = lines.length; - for (int i = lines.length - 1; i > 1; --i) { - if (footerPattern.matcher(lines[i]).matches()) { - footerFirstLine = i; - continue; - } - if (footerFirstLine != lines.length && lines[i].length() == 0) { - break; - } - if (footerFirstLine != lines.length - && includeInFooterPattern.matcher(lines[i]).matches()) { - footerFirstLine = i + 1; - continue; - } - footerFirstLine = lines.length; - break; - } + int footerFirstLine = indexOfFirstFooterLine(lines); int insertAfter = footerFirstLine; for (int i = footerFirstLine; i < lines.length; ++i) { if (issuePattern.matcher(lines[i]).matches()) { @@ -217,4 +207,57 @@ public class ChangeIdUtil { } return ret.toString(); } + + /** + * Find the index in the String {@code} message} where the Change-Id entry + * begins + * + * @param message + * @param delimiter + * the line delimiter, like "\n" or "\r\n", needed to find the + * footer + * @return the index of the ChangeId footer in the message, or -1 if no + * ChangeId footer available + */ + public static int indexOfChangeId(String message, String delimiter) { + String[] lines = message.split(delimiter); + int footerFirstLine = indexOfFirstFooterLine(lines); + if (footerFirstLine == lines.length) + return -1; + + int indexOfFooter = 0; + for (int i = 0; i < footerFirstLine; ++i) + indexOfFooter += lines[i].length() + delimiter.length(); + return message.indexOf(CHANGE_ID, indexOfFooter); + } + + /** + * Find the index of the first line of the footer paragraph in an array of + * the lines, or lines.length if no footer is available + * + * @param lines + * the commit message split into lines and the line delimiters + * stripped off + * @return the index of the first line of the footer paragraph, or + * lines.length if no footer is available + */ + public static int indexOfFirstFooterLine(String[] lines) { + int footerFirstLine = lines.length; + for (int i = lines.length - 1; i > 1; --i) { + if (footerPattern.matcher(lines[i]).matches()) { + footerFirstLine = i; + continue; + } + if (footerFirstLine != lines.length && lines[i].length() == 0) + break; + if (footerFirstLine != lines.length + && includeInFooterPattern.matcher(lines[i]).matches()) { + footerFirstLine = i + 1; + continue; + } + footerFirstLine = lines.length; + break; + } + return footerFirstLine; + } }