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

Add validation for readmes #7088

Merged
merged 22 commits into from
Jul 24, 2020
Merged
Show file tree
Hide file tree
Changes from 15 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
3 changes: 3 additions & 0 deletions .azure-pipelines/templates/run-validations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ steps:
- script: ddev validate metadata
displayName: 'Validate metric data'

- script: ddev validate readmes
displayName: 'Validate README files'

- script: ddev validate saved-views
displayName: 'Validate saved views data'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .imports import imports
from .manifest import manifest
from .metadata import metadata
from .readmes import readmes
from .saved_views import saved_views
from .service_checks import service_checks

Expand All @@ -26,6 +27,7 @@
imports,
manifest,
metadata,
readmes,
saved_views,
service_checks,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# (C) Datadog, Inc. 2020-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
import re
from os import path

import click

from ...utils import complete_valid_checks, get_root, get_valid_integrations, read_readme_file
from ..console import CONTEXT_SETTINGS, abort, echo_failure, echo_info, echo_success

IMAGE_EXTENSIONS = {".png", ".jpg"}


@click.command(context_settings=CONTEXT_SETTINGS, short_help='Validate README.md files')
@click.pass_context
@click.argument('integration', autocompletion=complete_valid_checks, required=False)
def readmes(ctx, integration):
"""Validates README files

If `check` is specified, only the check will be validated,
otherwise all README files in the repo will be.
"""

repo = ctx.obj['repo_name']

errors = False
integrations = []

if integration:
integrations = [integration]
else:
integrations = sorted(get_valid_integrations())

for integration in integrations:
has_overview = False
has_setup = False

lines = read_readme_file(integration)
for line_no, line in lines:

if "## Overview" == line.strip():
has_overview = True

if "## Setup" == line.strip():
has_setup = True

for ext in IMAGE_EXTENSIONS:
AlexandreYang marked this conversation as resolved.
Show resolved Hide resolved
AlexandreYang marked this conversation as resolved.
Show resolved Hide resolved
if ext in line:
AlexandreYang marked this conversation as resolved.
Show resolved Hide resolved
IMAGE_REGEX = (
rf".*https:\/\/raw\.githubusercontent\.com\/DataDog\/"
rf"{re.escape(repo)}\/master\/({re.escape(integration)}\/images\/.*.{ext}).*"
)

match = re.match(IMAGE_REGEX, line)
if not match:
errors = True
echo_failure(f"{integration} readme file does not have a valid image file on line {line_no}")
Copy link
Collaborator

@nmuesch nmuesch Jul 24, 2020

Choose a reason for hiding this comment

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

One thing I noticed is that the other validations print the integration name once when there is an error, then print each error message on a newline with a slight indent, to group errors per integration
Example in the manifest validations - https://github.com/DataDog/integrations-core/blob/master/datadog_checks_dev/datadog_checks/dev/tooling/commands/validate/manifest.py#L289-L301

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 like that format! I updated the PR

echo_info(
f"This image path must be in the form: "
f"https://raw.githubusercontent.com/DataDog/{repo}/master/{integration}/images/<IMAGE_NAME>"
)

rel_path = match.groups()[0]
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think need to abort above or put this in an else, otherwise we never see the failure message above if match doesn't exist.

Copy link
Collaborator

Choose a reason for hiding this comment

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

EDIT: sorry you do see the error message above, but it gets drowned out a bit by a stacktrace

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch, I updated to break if there's a failure!

if rel_path:
file_path = path.join(get_root(), rel_path)
if not path.exists(file_path):
errors = True
echo_failure(f"{integration} image: {rel_path} is linked in its readme but does not exist")

if not (has_overview and has_setup):
errors = True
echo_failure(f"{integration} readme file does not have an overview and setup section")
sarah-witt marked this conversation as resolved.
Show resolved Hide resolved

if errors:
abort()

echo_success("All READMEs are valid!")
9 changes: 7 additions & 2 deletions datadog_checks_dev/datadog_checks/dev/tooling/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import requests
import semver

from ..utils import dir_exists, file_exists, read_file, write_file
from ..utils import dir_exists, file_exists, read_file, read_file_lines, write_file
from .config import load_config
from .constants import NOT_CHECKS, REPO_CHOICES, REPO_OPTIONS_MAP, VERSION_BUMP, get_root, set_root
from .git import get_latest_tag
Expand Down Expand Up @@ -366,6 +366,11 @@ def read_metadata_rows(metadata_file):
yield line_no, row


def read_readme_file(check_name):
for line_no, line in enumerate(read_file_lines(get_readme_file(check_name))):
yield line_no, line


def read_version_file(check_name):
return read_file(get_version_file(check_name))

Expand Down Expand Up @@ -396,7 +401,7 @@ def load_manifest(check_name):

def load_saved_views(path):
"""
Load the manifest file into a dictionary
Load the saved view file into a dictionary
"""
if file_exists(path):
return json.loads(read_file(path).strip())
Expand Down