diff --git a/HACKING.rst b/HACKING.rst index 0deb2481..fa0cc018 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -373,6 +373,11 @@ OpenStack Licensing # License for the specific language governing permissions and limitations # under the License. + Alternately also check for the + `SPDX license header `__ for Apache 2.0:: + + # SPDX-License-Identifier: Apache-2.0 + - [H104] Files with no code shouldn't contain any license header nor comments, and must be left completely empty. diff --git a/hacking/checks/comments.py b/hacking/checks/comments.py index 96eaa8fa..e923e1fb 100644 --- a/hacking/checks/comments.py +++ b/hacking/checks/comments.py @@ -65,6 +65,8 @@ def hacking_has_license(physical_line, filename, lines, line_number): # header if 0 <= line.find('Licensed under the Apache License') < 10: license_found = True + if 0 <= line.find('SPDX-License-Identifier:') < 10: + license_found = True if not license_found: return (0, "H102: Apache 2.0 license header not found") @@ -86,8 +88,9 @@ def hacking_has_correct_license(physical_line, filename, lines, line_number): column = line.find('Licensed under the Apache License') if (0 < column < 10 and not _check_for_exact_apache(idx, lines)): - return (column, "H103: Header does not match Apache 2.0 " - "License notice") + if (line.find('SPDX-License-Identifier: Apache-2.0') <= 0): + return (column, "H103: Header does not match Apache 2.0 " + "License notice") EMPTY_LINE_RE = re.compile("^\s*(#.*|$)") diff --git a/hacking/tests/checks/test_comments.py b/hacking/tests/checks/test_comments.py index 5e2d7113..f837ee24 100644 --- a/hacking/tests/checks/test_comments.py +++ b/hacking/tests/checks/test_comments.py @@ -18,6 +18,145 @@ from hacking import tests class CoreTestCase(tests.TestCase): + def test_H102_none(self): + """Verify that the H102 check finds an SPDX header""" + self.assertEqual( + (0, 'H102: Apache 2.0 license header not found'), + comments.hacking_has_license( + None, + None, + [ + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + ], + 1, + ), + ) + + def test_H102_full(self): + """Verify that the H102 check finds an SPDX header""" + self.assertIsNone(comments.hacking_has_license( + None, + None, + [ + '# foo', + '# Licensed under the Apache License, Version 2.0', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + ], + 1, + )) + + def test_H102_SPDX(self): + """Verify that the H102 check finds an SPDX header""" + self.assertIsNone(comments.hacking_has_license( + None, + None, + [ + '# foo', + '# SPDX-License-Identifier: Apache-2.0', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + ], + 1, + )) + + def test_H103_full_fail(self): + """Verify that the H103 check finds an SPDX header""" + self.assertEqual( + (2, 'H103: Header does not match Apache 2.0 License notice'), + comments.hacking_has_correct_license( + None, + None, + [ + '# foo', + '# Licensed under the Apache License, Version 2.0', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + ], + 1, + ), + ) + + def test_H103_full(self): + """Verify that the H103 check finds an SPDX header""" + self.assertIsNone(comments.hacking_has_correct_license( + None, + None, + [ + """ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + """ # noqa + ], + 1, + )) + + def test_H103_SPDX(self): + """Verify that the H103 check finds an SPDX header""" + self.assertIsNone(comments.hacking_has_correct_license( + None, + None, + [ + '# foo', + '# SPDX-License-Identifier: Apache-2.0', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + '# foo', + '# bar', + ], + 1, + )) + def test_H104_regex(self): """Verify that the H104 regex matches correct lines.""" self.assertTrue(comments.hacking_has_only_comments(