Skip to content

Commit

Permalink
Add Sectioners with implementations for Travis, Github, and Gitlab
Browse files Browse the repository at this point in the history
  • Loading branch information
cognifloyd committed Nov 17, 2020
1 parent 9bbb934 commit dd420e5
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 3 deletions.
19 changes: 16 additions & 3 deletions src/molecule/command/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import molecule.scenarios
from molecule import config, logger, util
from molecule.console import get_sectioner

LOG = logger.get_logger(__name__)
MOLECULE_GLOB = os.environ.get("MOLECULE_GLOB", "molecule/*/molecule.yml")
Expand All @@ -39,12 +40,24 @@

def section_logger(func: Callable) -> Callable:
"""Wrap effective execution of a method."""
sectioner = get_sectioner()

def wrapper(*args, **kwargs):
scenario = args[1].scenario.name
subcommand = args[2]
section_id = f"{scenario}.{subcommand}"

sectioner.print_header(
section_id,
title=f"Molecule {scenario} > {subcommand}",
title_with_markers=f"[section_title]Molecule[/] [scenario]{scenario}[/] > [action]{subcommand}[/]",
)
args[0].print_info()
rt = func(*args, **kwargs)
# section close code goes here
return rt
try:
return func(*args, **kwargs)
finally:
# uses finally to ensure this prints even on error.
sectioner.print_footer(section_id)

return wrapper

Expand Down
148 changes: 148 additions & 0 deletions src/molecule/console.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Console and terminal utilities."""
import os
import sys
import time
from abc import ABC, abstractmethod
from typing import Any

from rich.style import Style
Expand All @@ -14,6 +16,7 @@
"danger": "bold red",
"scenario": "green",
"action": "green",
"section_title": "bold cyan",
"logging.level.notset": Style(dim=True),
"logging.level.debug": Style(color="white", dim=True),
"logging.level.info": Style(color="blue"),
Expand Down Expand Up @@ -63,3 +66,148 @@ def should_do_markup() -> bool:
console = ConsoleEx(
force_terminal=should_do_markup(), theme=theme, record=True, redirect=True
)


class OutputSectioner(ABC):
@classmethod
@abstractmethod
def can_handle(cls):
""""Investigate environment to see if section markers are supported."""

@abstractmethod
def print_header(
self, section_id: str, title: str = None, title_with_markers: str = None
):
""""Print the pre-section header, optionally with a (marked up) title."""

@abstractmethod
def print_footer(self, section_id: str):
""""Print the post-section footer."""


class NullSectioner(OutputSectioner):
@classmethod
def can_handle(cls):
return True

def print_header(
self, section_id: str, title: str = None, title_with_markers: str = None
):
pass

def print_footer(self, section_id: str):
pass


class GithubActionsGroups(OutputSectioner):
@classmethod
def can_handle(cls):
return os.getenv("CI") and os.getenv("GITHUB_ACTIONS")

def print_header(
self, section_id: str, title: str = None, title_with_markers: str = None
):
if title is None and title_with_markers is None:
section_title = ""
else:
section_title = title_with_markers or f"[section_title]{title}[/]"
console.print(
"::group::",
section_title,
sep="",
markup=True,
emoji=False,
highlight=False,
)

def print_footer(self, section_id: str):
console.print("::endgroup::", markup=True, emoji=False, highlight=False)


class GitlabPipelinesSections(OutputSectioner):
# GitLab requres:
# - \r (carriage return)
# - \e[0K (clear line ANSI escape code. We use \033 for the \e escape char)
clear_line = "\r\033[0K"

@classmethod
def can_handle(cls):
return os.getenv("CI") and os.getenv("GITLAB_CI")

def print_header(
self, section_id: str, title: str = None, title_with_markers: str = None
):
# must be one color for the whole line or gitlab sets odd widths to each word.
# so, ignore title_with_markers
section_title = f"[section_title]{title}[/]"
console.print(
f"section_start:{int(time.time())}:{section_id}",
end=self.clear_line,
markup=False,
emoji=False,
highlight=False,
)
console.print(
section_title,
end="\n",
markup=True,
emoji=False,
highlight=False,
)

def print_footer(self, section_id: str):
console.print(
f"section_end:{int(time.time())}:{section_id}",
end=f"{self.clear_line}\n",
markup=False,
emoji=False,
highlight=False,
)


class TravisCIsections(OutputSectioner):
@classmethod
def can_handle():
return os.getenv("CI") and os.getenv("TRAVIS")

def print_header(
section_id: str, title: str = None, title_with_markers: str = None
):
if title is None and title_with_markers is None:
section_title = ""
else:
section_title = title_with_markers or f"[section_title]{title}[/]"
console.print(
f"travis_section:start:{section_id}",
section_title,
sep="",
markup=True,
emoji=False,
highlight=False,
)

def print_footer(section_id: str):
console.print(
f"travis_section:end:{section_id}",
markup=False,
emoji=False,
highlight=False,
)


sectioners = [
GithubActionsGroups,
GitlabPipelinesSections,
TravisCIsections,
NullSectioner, # must be last.
]
_sectioner = None


def get_sectioner():
if _sectioner is not None:
return _sectioner
for sectioner in secitoners:
if sectioner.can_handle():
_sectioner = sectioner()
break

0 comments on commit dd420e5

Please sign in to comment.