Provide git config commit.cleanup
Add an enumeration for the possible values, and a method to resolve the "default" value. Give CommitConfig a static method to process a text according to a given clean-up mode and comment character. (The core.commentChar is not yet handled by JGit; it's hard-coded as #.) Bug: 553065 Change-Id: If6e384522275f73b713fbc29ffcaa1753c239dea Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
parent
2b01ac3389
commit
318a25f0e6
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (C) 2022, Thomas Wolf <thomas.wolf@paranor.ch> and others
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||
* https://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package org.eclipse.jgit.lib;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.lib.CommitConfig.CleanupMode;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CommitConfigTest {
|
||||
|
||||
@Test
|
||||
public void testDefaults() throws Exception {
|
||||
CommitConfig cfg = parse("");
|
||||
assertEquals("Unexpected clean-up mode", CleanupMode.DEFAULT,
|
||||
cfg.getCleanupMode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitCleanup() throws Exception {
|
||||
String[] values = { "strip", "whitespace", "verbatim", "scissors",
|
||||
"default" };
|
||||
CleanupMode[] expected = { CleanupMode.STRIP, CleanupMode.WHITESPACE,
|
||||
CleanupMode.VERBATIM, CleanupMode.SCISSORS,
|
||||
CleanupMode.DEFAULT };
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
CommitConfig cfg = parse("[commit]\n\tcleanup = " + values[i]);
|
||||
assertEquals("Unexpected clean-up mode", expected[i],
|
||||
cfg.getCleanupMode());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolve() throws Exception {
|
||||
String[] values = { "strip", "whitespace", "verbatim", "scissors",
|
||||
"default" };
|
||||
CleanupMode[] expected = { CleanupMode.STRIP, CleanupMode.WHITESPACE,
|
||||
CleanupMode.VERBATIM, CleanupMode.SCISSORS,
|
||||
CleanupMode.DEFAULT };
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
CommitConfig cfg = parse("[commit]\n\tcleanup = " + values[i]);
|
||||
for (CleanupMode mode : CleanupMode.values()) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
CleanupMode resolved = cfg.resolve(mode, j == 0);
|
||||
if (mode != CleanupMode.DEFAULT) {
|
||||
assertEquals("Clean-up mode should be unchanged", mode,
|
||||
resolved);
|
||||
} else if (i + 1 < values.length) {
|
||||
assertEquals("Unexpected clean-up mode", expected[i],
|
||||
resolved);
|
||||
} else {
|
||||
assertEquals("Unexpected clean-up mode",
|
||||
j == 0 ? CleanupMode.STRIP
|
||||
: CleanupMode.WHITESPACE,
|
||||
resolved);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanDefaultThrows() throws Exception {
|
||||
assertThrows(IllegalArgumentException.class, () -> CommitConfig
|
||||
.cleanText("Whatever", CleanupMode.DEFAULT, '#'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanVerbatim() throws Exception {
|
||||
String message = "\n \nWhatever \n\n\n# A comment\n\nMore\t \n\n\n";
|
||||
assertEquals("Unexpected message change", message,
|
||||
CommitConfig.cleanText(message, CleanupMode.VERBATIM, '#'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanWhitespace() throws Exception {
|
||||
String message = "\n \nWhatever \n\n\n# A comment\n\nMore\t \n\n\n";
|
||||
assertEquals("Unexpected message change",
|
||||
"Whatever\n\n# A comment\n\nMore\n",
|
||||
CommitConfig.cleanText(message, CleanupMode.WHITESPACE, '#'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanStrip() throws Exception {
|
||||
String message = "\n \nWhatever \n\n\n# A comment\n\nMore\t \n\n\n";
|
||||
assertEquals("Unexpected message change", "Whatever\n\nMore\n",
|
||||
CommitConfig.cleanText(message, CleanupMode.STRIP, '#'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanStripCustomChar() throws Exception {
|
||||
String message = "\n \nWhatever \n\n\n# Not a comment\n\n <A comment\nMore\t \n\n\n";
|
||||
assertEquals("Unexpected message change",
|
||||
"Whatever\n\n# Not a comment\n\nMore\n",
|
||||
CommitConfig.cleanText(message, CleanupMode.STRIP, '<'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanScissors() throws Exception {
|
||||
String message = "\n \nWhatever \n\n\n# Not a comment\n\n <A comment\nMore\t \n\n\n"
|
||||
+ "# ------------------------ >8 ------------------------\n"
|
||||
+ "More\nMore\n";
|
||||
assertEquals("Unexpected message change",
|
||||
"Whatever\n\n# Not a comment\n\n <A comment\nMore\n",
|
||||
CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanScissorsCustomChar() throws Exception {
|
||||
String message = "\n \nWhatever \n\n\n# Not a comment\n\n <A comment\nMore\t \n\n\n"
|
||||
+ "< ------------------------ >8 ------------------------\n"
|
||||
+ "More\nMore\n";
|
||||
assertEquals("Unexpected message change",
|
||||
"Whatever\n\n# Not a comment\n\n <A comment\nMore\n",
|
||||
CommitConfig.cleanText(message, CleanupMode.SCISSORS, '<'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanScissorsAtTop() throws Exception {
|
||||
String message = "# ------------------------ >8 ------------------------\n"
|
||||
+ "\n \nWhatever \n\n\n# Not a comment\n\n <A comment\nMore\t \n\n\n"
|
||||
+ "More\nMore\n";
|
||||
assertEquals("Unexpected message change", "",
|
||||
CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanScissorsNoScissor() throws Exception {
|
||||
String message = "\n \nWhatever \n\n\n# A comment\n\nMore\t \n\n\n";
|
||||
assertEquals("Unexpected message change",
|
||||
"Whatever\n\n# A comment\n\nMore\n",
|
||||
CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanScissorsNoScissor2() throws Exception {
|
||||
String message = "Text\n"
|
||||
+ "## ------------------------ >8 ------------------------\n"
|
||||
+ "More\nMore\n";
|
||||
assertEquals("Unexpected message change", message,
|
||||
CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanScissorsNoScissor3() throws Exception {
|
||||
String message = "Text\n"
|
||||
// Wrong number of dashes
|
||||
+ "# ----------------------- >8 ------------------------\n"
|
||||
+ "More\nMore\n";
|
||||
assertEquals("Unexpected message change", message,
|
||||
CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanScissorsAtEnd() throws Exception {
|
||||
String message = "Text\n"
|
||||
+ "# ------------------------ >8 ------------------------\n";
|
||||
assertEquals("Unexpected message change", "Text\n",
|
||||
CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
|
||||
}
|
||||
|
||||
private static CommitConfig parse(String content)
|
||||
throws ConfigInvalidException {
|
||||
Config c = new Config();
|
||||
c.fromText(content);
|
||||
return c.get(CommitConfig.KEY);
|
||||
}
|
||||
|
||||
}
|
|
@ -18,11 +18,13 @@
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jgit.annotations.NonNull;
|
||||
import org.eclipse.jgit.annotations.Nullable;
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.internal.JGitText;
|
||||
import org.eclipse.jgit.lib.Config.ConfigEnum;
|
||||
import org.eclipse.jgit.lib.Config.SectionParser;
|
||||
import org.eclipse.jgit.util.FS;
|
||||
import org.eclipse.jgit.util.IO;
|
||||
|
@ -34,22 +36,76 @@
|
|||
* @since 5.13
|
||||
*/
|
||||
public class CommitConfig {
|
||||
|
||||
/**
|
||||
* Key for {@link Config#get(SectionParser)}.
|
||||
*/
|
||||
public static final Config.SectionParser<CommitConfig> KEY = CommitConfig::new;
|
||||
|
||||
private static final String CUT = " ------------------------ >8 ------------------------\n"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* How to clean up commit messages when committing.
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public enum CleanupMode implements ConfigEnum {
|
||||
|
||||
/**
|
||||
* {@link #WHITESPACE}, additionally remove comment lines.
|
||||
*/
|
||||
STRIP,
|
||||
|
||||
/**
|
||||
* Remove trailing whitespace and leading and trailing empty lines;
|
||||
* collapse multiple empty lines to a single one.
|
||||
*/
|
||||
WHITESPACE,
|
||||
|
||||
/**
|
||||
* Make no changes.
|
||||
*/
|
||||
VERBATIM,
|
||||
|
||||
/**
|
||||
* Omit everything from the first "scissor" line on, then apply
|
||||
* {@link #WHITESPACE}.
|
||||
*/
|
||||
SCISSORS,
|
||||
|
||||
/**
|
||||
* Use {@link #STRIP} for user-edited messages, otherwise
|
||||
* {@link #WHITESPACE}, unless overridden by a git config setting other
|
||||
* than DEFAULT.
|
||||
*/
|
||||
DEFAULT;
|
||||
|
||||
@Override
|
||||
public String toConfigValue() {
|
||||
return name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchConfigValue(String in) {
|
||||
return toConfigValue().equals(in);
|
||||
}
|
||||
}
|
||||
|
||||
private final static Charset DEFAULT_COMMIT_MESSAGE_ENCODING = StandardCharsets.UTF_8;
|
||||
|
||||
private String i18nCommitEncoding;
|
||||
|
||||
private String commitTemplatePath;
|
||||
|
||||
private CleanupMode cleanupMode;
|
||||
|
||||
private CommitConfig(Config rc) {
|
||||
commitTemplatePath = rc.getString(ConfigConstants.CONFIG_COMMIT_SECTION,
|
||||
null, ConfigConstants.CONFIG_KEY_COMMIT_TEMPLATE);
|
||||
i18nCommitEncoding = rc.getString(ConfigConstants.CONFIG_SECTION_I18N,
|
||||
null, ConfigConstants.CONFIG_KEY_COMMIT_ENCODING);
|
||||
cleanupMode = rc.getEnum(ConfigConstants.CONFIG_COMMIT_SECTION, null,
|
||||
ConfigConstants.CONFIG_KEY_CLEANUP, CleanupMode.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,6 +130,48 @@ public String getCommitEncoding() {
|
|||
return i18nCommitEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the {@link CleanupMode} as given by git config
|
||||
* {@code commit.cleanup}.
|
||||
*
|
||||
* @return the {@link CleanupMode}; {@link CleanupMode#DEFAULT} if the git
|
||||
* config is not set
|
||||
* @since 6.1
|
||||
*/
|
||||
@NonNull
|
||||
public CleanupMode getCleanupMode() {
|
||||
return cleanupMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a non-default {@link CleanupMode} from the given mode and the
|
||||
* git config.
|
||||
*
|
||||
* @param mode
|
||||
* {@link CleanupMode} to resolve
|
||||
* @param defaultStrip
|
||||
* if {@code true} return {@link CleanupMode#STRIP} if the git
|
||||
* config is also "default", otherwise return
|
||||
* {@link CleanupMode#WHITESPACE}
|
||||
* @return the {@code mode}, if it is not {@link CleanupMode#DEFAULT},
|
||||
* otherwise the resolved mode, which is never
|
||||
* {@link CleanupMode#DEFAULT}
|
||||
* @since 6.1
|
||||
*/
|
||||
@NonNull
|
||||
public CleanupMode resolve(@NonNull CleanupMode mode,
|
||||
boolean defaultStrip) {
|
||||
if (CleanupMode.DEFAULT == mode) {
|
||||
CleanupMode defaultMode = getCleanupMode();
|
||||
if (CleanupMode.DEFAULT == defaultMode) {
|
||||
return defaultStrip ? CleanupMode.STRIP
|
||||
: CleanupMode.WHITESPACE;
|
||||
}
|
||||
return defaultMode;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content to the commit template as defined in
|
||||
* {@code commit.template}. If no {@code i18n.commitEncoding} is specified,
|
||||
|
@ -135,4 +233,86 @@ private Charset getEncoding() throws ConfigInvalidException {
|
|||
|
||||
return commitMessageEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a text according to the given {@link CleanupMode}.
|
||||
*
|
||||
* @param text
|
||||
* text to process
|
||||
* @param mode
|
||||
* {@link CleanupMode} to use
|
||||
* @param commentChar
|
||||
* comment character (normally {@code #}) to use if {@code mode}
|
||||
* is {@link CleanupMode#STRIP} or {@link CleanupMode#SCISSORS}
|
||||
* @return the processed text
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code mode} is {@link CleanupMode#DEFAULT} (use
|
||||
* {@link #resolve(CleanupMode, boolean)} first)
|
||||
* @since 6.1
|
||||
*/
|
||||
public static String cleanText(@NonNull String text,
|
||||
@NonNull CleanupMode mode, char commentChar) {
|
||||
String toProcess = text;
|
||||
boolean strip = false;
|
||||
switch (mode) {
|
||||
case VERBATIM:
|
||||
return text;
|
||||
case SCISSORS:
|
||||
String cut = commentChar + CUT;
|
||||
if (text.startsWith(cut)) {
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
int cutPos = text.indexOf('\n' + cut);
|
||||
if (cutPos >= 0) {
|
||||
toProcess = text.substring(0, cutPos + 1);
|
||||
}
|
||||
break;
|
||||
case STRIP:
|
||||
strip = true;
|
||||
break;
|
||||
case WHITESPACE:
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
// Internal error; no translation
|
||||
throw new IllegalArgumentException("Invalid clean-up mode " + mode); //$NON-NLS-1$
|
||||
}
|
||||
// WHITESPACE
|
||||
StringBuilder result = new StringBuilder();
|
||||
boolean lastWasEmpty = true;
|
||||
for (String line : toProcess.split("\n")) { //$NON-NLS-1$
|
||||
line = line.stripTrailing();
|
||||
if (line.isEmpty()) {
|
||||
if (!lastWasEmpty) {
|
||||
result.append('\n');
|
||||
lastWasEmpty = true;
|
||||
}
|
||||
} else if (!strip || !isComment(line, commentChar)) {
|
||||
lastWasEmpty = false;
|
||||
result.append(line).append('\n');
|
||||
}
|
||||
}
|
||||
int bufferSize = result.length();
|
||||
if (lastWasEmpty && bufferSize > 0) {
|
||||
bufferSize--;
|
||||
result.setLength(bufferSize);
|
||||
}
|
||||
if (bufferSize > 0 && !toProcess.endsWith("\n")) { //$NON-NLS-1$
|
||||
if (result.charAt(bufferSize - 1) == '\n') {
|
||||
result.setLength(bufferSize - 1);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static boolean isComment(String text, char commentChar) {
|
||||
int len = text.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
char ch = text.charAt(i);
|
||||
if (!Character.isWhitespace(ch)) {
|
||||
return ch == commentChar;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -181,6 +181,13 @@ public final class ConfigConstants {
|
|||
*/
|
||||
public static final String CONFIG_TAG_SECTION = "tag";
|
||||
|
||||
/**
|
||||
* The "cleanup" key
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public static final String CONFIG_KEY_CLEANUP = "cleanup";
|
||||
|
||||
/**
|
||||
* The "gpgSign" key
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue