Skip to content

Commit

Permalink
Merge pull request #46 from fair-software/config
Browse files Browse the repository at this point in the history
Config
  • Loading branch information
jspaaks committed Dec 7, 2020
2 parents d82eb0f + 4a97526 commit e687dc4
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 157 deletions.
57 changes: 27 additions & 30 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -144,26 +144,26 @@ Which then shows something like:
GitHub or GitLab repository at URL.
Options:
-b, --branch TEXT Which git branch to use.
-c, --config-file PATH Name of the configuration file to control
howfairis'es behavior. The configuration
file needs to be on the remote, and takes
into account the value of --branch and
--path. Default: .howfairis.yml
-d, --show-default-config Show default configuration and exit.
-i, --include-comments [yes|no]
When looking for badges, include sections of
the README that have been commented out
using <!-- and -->. Default: no
-p, --path TEXT Relative path (on the remote). Use this if
you want howfairis to look for a README in a
subdirectory.
-t, --show-trace [yes|no] Show full traceback on errors. Default: no
-v, --version Show version and exit.
-h, --help Show this message and exit.
-b, --branch TEXT Which git branch to use.
-c, --config-file PATH Name of the configuration file to control
howfairis'es behavior. The configuration file
needs to be present on the local system and
can include a relative path.
-d, --show-default-config Show default configuration and exit.
-p, --path TEXT Relative path (on the remote). Use this if
you want howfairis to look for a README and a
configuration file in a subdirectory.
-r, --remote-config-file TEXT Name of the configuration file to control
howfairis'es behavior. The configuration file
needs to be on the remote, and takes into
account the value of --branch and --path.
Default: .howfairis.yml
-t, --show-trace [yes|no] Show full traceback on errors. Default: no
-v, --version Show version and exit.
-h, --help Show this message and exit.
Configuration file
^^^^^^^^^^^^^^^^^^
Expand All @@ -176,23 +176,20 @@ The configuration file should follow the voluptuous_ schema laid out in schema.p
.. code:: python
schema = {
Optional("force"): Any({
Optional("repository"): Any(bool, None),
Optional("license"): Any(bool, None),
Optional("registry"): Any(bool, None),
Optional("citation"): Any(bool, None),
Optional("checklist"): Any(bool, None),
}, None),
Optional("force_repository"): Any(bool, None),
Optional("force_license"): Any(bool, None),
Optional("force_registry"): Any(bool, None),
Optional("force_citation"): Any(bool, None),
Optional("force_checklist"): Any(bool, None),
Optional("include_comments"): Any(bool, None)
}
For example, the following is a valid configuration file document:

.. code:: yaml
force:
registry: true # It is good practice to add an explanation
# of why you chose to set the state manually
force_registry: true # It is good practice to add an explanation
# of why you chose to set the state manually
The manual override will be reflected in the output, as follows:

Expand Down
46 changes: 29 additions & 17 deletions clitests/script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,37 @@ howfairis --help
howfairis --version
howfairis --show-default-config

DURATION=10
DURATION=20

# github
howfairis https://github.com/fair-software/badge-test && sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p force/00100 && sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p force/10110 && sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p force/11110 && sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p force/11111 && sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p force/uu1uu && sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p force/u && sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p include_comments && sleep $DURATION
howfairis https://github.com/fair-software/badge-test
sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p force/00100
sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p force/10110
sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p force/11110
sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p force/11111
sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p force/uu1uu
sleep $DURATION
howfairis https://github.com/fair-software/badge-test -p include_comments
sleep $DURATION


# gitlab
howfairis https://gitlab.com/jspaaks/badge-test && sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p force/00100 && sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p force/10110 && sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p force/11110 && sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p force/11111 && sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p force/uu1uu && sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p force/u && sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p include_comments && sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test
sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p force/00100
sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p force/10110
sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p force/11110
sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p force/11111
sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p force/uu1uu
sleep $DURATION
howfairis https://gitlab.com/jspaaks/badge-test -p include_comments
sleep $DURATION
7 changes: 4 additions & 3 deletions howfairis/Checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@


class Checker(RepositoryMixin, LicenseMixin, RegistryMixin, CitationMixin, ChecklistMixin):
def __init__(self, config=None):
def __init__(self, config, repo):
super().__init__()
self.compliance = None
self.config = config
self.readme = None
self.repo = repo

self._get_readme()

Expand All @@ -41,7 +42,7 @@ def remove_comments(text):
return re.sub(r"<!--.*?-->", "", text, flags=re.DOTALL)

for readme_filename in ["README.rst", "README.md"]:
raw_url = self.config.repo.raw_url_format_string.format(readme_filename)
raw_url = self.repo.raw_url_format_string.format(readme_filename)
try:
response = requests.get(raw_url)
# If the response was successful, no Exception will be raised
Expand All @@ -56,7 +57,7 @@ def remove_comments(text):
else:
readme_fmt = None

if self.config.yamldata.get("include_comments") is True:
if self.config.merged.get("include_comments") is True:
text = response.text
else:
text = remove_comments(response.text)
Expand Down
103 changes: 62 additions & 41 deletions howfairis/Config.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,94 @@
import os
import requests
from ruamel.yaml import YAML
from voluptuous.error import Invalid
from voluptuous.error import MultipleInvalid
from howfairis.schema import validate_against_schema


class Config:
def __init__(self, repo, config_filename=None, include_comments=None):
self.repo = repo
self.has_user_input = config_filename is not None
self.yamldata = None

self._load_default_config()
self._load_repo_config(config_filename)
self._load_cli_config(include_comments)

def _load_cli_config(self, include_comments):
if include_comments == "yes":
d = dict(include_comments=True)
elif include_comments == "no":
d = dict(include_comments=False)
else:
d = dict()
self.yamldata.update(d)
return self

def _load_default_config(self):
def __init__(self, repo, config_filename=None, ignore_remote_config=False):
self.default = Config._load_default_config()
self.repo = Config._load_repo_config(repo, ignore_remote_config)
self.user = Config._load_user_config(config_filename)

@staticmethod
def _load_default_config():
pkg_root = os.path.dirname(__file__)
config_filename = os.path.join(pkg_root, "data", ".howfairis.yml")
with open(config_filename, "rt") as f:
text = f.read()
newdata = YAML(typ="safe").load(text)
if newdata is None:
newdata = dict()
default_config = YAML(typ="safe").load(text)
if default_config is None:
default_config = dict()
try:
validate_against_schema(newdata)
except Exception as e:
raise Exception("Default configuration file should follow the schema.") from e
self.yamldata = newdata
return self
validate_against_schema(default_config)
except (Invalid, MultipleInvalid):
print("Default configuration file should follow the schema for it to be considered.")
return dict()
return default_config

def _load_repo_config(self, config_filename):
if self.repo is None:
return self
@staticmethod
def _load_repo_config(repo, ignore_remote_config):
if repo is None:
return dict()

if config_filename is None:
if ignore_remote_config is True:
return dict()

if repo.config_file is None:
config_filename = ".howfairis.yml"
else:
config_filename = repo.config_file

raw_url = self.repo.raw_url_format_string.format(config_filename)
raw_url = repo.raw_url_format_string.format(config_filename)
try:
response = requests.get(raw_url)
# If the response was successful, no Exception will be raised
response.raise_for_status()
print("Using the configuration file {0}".format(raw_url))
except requests.HTTPError as e:
if self.has_user_input:
if repo.config_file is not None:
raise Exception("Could not find the configuration file {0}".format(raw_url)) from e
return self
return dict()

try:
newdata = YAML(typ="safe").load(response.text)
repo_config = YAML(typ="safe").load(response.text)
except Exception as e:
raise Exception("Problem loading YAML configuration from file {0}".format(raw_url)) from e

try:
validate_against_schema(newdata)
except Exception as e:
raise Exception("Configuration file should follow the schema.") from e
validate_against_schema(repo_config)
except (Invalid, MultipleInvalid):
print("Repository's configuration file should follow the schema for it to be considered.")
return dict()

return repo_config

@staticmethod
def _load_user_config(config_filename):
if config_filename is None:
return dict()

self.yamldata.update(newdata)
p = os.path.join(os.getcwd(), config_filename)
if not os.path.exists(p):
raise FileNotFoundError("{0} doesn't exist.".format(config_filename))

with open(p, "rt") as f:
text = f.read()
user_config = YAML(typ="safe").load(text)
if user_config is None:
user_config = dict()
try:
validate_against_schema(user_config)
except Exception as e:
raise Exception("User configuration file should follow the schema.") from e
return user_config

return self
@property
def merged(self):
m = dict()
m.update(self.default)
m.update(self.repo)
m.update(self.user)
return m
9 changes: 5 additions & 4 deletions howfairis/Repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@


class Repo:
def __init__(self, url, branch=None, path=None):
self.url = url
self.branch = "master" if branch is None else branch
self.path = "" if path is None else "/" + path.strip("/")
def __init__(self, url, branch=None, path=None, config_file=None):
self.api = None
self.branch = "master" if branch is None else branch
self.config_file = config_file
self.owner = None
self.path = "" if path is None else "/" + path.strip("/")
self.platform = None
self.raw_url_format_string = None
self.repo = None
self.url = url

self._deconstruct_url()

Expand Down
42 changes: 29 additions & 13 deletions howfairis/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,23 +52,27 @@ def check_badge(compliance, readme=None):
help="Which git branch to use.")
@click.option("-c", "--config-file", default=None, type=click.Path(),
help="Name of the configuration file to control howfairis'es behavior. The configuration " +
"file needs to be on the remote, and takes into account the value of " +
"--branch and --path. Default: .howfairis.yml")
"file needs to be present on the local system and can include a relative path.")
@click.option("-d", "--show-default-config", default=False, is_flag=True,
help="Show default configuration and exit.")
@click.option("-i", "--include-comments", default=None, type=click.Choice(["yes", "no"], case_sensitive=True),
help="When looking for badges, include sections of the README that " +
"have been commented out using <!-- and -->. Default: no")
@click.option("-i", "--ignore-remote-config", default=False, is_flag=True,
help="Ignore any configuration files on the remote.")
@click.option("-p", "--path", default=None, type=click.STRING,
help="Relative path (on the remote). Use this if you want howfairis to look for a " +
"README in a subdirectory.")
"README and a configuration file in a subdirectory.")
@click.option("-r", "--remote-config-file", default=None, type=click.STRING,
help="Name of the configuration file to control howfairis'es behavior. The configuration " +
"file needs to be on the remote, and takes into account the value of " +
"--branch and --path. Default: .howfairis.yml")
@click.option("-t", "--show-trace", default=None, type=click.Choice(["yes", "no"], case_sensitive=True),
help="Show full traceback on errors. Default: no")
@click.option("-v", "--version", default=False, is_flag=True,
help="Show version and exit.")
@click.argument("url", required=False)
def cli(url=None, branch=None, config_file=None, include_comments=None,
path=None, show_trace=False, version=False, show_default_config=False):
def cli(url=None, branch=None, config_file=None, remote_config_file=None, path=None,
show_trace=False, version=False, ignore_remote_config=False, show_default_config=False):
# pylint: disable=too-many-locals

"""Determine compliance with recommendations from fair-software.eu for the GitHub or GitLab repository at URL."""

if version is True:
Expand All @@ -89,19 +93,31 @@ def cli(url=None, branch=None, config_file=None, include_comments=None,
init_terminal_colors()
assert url is not None, "Expected URL to not be emtpy."
print("Checking compliance with fair-software.eu...")

if url is not None:
print("url: " + url)
if config_file is not None:
print("config_file: " + config_file)

if branch is not None:
print("branch: " + branch)

if path is not None:
print("path: " + path)

repo = Repo(url, branch, path)
config = Config(repo, config_file, include_comments)
if ignore_remote_config is True:
print("Ignoring any configuration files on the remote.")
assert remote_config_file is None, "When ignoring any configuration files on the remote, you" + \
" should not set a remote configuration filename."
else:
if remote_config_file is not None:
print("Remote configuration filename: " + remote_config_file)

if config_file is not None:
print("Local configuration file: " + config_file)

repo = Repo(url, branch, path, remote_config_file)
config = Config(repo, config_file, ignore_remote_config)

checker = Checker(config)
checker = Checker(config, repo)
checker.check_five_recommendations()
check_badge(compliance=checker.compliance, readme=checker.readme)

Expand Down
Loading

0 comments on commit e687dc4

Please sign in to comment.