Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip the checks if the news file was changed #337

Merged
merged 21 commits into from
Feb 13, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,20 @@ Furthermore, you can add your own fragment types using:
directory = "deprecation"
name = "Deprecations"
showcontent = true


Automatic pull request checks
-----------------------------

To check if a feature branch is missing a news fragment, run::

towncrier check

By default this compares the current branch against ``origin/master``. You can use ``--compare-with`` if the trunk is named differently::

towncrier check --compare-with origin/main

The check succeeds if at least one of the following is true:

- The current branch adds at least one news fragment
- The current branch changes the news file (e.g. the PR is a new release)
5 changes: 5 additions & 0 deletions src/towncrier/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ def __main(comparewith, directory, config):
click.echo("{}. {}".format(n, change))
click.echo("----")

news_file = os.path.normpath(os.path.join(base_directory, config["filename"]))
if news_file in files:
click.echo("Checks SKIPPED: news file changes detected.")
sys.exit(0)

if config.get("directory"):
fragment_base_directory = os.path.abspath(config["directory"])
fragment_directory = None
Expand Down
5 changes: 5 additions & 0 deletions src/towncrier/newsfragments/337.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Make the check subcommand succeed for branches that change the news file

This should enable the ``check`` subcommand to be used as a CI lint step and
not fail when a pull request only modifies the configured news file (i.e. when
the news file is being assembled for the next release).
73 changes: 73 additions & 0 deletions src/towncrier/test/test_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# See LICENSE for details.

import os
import os.path
import sys

from twisted.trial.unittest import TestCase
Expand Down Expand Up @@ -30,6 +31,29 @@ def create_project(pyproject_path):
call(["git", "checkout", "-b", "otherbranch"])


def commit(message):
call(["git", "add", "."])
call(["git", "commit", "-m", message])


def write(path, contents):
dir = os.path.dirname(path)
if dir:
try:
os.makedirs(dir)
except OSError:
pass
with open(path, "w") as f:
f.write(contents)


def initial_commit():
call(["git", "init", "--initial-branch=main"])
call(["git", "config", "user.name", "user"])
call(["git", "config", "user.email", "[email protected]"])
commit("Initial Commit")


class TestChecker(TestCase):
maxDiff = None

Expand Down Expand Up @@ -148,3 +172,52 @@ def test_none_stdout_encoding_works(self):

self.assertEqual(0, proc.returncode)
self.assertEqual(b"", stderr)

def test_first_release(self):
runner = CliRunner()

with runner.isolated_filesystem():
# Arrange
write("towncrier.toml", "[tool.towncrier]")
write("newsfragments/.gitignore", "!.gitignore")
initial_commit()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like duplicate code between tests.
Why not reuse the existing create_project

Suggested change
# Arrange
write("towncrier.toml", "[tool.towncrier]")
write("newsfragments/.gitignore", "!.gitignore")
initial_commit()
create_project('towncrier.toml')

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dislike create_project().

  • It encapsulates a poorly scoped amount of code. The semantics are unclear. It does too many unrelated things. Changing it like you did in Make check subcommand detect if only configured news file has changed #296 affects every test that uses it which is risky.
  • It is inflexible: you either use it or you don't. I prefer my approach: a set of (mostly) orthogonal building blocks that every test can use to arrange things precisely the way that particular test needs to.
  • It is a little to implicit for my taste. I actually like that every file the test creates is explicitly named in the test itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing it like you did in #296 affects every test that uses it which is risky.

Just to be clear: I'm not criticizing you, I'm criticizing a specific decision you made because I think I know how to solve that specific problem better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hexagonrecursion don't worry :) If you think that some code is not ok. please say it loud.
I will not take it as an offense... I know that I am capable of writing bad code :)

Your comments are valid.

Regarding the risky change. As long as the tests are not failing, I think that any change should be done if we thing that it improves the readability and usability.
We should be confident that the test suite is solid and don't code with fear :)

If you think that create_project is bad pattern, it's best to add a docstring comment to it and let other developers know what is the current best practice.

But I think that all test helpers should have short docstrings describing when and why they should be used :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that I am capable of writing bad code

Same here. I also prefer to err on the side of not offending anybody.

If you think that create_project is bad pattern, it's best to add a docstring comment to it and let other developers know what is the current best practice.

If you are onboard with my argument I'll submit a followup PR to refactor the rest of the file and delete create_project()

But I think that all test helpers should have short docstrings describing when and why they should be used :)

👍


write("newsfragments/123.feature", "Foo the bar")
commit("Foo the bar")

call(["git", "checkout", "-b", "next-resease"])
call(["towncrier", "--yes", "--version", "1.0"])
commit("Prepare a release")

# Act
result = runner.invoke(_main, ["--compare-with", "main"])

# Assert
self.assertEqual(0, result.exit_code, (result, result.output))
self.assertIn("Checks SKIPPED: news file changes detected", result.output)

def test_second_release(self):
runner = CliRunner()

with runner.isolated_filesystem():
# Arrange
write("towncrier.toml", "[tool.towncrier]")
write("newsfragments/.gitignore", "!.gitignore")
Copy link
Member

@adiroiban adiroiban Apr 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this ignore here?
I guess that this is a replacement for write("newsfragments/123.feature", "Foo the bar")
For me, writing an explicit news fragment is easier to read and understand what is going on here.

initial_commit()

call(["towncrier", "--yes", "--version", "1.0"])
commit("First release")

write("newsfragments/123.feature", "Foo the bar")
commit("Foo the bar")

call(["git", "checkout", "-b", "next-resease"])
call(["towncrier", "--yes", "--version", "2.0"])
commit("Second release")

# Act
result = runner.invoke(_main, ["--compare-with", "main"])

# Assert
self.assertEqual(0, result.exit_code, (result, result.output))
self.assertIn("Checks SKIPPED: news file changes detected", result.output)