From a1d4bc5726bbac54d256b41b2201ba14ae8da89d Mon Sep 17 00:00:00 2001 From: Joerg Budischewski Date: Sun, 20 Jul 2025 18:11:44 +0200 Subject: [PATCH 1/5] [cli-221] added new Option.Builder.listValueSeparator() to allow to properly use options with single argument-commaseparated values. To remain backward compatibility to the java-property-style parsing wth default valueSeparator '=', this mutually exclusive new method needed to be added --- .../java/org/apache/commons/cli/Char.java | 3 + .../org/apache/commons/cli/DefaultParser.java | 3 + .../java/org/apache/commons/cli/Option.java | 68 ++++++++++++++++++- .../apache/commons/cli/DefaultParserTest.java | 65 ++++++++++++++++++ .../org/apache/commons/cli/OptionTest.java | 24 +++++++ 5 files changed, 162 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/apache/commons/cli/Char.java b/src/main/java/org/apache/commons/cli/Char.java index 9b6e5e2ab..a38ece8bf 100644 --- a/src/main/java/org/apache/commons/cli/Char.java +++ b/src/main/java/org/apache/commons/cli/Char.java @@ -40,6 +40,9 @@ final class Char { /** Tab. */ static final char TAB = '\t'; + /** Comma. */ + static final char COMMA = ','; + private Char() { // empty } diff --git a/src/main/java/org/apache/commons/cli/DefaultParser.java b/src/main/java/org/apache/commons/cli/DefaultParser.java index c219113f8..7157ad0b6 100644 --- a/src/main/java/org/apache/commons/cli/DefaultParser.java +++ b/src/main/java/org/apache/commons/cli/DefaultParser.java @@ -609,6 +609,9 @@ private void handleToken(final String token) throws ParseException { skipParsing = true; } else if (currentOption != null && currentOption.acceptsArg() && isArgument(token)) { currentOption.processValue(stripLeadingAndTrailingQuotesDefaultOn(token)); + if (currentOption.areValuesAsList()) { + currentOption = null; + } } else if (token.startsWith("--")) { handleLongOption(token); } else if (token.startsWith("-") && !"-".equals(token)) { diff --git a/src/main/java/org/apache/commons/cli/Option.java b/src/main/java/org/apache/commons/cli/Option.java index 155a70291..acc2f2bc8 100644 --- a/src/main/java/org/apache/commons/cli/Option.java +++ b/src/main/java/org/apache/commons/cli/Option.java @@ -102,6 +102,9 @@ private static Class toType(final Class type) { /** The character that is the value separator. */ private char valueSeparator; + /** multiple values are within a single argument separated by valueSeparator char */ + private boolean valuesAsList; + /** * Constructs a new {@code Builder} with the minimum required parameters for an {@code Option} instance. * @@ -315,7 +318,9 @@ public Builder valueSeparator() { } /** - * The Option will use {@code sep} as a means to separate argument values. + * The Option will use {@code sep} as a means to separate java-property-style argument values + * + * Method is mutually exclusive to listValueSeparator() method. *

* Example: *

@@ -331,6 +336,10 @@ public Builder valueSeparator() { * String propertyValue = line.getOptionValues("D")[1]; // will be "value" * * + * In the above example (unlimited args), followup arguments are interpreted + * to be additional values to this option, needs to be terminated with -- so that + * others options or args can follow. + * * @param valueSeparator The value separator. * @return this builder. */ @@ -339,6 +348,49 @@ public Builder valueSeparator(final char valueSeparator) { return this; } + /** + * The Option will use ',' to invoke listValueSeparator() + * + * @since 1.10.0 + * @return this builder. + */ + public Builder listValueSeparator() { + return listValueSeparator(Char.COMMA); + } + + /** + * defines the separator used to separate a list of values passed in a single arg + * + * Method is mutually exclusive to valueSeparator() method. + *

+ * Example: + *

+ * + *
+         * final Option colors = Option.builder().option("c").longOpt("colors").hasArgs().listValueSeparator('|').build();
+         * final Options options = new Options();
+         * options.addOption(colors);
+         *
+         * final String[] args = {"-c", "red|blue|yellow", "b,c"};
+         * final DefaultParser parser = new DefaultParser();
+         * final CommandLine commandLine = parser.parse(options, args, null, true);
+         * String [] colorValues = commandLine.getOptionValues(colors);
+         * // colorValues[0] will be "red"
+         * // colorValues[1] will be "blue"
+         * // colorValues[2] will be "yellow"
+         * String arguments = commandLine.getArgs()[0]; // will be b,c
+         *
+         * 
+ * + * @since 1.10.0 + * @param listValueSeparator The char to be used to split the argument into mulitple values. + * @return this builder. + */ + public Builder listValueSeparator(final char listValueSeparator) { + this.valueSeparator = listValueSeparator; + this.valuesAsList = true; + return this; + } } /** Empty array. */ @@ -419,6 +471,9 @@ public static Builder builder(final String option) { /** The character that is the value separator. */ private char valueSeparator; + /** multiple values are within a single argument separated by valueSeparator char */ + private boolean valuesAsList; + /** * Private constructor used by the nested Builder class. * @@ -437,6 +492,7 @@ private Option(final Builder builder) { this.type = builder.type; this.valueSeparator = builder.valueSeparator; this.converter = builder.converter; + this.valuesAsList = builder.valuesAsList; } /** @@ -820,6 +876,16 @@ public boolean isRequired() { return required; } + /** + * Tests whether multiple values are expected in a single argument separated by a separation character + * + * @return boolean true when multiple values are expected in a single separated by a separation character + * @since 1.10.0 + */ + public boolean areValuesAsList() { + return valuesAsList; + } + /** * Processes the value. If this Option has a value separator the value will have to be parsed into individual tokens. When n-1 tokens have been processed * and there are more value separators in the value, parsing is ceased and the remaining characters are added as a single token. diff --git a/src/test/java/org/apache/commons/cli/DefaultParserTest.java b/src/test/java/org/apache/commons/cli/DefaultParserTest.java index de52a8600..0e67737d9 100644 --- a/src/test/java/org/apache/commons/cli/DefaultParserTest.java +++ b/src/test/java/org/apache/commons/cli/DefaultParserTest.java @@ -35,6 +35,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; +import org.junit.jupiter.params.provider.ValueSource; class DefaultParserTest extends AbstractParserTestCase { @@ -329,6 +330,70 @@ void legacyStopAtNonOption() throws ParseException { assertTrue(e.getMessage().contains("-d")); } + @Test + void listValueSeparatorTest() throws ParseException { + final Option colors = Option.builder().option("c").longOpt("colors").hasArgs().listValueSeparator('|').build(); + final Options options = new Options(); + options.addOption(colors); + + final String[] args = {"-c", "red|blue|yellow", "b,c"}; + final DefaultParser parser = new DefaultParser(); + final CommandLine commandLine = parser.parse(options, args, null, true); + String [] colorValues = commandLine.getOptionValues(colors); + assertEquals(3, colorValues.length ); + assertEquals("red", colorValues[0]); + assertEquals("blue", colorValues[1]); + assertEquals("yellow", colorValues[2]); + assertEquals("b,c", commandLine.getArgs()[0]); + } + + @ParameterizedTest + @ValueSource(strings = { + "--colors=red,blue,yellow b", + "--colors red,blue,yellow b" , + "-c=red,blue,yellow b" , + "-c red,blue,yellow b" }) + void listValueSeparatorDefaultTest(String args) throws ParseException { + final Option colors = Option.builder().option("c").longOpt("colors").hasArgs().listValueSeparator().build(); + final Options options = new Options(); + options.addOption(colors); + + final DefaultParser parser = new DefaultParser(); + final CommandLine commandLine = parser.parse(options, args.split(" "), null, true); + String [] colorValues = commandLine.getOptionValues(colors); + assertEquals(3, colorValues.length ); + assertEquals("red", colorValues[0]); + assertEquals("blue", colorValues[1]); + assertEquals("yellow", colorValues[2]); + assertEquals("b", commandLine.getArgs()[0]); + } + + @ParameterizedTest + @ValueSource(strings = { + "--colors=red,blue,yellow -f bar b", + "-f bar --colors=red,blue,yellow b", + "b --colors=red,blue,yellow -f bar", + "b --colors=red -c blue --colors=yellow -f bar", + }) + void listValueSeparatorSeriesDoesntMatter(final String args) throws ParseException { + final Option colors = Option.builder().option("c").longOpt("colors").hasArgs().listValueSeparator().build(); + final Option foo = Option.builder().option("f").hasArg().build(); + final Options options = new Options(); + options.addOption(colors); + options.addOption(foo); + + final DefaultParser parser = new DefaultParser(); + final CommandLine commandLine = parser.parse(options, args.split(" "), null, false); + final String [] colorValues = commandLine.getOptionValues(colors); + final String fooValue = commandLine.getOptionValue(foo); + assertEquals(3, colorValues.length ); + assertEquals("red", colorValues[0]); + assertEquals("blue", colorValues[1]); + assertEquals("yellow", colorValues[2]); + assertEquals("bar", fooValue); + assertEquals("b", commandLine.getArgs()[0]); + } + @Override @BeforeEach public void setUp() { diff --git a/src/test/java/org/apache/commons/cli/OptionTest.java b/src/test/java/org/apache/commons/cli/OptionTest.java index ec0cb100a..0781f8314 100644 --- a/src/test/java/org/apache/commons/cli/OptionTest.java +++ b/src/test/java/org/apache/commons/cli/OptionTest.java @@ -344,4 +344,28 @@ void testTypeObject() { option.setType(type); assertEquals(CharSequence.class, option.getType()); } + + @Test + void testDefaultValueSeparator() { + final Option option = Option.builder().option("a").hasArgs().valueSeparator().build(); + assertFalse(option.areValuesAsList()); + assertTrue(option.hasValueSeparator()); + assertEquals('=',option.getValueSeparator()); + } + + @Test + void testDefaultValueAsList() { + final Option option = Option.builder().option("a").hasArgs().listValueSeparator().build(); + assertTrue(option.areValuesAsList()); + assertTrue(option.hasValueSeparator()); + assertEquals(',',option.getValueSeparator()); + } + + @Test + void testValueAsList() { + final Option option = Option.builder().option("a").hasArgs().listValueSeparator('|').build(); + assertTrue(option.areValuesAsList()); + assertTrue(option.hasValueSeparator()); + assertEquals('|',option.getValueSeparator()); + } } From b0b1985abfbc97cb05e8131011b0dce803b72379 Mon Sep 17 00:00:00 2001 From: Joerg Budischewski Date: Sun, 20 Jul 2025 19:56:41 +0200 Subject: [PATCH 2/5] [cli-221] checkstyle fixes, option attribute renamed, documentation fixes --- .../org/apache/commons/cli/DefaultParser.java | 2 +- .../java/org/apache/commons/cli/Option.java | 43 ++++++++++++------- .../apache/commons/cli/DefaultParserTest.java | 18 ++++---- .../org/apache/commons/cli/OptionTest.java | 24 +++++++---- 4 files changed, 53 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/apache/commons/cli/DefaultParser.java b/src/main/java/org/apache/commons/cli/DefaultParser.java index 7157ad0b6..bbd63c7fc 100644 --- a/src/main/java/org/apache/commons/cli/DefaultParser.java +++ b/src/main/java/org/apache/commons/cli/DefaultParser.java @@ -609,7 +609,7 @@ private void handleToken(final String token) throws ParseException { skipParsing = true; } else if (currentOption != null && currentOption.acceptsArg() && isArgument(token)) { currentOption.processValue(stripLeadingAndTrailingQuotesDefaultOn(token)); - if (currentOption.areValuesAsList()) { + if (currentOption.isValueSeparatorUsedForSingleArgument()) { currentOption = null; } } else if (token.startsWith("--")) { diff --git a/src/main/java/org/apache/commons/cli/Option.java b/src/main/java/org/apache/commons/cli/Option.java index acc2f2bc8..a4a326bc8 100644 --- a/src/main/java/org/apache/commons/cli/Option.java +++ b/src/main/java/org/apache/commons/cli/Option.java @@ -103,7 +103,7 @@ private static Class toType(final Class type) { private char valueSeparator; /** multiple values are within a single argument separated by valueSeparator char */ - private boolean valuesAsList; + private boolean valueSeparatorUsedForSingleArgument; /** * Constructs a new {@code Builder} with the minimum required parameters for an {@code Option} instance. @@ -318,7 +318,7 @@ public Builder valueSeparator() { } /** - * The Option will use {@code sep} as a means to separate java-property-style argument values + * The Option will use {@code sep} as a means to separate java-property-style argument values. * * Method is mutually exclusive to listValueSeparator() method. *

@@ -336,7 +336,7 @@ public Builder valueSeparator() { * String propertyValue = line.getOptionValues("D")[1]; // will be "value" * * - * In the above example (unlimited args), followup arguments are interpreted + * In the above example, followup arguments are interpreted * to be additional values to this option, needs to be terminated with -- so that * others options or args can follow. * @@ -359,26 +359,28 @@ public Builder listValueSeparator() { } /** - * defines the separator used to separate a list of values passed in a single arg + * defines the separator used to split a list of values passed in a single argument. + * + * Method is mutually exclusive to valueSeparator() method. In the resulting option, + * isValueSeparatorUsedForSingleArgument() will return true. * - * Method is mutually exclusive to valueSeparator() method. *

* Example: *

* *
-         * final Option colors = Option.builder().option("c").longOpt("colors").hasArgs().listValueSeparator('|').build();
+         * final Option colors = Option.builder().option("c").hasArgs().listValueSeparator('|').build();
          * final Options options = new Options();
          * options.addOption(colors);
          *
          * final String[] args = {"-c", "red|blue|yellow", "b,c"};
          * final DefaultParser parser = new DefaultParser();
          * final CommandLine commandLine = parser.parse(options, args, null, true);
-         * String [] colorValues = commandLine.getOptionValues(colors);
+         * final String [] colorValues = commandLine.getOptionValues(colors);
          * // colorValues[0] will be "red"
          * // colorValues[1] will be "blue"
          * // colorValues[2] will be "yellow"
-         * String arguments = commandLine.getArgs()[0]; // will be b,c
+         * final String arguments = commandLine.getArgs()[0]; // will be b,c
          *
          * 
* @@ -388,7 +390,7 @@ public Builder listValueSeparator() { */ public Builder listValueSeparator(final char listValueSeparator) { this.valueSeparator = listValueSeparator; - this.valuesAsList = true; + this.valueSeparatorUsedForSingleArgument = true; return this; } } @@ -472,7 +474,7 @@ public static Builder builder(final String option) { private char valueSeparator; /** multiple values are within a single argument separated by valueSeparator char */ - private boolean valuesAsList; + private boolean valueSeparatorUsedForSingleArgument; /** * Private constructor used by the nested Builder class. @@ -492,7 +494,7 @@ private Option(final Builder builder) { this.type = builder.type; this.valueSeparator = builder.valueSeparator; this.converter = builder.converter; - this.valuesAsList = builder.valuesAsList; + this.valueSeparatorUsedForSingleArgument = builder.valueSeparatorUsedForSingleArgument; } /** @@ -877,13 +879,24 @@ public boolean isRequired() { } /** - * Tests whether multiple values are expected in a single argument separated by a separation character + * Tests whether multiple values are expected in a single argument split by a separation character + * + * @return boolean true when the builder's listValueSeparator() method was used. Multiple values are expected in a single argument and + * are split by a separation character. + * @since 1.10.0 + */ + public boolean isValueSeparatorUsedForSingleArgument() { + return valueSeparatorUsedForSingleArgument; + } + + /** + * Set this to true to use the valueSeparator only on a single argument. See also builder's listValueSeparator() method. * - * @return boolean true when multiple values are expected in a single separated by a separation character + * @param valueSeparatorUsedForSingleArgument the new value for this property * @since 1.10.0 */ - public boolean areValuesAsList() { - return valuesAsList; + public void setValueSeparatorUsedForSingleArgument(final boolean valueSeparatorUsedForSingleArgument) { + this.valueSeparatorUsedForSingleArgument = valueSeparatorUsedForSingleArgument; } /** diff --git a/src/test/java/org/apache/commons/cli/DefaultParserTest.java b/src/test/java/org/apache/commons/cli/DefaultParserTest.java index 0e67737d9..86a6763b4 100644 --- a/src/test/java/org/apache/commons/cli/DefaultParserTest.java +++ b/src/test/java/org/apache/commons/cli/DefaultParserTest.java @@ -339,8 +339,8 @@ void listValueSeparatorTest() throws ParseException { final String[] args = {"-c", "red|blue|yellow", "b,c"}; final DefaultParser parser = new DefaultParser(); final CommandLine commandLine = parser.parse(options, args, null, true); - String [] colorValues = commandLine.getOptionValues(colors); - assertEquals(3, colorValues.length ); + final String [] colorValues = commandLine.getOptionValues(colors); + assertEquals(3, colorValues.length); assertEquals("red", colorValues[0]); assertEquals("blue", colorValues[1]); assertEquals("yellow", colorValues[2]); @@ -350,18 +350,18 @@ void listValueSeparatorTest() throws ParseException { @ParameterizedTest @ValueSource(strings = { "--colors=red,blue,yellow b", - "--colors red,blue,yellow b" , - "-c=red,blue,yellow b" , - "-c red,blue,yellow b" }) - void listValueSeparatorDefaultTest(String args) throws ParseException { + "--colors red,blue,yellow b", + "-c=red,blue,yellow b", + "-c red,blue,yellow b"}) + void listValueSeparatorDefaultTest(final String args) throws ParseException { final Option colors = Option.builder().option("c").longOpt("colors").hasArgs().listValueSeparator().build(); final Options options = new Options(); options.addOption(colors); final DefaultParser parser = new DefaultParser(); final CommandLine commandLine = parser.parse(options, args.split(" "), null, true); - String [] colorValues = commandLine.getOptionValues(colors); - assertEquals(3, colorValues.length ); + final String [] colorValues = commandLine.getOptionValues(colors); + assertEquals(3, colorValues.length); assertEquals("red", colorValues[0]); assertEquals("blue", colorValues[1]); assertEquals("yellow", colorValues[2]); @@ -386,7 +386,7 @@ void listValueSeparatorSeriesDoesntMatter(final String args) throws ParseExcepti final CommandLine commandLine = parser.parse(options, args.split(" "), null, false); final String [] colorValues = commandLine.getOptionValues(colors); final String fooValue = commandLine.getOptionValue(foo); - assertEquals(3, colorValues.length ); + assertEquals(3, colorValues.length); assertEquals("red", colorValues[0]); assertEquals("blue", colorValues[1]); assertEquals("yellow", colorValues[2]); diff --git a/src/test/java/org/apache/commons/cli/OptionTest.java b/src/test/java/org/apache/commons/cli/OptionTest.java index 0781f8314..779194d84 100644 --- a/src/test/java/org/apache/commons/cli/OptionTest.java +++ b/src/test/java/org/apache/commons/cli/OptionTest.java @@ -348,24 +348,30 @@ void testTypeObject() { @Test void testDefaultValueSeparator() { final Option option = Option.builder().option("a").hasArgs().valueSeparator().build(); - assertFalse(option.areValuesAsList()); + assertFalse(option.isValueSeparatorUsedForSingleArgument()); assertTrue(option.hasValueSeparator()); - assertEquals('=',option.getValueSeparator()); + assertEquals('=', option.getValueSeparator()); } @Test - void testDefaultValueAsList() { + void testDefaultListValueSeparator() { final Option option = Option.builder().option("a").hasArgs().listValueSeparator().build(); - assertTrue(option.areValuesAsList()); + assertTrue(option.isValueSeparatorUsedForSingleArgument()); assertTrue(option.hasValueSeparator()); - assertEquals(',',option.getValueSeparator()); + assertEquals(',', option.getValueSeparator()); } - + @Test - void testValueAsList() { + void testListValueSeparator() { final Option option = Option.builder().option("a").hasArgs().listValueSeparator('|').build(); - assertTrue(option.areValuesAsList()); + assertTrue(option.isValueSeparatorUsedForSingleArgument()); + assertTrue(option.hasValueSeparator()); + assertEquals('|', option.getValueSeparator()); + + option.setValueSeparatorUsedForSingleArgument(false); + assertFalse(option.isValueSeparatorUsedForSingleArgument()); assertTrue(option.hasValueSeparator()); - assertEquals('|',option.getValueSeparator()); + assertEquals('|', option.getValueSeparator()); + } } From ceacf036b08a7d477e15807492639ecfdd22c89f Mon Sep 17 00:00:00 2001 From: Joerg Budischewski Date: Wed, 30 Jul 2025 23:18:25 +0200 Subject: [PATCH 3/5] [cli-221] resolved merge conflict from master --- .github/pull_request_template.md | 6 +- .github/workflows/codeql-analysis.yml | 6 +- .github/workflows/scorecards-analysis.yml | 2 +- CONTRIBUTING.md | 4 +- README.md | 2 +- RELEASE-NOTES.txt | 62 ++ pom.xml | 2 +- src/changes/changes.xml | 13 +- .../commons/cli/AlreadySelectedException.java | 16 +- .../org/apache/commons/cli/DefaultParser.java | 92 +- .../org/apache/commons/cli/HelpFormatter.java | 10 +- .../commons/cli/MissingOptionException.java | 17 +- .../java/org/apache/commons/cli/Option.java | 42 +- .../org/apache/commons/cli/OptionBuilder.java | 2 +- .../org/apache/commons/cli/OptionGroup.java | 20 +- .../apache/commons/cli/OptionValidator.java | 2 +- .../java/org/apache/commons/cli/Options.java | 98 ++- .../java/org/apache/commons/cli/Parser.java | 16 +- .../commons/cli/PatternOptionBuilder.java | 4 +- .../cli/help/AbstractHelpFormatter.java | 10 +- src/main/javadoc/overview.html | 791 +++++++++++++++++- src/site/site.xml | 10 +- src/site/xdoc/download_cli.xml | 8 +- src/site/xdoc/introduction.xml | 102 --- src/site/xdoc/properties.xml | 122 --- src/site/xdoc/usage.xml | 613 -------------- .../commons/cli/AbstractParserTestCase.java | 60 +- .../cli/AlreadySelectedExceptionTest.java | 8 +- .../apache/commons/cli/CommandLineTest.java | 66 +- .../apache/commons/cli/DefaultParserTest.java | 198 +++-- .../apache/commons/cli/HelpFormatterTest.java | 91 +- .../cli/MissingOptionExceptionTest.java | 51 ++ .../apache/commons/cli/OptionBuilderTest.java | 4 +- .../apache/commons/cli/OptionGroupTest.java | 60 +- .../org/apache/commons/cli/OptionTest.java | 73 +- .../org/apache/commons/cli/OptionsTest.java | 107 ++- .../org/apache/commons/cli/SolrCliTest.java | 122 ++- .../commons/cli/SolrCreateToolTest.java | 84 +- .../org/apache/commons/cli/ValueTest.java | 2 +- .../apache/commons/cli/bug/BugCLI252Test.java | 4 +- .../apache/commons/cli/bug/BugCLI265Test.java | 8 +- .../apache/commons/cli/bug/BugCLI266Test.java | 71 +- .../apache/commons/cli/bug/BugCLI312Test.java | 8 +- .../apache/commons/cli/bug/BugCLI325Test.java | 7 +- .../org/apache/commons/cli/bug/BugsTest.java | 8 +- .../commons/cli/help/HelpFormatterTest.java | 110 +-- .../commons/cli/help/OptionFormatterTest.java | 67 +- 47 files changed, 1705 insertions(+), 1576 deletions(-) delete mode 100644 src/site/xdoc/introduction.xml delete mode 100644 src/site/xdoc/properties.xml delete mode 100644 src/site/xdoc/usage.xml create mode 100644 src/test/java/org/apache/commons/cli/MissingOptionExceptionTest.java diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e17973cb0..7578b4da0 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -22,7 +22,9 @@ Thanks for your contribution to [Apache Commons](https://commons.apache.org/)! Y Before you push a pull request, review this list: - [ ] Read the [contribution guidelines](CONTRIBUTING.md) for this project. +- [ ] Read the [ASF Generative Tooling Guidance](https://www.apache.org/legal/generative-tooling.html) if you use Artificial Intelligence (AI). +- [ ] I used AI to create any part of, or all of, this pull request. - [ ] Run a successful build using the default [Maven](https://maven.apache.org/) goal with `mvn`; that's `mvn` on the command line by itself. -- [ ] Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible but is a best-practice. +- [ ] Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible, but it is a best-practice. - [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why. -- [ ] Each commit in the pull request should have a meaningful subject line and body. Note that commits might be squashed by a maintainer on merge. +- [ ] Each commit in the pull request should have a meaningful subject line and body. Note that a maintainer may squash commits during the merge process. diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 5bb1f901d..7400fb888 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -57,7 +57,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # 3.29.2 + uses: github/codeql-action/init@4e828ff8d448a8a6e532957b1811f387a63867e8 # 3.29.4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -68,7 +68,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@181d5eefc20863364f96762470ba6f862bdef56b # 3.29.2 + uses: github/codeql-action/autobuild@4e828ff8d448a8a6e532957b1811f387a63867e8 # 3.29.4 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -82,4 +82,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # 3.29.2 + uses: github/codeql-action/analyze@4e828ff8d448a8a6e532957b1811f387a63867e8 # 3.29.4 diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index c52dbd34e..325206c18 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -64,6 +64,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@181d5eefc20863364f96762470ba6f862bdef56b # 3.29.2 + uses: github/codeql-action/upload-sarif@4e828ff8d448a8a6e532957b1811f387a63867e8 # 3.29.4 with: sarif_file: results.sarif diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 927ab3f6f..e4440b2a2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -61,11 +61,11 @@ Making Changes + Create a _topic branch_ for your isolated work. * Usually you should base your branch from the `master` branch. - * A good topic branch name can be the JIRA bug ID plus a keyword, for example, `CLI-123-InputStream`. + * A good topic branch name can be the JIRA bug ID plus a keyword, e.g. `CLI-123-InputStream`. * If you have submitted multiple JIRA issues, try to maintain separate branches and pull requests. + Make commits of logical units. * Make sure your commit messages are meaningful and in the proper format. Your commit message should contain the key of the JIRA issue. - * For example, `[CLI-123] Close input stream earlier` + * For example, `[CLI-123] Close input stream sooner` + Respect the original code style: + Only use spaces for indentation; you can check for unnecessary whitespace with `git diff` before committing. + Create minimal diffs - disable _On Save_ actions like _Reformat Source Code_ or _Organize Imports_. If you feel the source code should be reformatted create a separate PR for this change first. diff --git a/README.md b/README.md index 2c6c46fbb..7c56440fc 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ There are some guidelines which will make applying PRs easier for us: + Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change. + Provide JUnit tests for your changes and make sure your changes don't break any existing tests by running `mvn`. + Before you pushing a PR, run `mvn` (by itself), this runs the default goal, which contains all build checks. -+ To see the code coverage report, regardless of coverage failures, run `mvn clean site -Dcommons.jacoco.haltOnFailure=false` ++ To see the code coverage report, regardless of coverage failures, run `mvn clean site -Dcommons.jacoco.haltOnFailure=false -Pjacoco` If you plan to contribute on a regular basis, please consider filing a [contributor license agreement](https://www.apache.org/licenses/#clas). You can learn more about contributing via GitHub in our [contribution guidelines](CONTRIBUTING.md). diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 48cc3f083..332b23281 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,11 +1,73 @@ Apache Commons CLI 1.10.0 Release Notes --------------------------------------- +The Apache Commons CLI team is pleased to announce the release of Apache Commons CLI 1.10.0. + Apache Commons CLI provides a simple API for presenting, processing, and validating a Command Line Interface. This is a feature and maintenance release. Java 8 or later is required. +New Features +------------ + +* CLI-339: Help formatter extension in the new package #314. Thanks to Claude Warren, Gary Gregory. +* CommandLine.Builder implements Supplier. Thanks to Gary Gregory. +* DefaultParser.Builder implements Supplier. Thanks to Gary Gregory. +* CLI-340: Add CommandLine.getParsedOptionValues() #334. Thanks to Claude Warren, Gary Gregory. +* CLI-333: org.apache.commons.cli.Option.Builder implements Supplier