Skip to content

Commit

Permalink
Merge pull request #331 from valory-xyz/fix/copyright_scaffold
Browse files Browse the repository at this point in the history
fix: scaffold copyright header
  • Loading branch information
DavidMinarsch authored Sep 20, 2022
2 parents e1ca87d + ee96c28 commit e1a85d6
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 12 deletions.
47 changes: 47 additions & 0 deletions aea/cli/scaffold.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
#
# ------------------------------------------------------------------------------
"""Implementation of the 'aea scaffold' subcommand."""

import os
import re
import shutil
from datetime import datetime
from pathlib import Path
from typing import cast

Expand Down Expand Up @@ -56,6 +58,50 @@
from aea.helpers.ipfs.base import IPFSHashOnly


COPYRIGHT_HEADER = """\
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright {year} {author}
#
# 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.
#
# ------------------------------------------------------------------------------
"""


def update_copyright_headers(ctx: Context, path: Path) -> None:
"""Update copyright headers"""

# this allows for arbitrary authors
year, author = datetime.now().year, ctx.agent_config.author
top = "\n".join(COPYRIGHT_HEADER.split("\n")[:3])
bottom = "\n".join(COPYRIGHT_HEADER.split("\n")[-15:])
new_copyright_header = COPYRIGHT_HEADER.format(year=year, author=author)

for file in path.rglob("**/*.py"):
content = file.read_text()
i, j = content.find(top), content.find(bottom)
if i == j == -1: # no copyright header present yet
file.write_text(f"{new_copyright_header}\n{content}")
elif i != j != -1: # copyright header detected
old_copyright_header = content[i : j + len(bottom)]
content = content.replace(old_copyright_header, new_copyright_header)
file.write_text(content)
else:
raise ValueError(f"Copyright pattern detection failed: {content}")


@click.group()
@click.option(
"--to-local-registry",
Expand Down Expand Up @@ -186,6 +232,7 @@ def scaffold_item(ctx: Context, item_type: str, item_name: str) -> None:
src = Path(os.path.join(AEA_DIR, item_type_plural, "scaffold"))
logger.debug(f"Copying {item_type} modules. src={src} dst={dest}")
shutil.copytree(src, dest)
update_copyright_headers(ctx, dest)

new_public_id = PublicId(author_name, item_name, DEFAULT_VERSION)

Expand Down
16 changes: 16 additions & 0 deletions tests/test_cli/test_scaffold/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2022 Valory AG
# Copyright 2018-2019 Fetch.AI Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -18,3 +19,18 @@
# ------------------------------------------------------------------------------

"""This test module contains the tests for the `aea scaffold` sub-command."""

from pathlib import Path


def files_outside_copyright_are_identical(*files: Path) -> bool:
"""Check files are identical outside copyright author / year"""

def remove_copyright_author_year_lines(s: str) -> str:
"""Filter copyright author and year for file comparison"""
lines, prefix = s.splitlines(), "# Copyright"
return "/n".join(line for line in lines if not line.startswith(prefix))

lines = (f.read_text() for f in files)
cleaned_lines = set(map(remove_copyright_author_year_lines, lines))
return len(set(cleaned_lines)) == 1
22 changes: 22 additions & 0 deletions tests/test_cli/test_scaffold/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
# ------------------------------------------------------------------------------
"""This test module contains the tests for the `aea scaffold connection` sub-command."""
import json
import logging
import os
import re
import shutil
import tempfile
import unittest.mock
from datetime import datetime
from pathlib import Path

import jsonschema
Expand All @@ -39,6 +42,7 @@
CONFIGURATION_SCHEMA_DIR,
CONNECTION_CONFIGURATION_SCHEMA,
CliRunner,
DEFAULT_AUTHOR,
ROOT_DIR,
)

Expand Down Expand Up @@ -91,6 +95,24 @@ def test_exit_code_equal_to_0(self):
"""Test that the exit code is equal to 0."""
assert self.result.exit_code == 0

def test_copyright_header_year_is_current(self):
"""Test that the year in copyright header is updated to current"""

incorrect_files, files_left_to_inspect = [], 2
current_year = datetime.now().year
path_pattern = f"**/{self.resource_name}/*.py"
for file in (Path(self.t) / self.agent_name).rglob(path_pattern):
content = file.read_text()
years_in_header = re.findall(r"Copyright.*([0-9]{4})", content)
has_correct_year = years_in_header == [str(current_year)]
has_correct_author = DEFAULT_AUTHOR in content
if not has_correct_year or not has_correct_author:
logging.error(content[:200])
incorrect_files.append(file)
files_left_to_inspect -= 1
assert not "\n".join(map(str, incorrect_files))
assert not files_left_to_inspect

def test_resource_folder_contains_module_connection(self):
"""Test that the resource folder contains scaffold connection.py module."""
p = Path(
Expand Down
11 changes: 6 additions & 5 deletions tests/test_cli/test_scaffold/test_protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#
# ------------------------------------------------------------------------------
"""This test module contains the tests for the `aea scaffold protocol` sub-command."""
import filecmp

import json
import os
import shutil
Expand All @@ -44,6 +44,7 @@
PROTOCOL_CONFIGURATION_SCHEMA,
ROOT_DIR,
)
from tests.test_cli.test_scaffold import files_outside_copyright_are_identical


class TestScaffoldProtocol:
Expand Down Expand Up @@ -100,15 +101,15 @@ def test_resource_folder_contains_module_message(self):
"""Test that the resource folder contains scaffold message.py module."""
p = Path(self.t, self.agent_name, "protocols", self.resource_name, "message.py")
original = Path(AEA_DIR, "protocols", "scaffold", "message.py")
assert filecmp.cmp(p, original)
assert files_outside_copyright_are_identical(p, original)

def test_resource_folder_contains_module_protocol(self):
"""Test that the resource folder contains scaffold protocol.py module."""
p = Path(
self.t, self.agent_name, "protocols", self.resource_name, "serialization.py"
)
original = Path(AEA_DIR, "protocols", "scaffold", "serialization.py")
assert filecmp.cmp(p, original)
assert files_outside_copyright_are_identical(p, original)

def test_resource_folder_contains_configuration_file(self):
"""Test that the resource folder contains a good configuration file."""
Expand Down Expand Up @@ -189,7 +190,7 @@ def test_resource_folder_contains_module_message(self):
self.t, "packages", AUTHOR, "protocols", self.resource_name, "message.py"
)
original = Path(AEA_DIR, "protocols", "scaffold", "message.py")
assert filecmp.cmp(p, original)
assert files_outside_copyright_are_identical(p, original)

def test_resource_folder_contains_module_protocol(self):
"""Test that the resource folder contains scaffold protocol.py module."""
Expand All @@ -202,7 +203,7 @@ def test_resource_folder_contains_module_protocol(self):
"serialization.py",
)
original = Path(AEA_DIR, "protocols", "scaffold", "serialization.py")
assert filecmp.cmp(p, original)
assert files_outside_copyright_are_identical(p, original)

def test_resource_folder_contains_configuration_file(self):
"""Test that the resource folder contains a good configuration file."""
Expand Down
14 changes: 7 additions & 7 deletions tests/test_cli/test_scaffold/test_skills.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

"""This test module contains the tests for the `aea scaffold skill` sub-command."""

import filecmp
import json
import os
import re
Expand All @@ -46,6 +45,7 @@
ROOT_DIR,
SKILL_CONFIGURATION_SCHEMA,
)
from tests.test_cli.test_scaffold import files_outside_copyright_are_identical


class TestScaffoldSkill:
Expand Down Expand Up @@ -99,19 +99,19 @@ def test_resource_folder_contains_module_handlers(self):
"""Test that the resource folder contains scaffold handlers.py module."""
p = Path(self.t, self.agent_name, "skills", self.resource_name, "handlers.py")
original = Path(AEA_DIR, "skills", "scaffold", "handlers.py")
assert filecmp.cmp(p, original)
assert files_outside_copyright_are_identical(p, original)

def test_resource_folder_contains_module_behaviours(self):
"""Test that the resource folder contains scaffold behaviours.py module."""
p = Path(self.t, self.agent_name, "skills", self.resource_name, "behaviours.py")
original = Path(AEA_DIR, "skills", "scaffold", "behaviours.py")
assert filecmp.cmp(p, original)
assert files_outside_copyright_are_identical(p, original)

def test_resource_folder_contains_module_model(self):
"""Test that the resource folder contains scaffold my_model.py module."""
p = Path(self.t, self.agent_name, "skills", self.resource_name, "my_model.py")
original = Path(AEA_DIR, "skills", "scaffold", "my_model.py")
assert filecmp.cmp(p, original)
assert files_outside_copyright_are_identical(p, original)

def test_resource_folder_contains_configuration_file(self):
"""Test that the resource folder contains a good configuration file."""
Expand Down Expand Up @@ -201,23 +201,23 @@ def test_resource_folder_contains_module_handlers(self):
self.t, "packages", AUTHOR, "skills", self.resource_name, "handlers.py"
)
original = Path(AEA_DIR, "skills", "scaffold", "handlers.py")
assert filecmp.cmp(p, original)
assert files_outside_copyright_are_identical(p, original)

def test_resource_folder_contains_module_behaviours(self):
"""Test that the resource folder contains scaffold behaviours.py module."""
p = Path(
self.t, "packages", AUTHOR, "skills", self.resource_name, "behaviours.py"
)
original = Path(AEA_DIR, "skills", "scaffold", "behaviours.py")
assert filecmp.cmp(p, original)
assert files_outside_copyright_are_identical(p, original)

def test_resource_folder_contains_module_model(self):
"""Test that the resource folder contains scaffold my_model.py module."""
p = Path(
self.t, "packages", AUTHOR, "skills", self.resource_name, "my_model.py"
)
original = Path(AEA_DIR, "skills", "scaffold", "my_model.py")
assert filecmp.cmp(p, original)
assert files_outside_copyright_are_identical(p, original)

def test_resource_folder_contains_configuration_file(self):
"""Test that the resource folder contains a good configuration file."""
Expand Down

0 comments on commit e1a85d6

Please sign in to comment.