diff --git a/src/towncrier/_builder.py b/src/towncrier/_builder.py index bedb4d66..41437ab4 100644 --- a/src/towncrier/_builder.py +++ b/src/towncrier/_builder.py @@ -47,11 +47,22 @@ def find_fragments(base_directory, sections, fragment_directory, definitions): for basename in files: parts = basename.split(u".") + counter = 0 if len(parts) == 1: continue else: ticket, category = parts[:2] + # If there is a number after the category then use it as a counter, + # otherwise ignore it. + # This means 1.feature.1 and 1.feature do not conflict but + # 1.feature.rst and 1.feature do. + if len(parts) > 2: + try: + counter = int(parts[2]) + except ValueError: + pass + if category not in definitions: continue @@ -59,13 +70,14 @@ def find_fragments(base_directory, sections, fragment_directory, definitions): fragment_filenames.append(full_filename) with open(full_filename, "rb") as f: data = f.read().decode("utf8", "replace") - if (ticket, category) in file_content: + + if (ticket, category, counter) in file_content: raise ValueError( "multiple files for {}.{} in {}".format( ticket, category, section_dir ) ) - file_content[ticket, category] = data + file_content[ticket, category, counter] = data content[key] = file_content @@ -93,14 +105,14 @@ def split_fragments(fragments, definitions): for section_name, section_fragments in fragments.items(): section = {} - for (ticket, category), content in section_fragments.items(): + for (ticket, category, counter), content in section_fragments.items(): content = indent(content.strip(), u" ")[2:] if definitions[category]["showcontent"] is False: content = u"" - texts = section.get(category, {}) + texts = section.get(category, OrderedDict()) if texts.get(content): texts[content] = sorted(texts[content] + [ticket]) diff --git a/src/towncrier/newsfragments/119.feature b/src/towncrier/newsfragments/119.feature new file mode 100644 index 00000000..85ba82f0 --- /dev/null +++ b/src/towncrier/newsfragments/119.feature @@ -0,0 +1,3 @@ +Add support for multiple fragements per issue/type pair. This extends the +naming pattern of the fragments to `issuenumber.type(.counter)` where counter +is an optional integer. diff --git a/src/towncrier/test/test_format.py b/src/towncrier/test/test_format.py index e2d04d6a..3b95f972 100644 --- a/src/towncrier/test/test_format.py +++ b/src/towncrier/test/test_format.py @@ -17,15 +17,15 @@ def test_split(self): fragments = { "": { - ("1", "misc"): u"", - ("baz", "misc"): u"", - ("2", "feature"): u"Foo added.", - ("5", "feature"): u"Foo added. \n", - ("6", "bugfix"): u"Foo added.", + ("1", "misc", 0): u"", + ("baz", "misc", 0): u"", + ("2", "feature", 0): u"Foo added.", + ("5", "feature", 0): u"Foo added. \n", + ("6", "bugfix", 0): u"Foo added.", }, "Web": { - ("3", "bugfix"): u"Web fixed. ", - ("4", "feature"): u"Foo added.", + ("3", "bugfix", 0): u"Web fixed. ", + ("4", "feature", 0): u"Foo added.", }, } @@ -65,19 +65,19 @@ def test_basic(self): { # asciibetical sorting will do 1, 142, 9 # we want 1, 9, 142 instead - ("142", "misc"): u"", - ("1", "misc"): u"", - ("9", "misc"): u"", - ("bar", "misc"): u"", - ("4", "feature"): u"Stuff!", - ("2", "feature"): u"Foo added.", - ("72", "feature"): u"Foo added.", - ("9", "feature"): u"Foo added.", - ("baz", "feature"): u"Fun!", + ("142", "misc", 0): u"", + ("1", "misc", 0): u"", + ("9", "misc", 0): u"", + ("bar", "misc", 0): u"", + ("4", "feature", 0): u"Stuff!", + ("2", "feature", 0): u"Foo added.", + ("72", "feature", 0): u"Foo added.", + ("9", "feature", 0): u"Foo added.", + ("baz", "feature", 0): u"Fun!", }, ), ("Names", {}), - ("Web", {("3", "bugfix"): u"Web fixed."}), + ("Web", {("3", "bugfix", 0): u"Web fixed."}), ] ) @@ -180,10 +180,10 @@ def test_issue_format(self): "": { # asciibetical sorting will do 1, 142, 9 # we want 1, 9, 142 instead - ("142", "misc"): u"", - ("1", "misc"): u"", - ("9", "misc"): u"", - ("bar", "misc"): u"", + ("142", "misc", 0): u"", + ("1", "misc", 0): u"", + ("9", "misc", 0): u"", + ("bar", "misc", 0): u"", } } @@ -220,11 +220,12 @@ def test_line_wrapping(self): ( "1", "feature", + 0, ): u""" asdf asdf asdf asdf looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong newsfragment. """, # NOQA - ("2", "feature"): u"https://google.com/q=?" + u"-" * 100, - ("3", "feature"): u"a " * 80, + ("2", "feature", 0): u"https://google.com/q=?" + u"-" * 100, + ("3", "feature", 0): u"a " * 80, } } @@ -270,11 +271,12 @@ def test_line_wrapping_disabled(self): ( "1", "feature", + 0 ): u""" asdf asdf asdf asdf looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong newsfragment. """, # NOQA - ("2", "feature"): u"https://google.com/q=?" + u"-" * 100, - ("3", "feature"): u"a " * 80, + ("2", "feature", 0): u"https://google.com/q=?" + u"-" * 100, + ("3", "feature", 0): u"a " * 80, } } diff --git a/src/towncrier/test/test_write.py b/src/towncrier/test/test_write.py index b6842df3..372bf0a1 100644 --- a/src/towncrier/test/test_write.py +++ b/src/towncrier/test/test_write.py @@ -19,16 +19,19 @@ def test_append_at_top(self): [ ( "", - { - ("142", "misc"): u"", - ("1", "misc"): u"", - ("4", "feature"): u"Stuff!", - ("2", "feature"): u"Foo added.", - ("72", "feature"): u"Foo added.", - }, + OrderedDict( + [ + (("142", "misc", 0), u""), + (("1", "misc", 0), u""), + (("4", "feature", 0), u"Stuff!"), + (("4", "feature", 1), u"Second Stuff!"), + (("2", "feature", 0), u"Foo added."), + (("72", "feature", 0), u"Foo added."), + ] + ), ), ("Names", {}), - ("Web", {("3", "bugfix"): u"Web fixed."}), + ("Web", {("3", "bugfix", 0): u"Web fixed."}), ] ) @@ -48,6 +51,7 @@ def test_append_at_top(self): - Foo added. (#2, #72) - Stuff! (#4) +- Second Stuff! (#4) Misc @@ -111,16 +115,16 @@ def test_append_at_top_with_hint(self): ( "", { - ("142", "misc"): u"", - ("1", "misc"): u"", - ("4", "feature"): u"Stuff!", - ("2", "feature"): u"Foo added.", - ("72", "feature"): u"Foo added.", - ("99", "feature"): u"Foo! " * 100, + ("142", "misc", 0): u"", + ("1", "misc", 0): u"", + ("4", "feature", 0): u"Stuff!", + ("2", "feature", 0): u"Foo added.", + ("72", "feature", 0): u"Foo added.", + ("99", "feature", 0): u"Foo! " * 100, }, ), ("Names", {}), - ("Web", {("3", "bugfix"): u"Web fixed."}), + ("Web", {("3", "bugfix", 0): u"Web fixed."}), ] )