diff --git a/assets/favicon.png b/assets/favicon.png new file mode 100644 index 0000000..1a8885a Binary files /dev/null and b/assets/favicon.png differ diff --git a/metrics b/metrics index 8ee838b..27ab4fa 100755 --- a/metrics +++ b/metrics @@ -1,145 +1,154 @@ #!/usr/bin/env python3 # Copyright (C) 2020 Simon Quigley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import argparse import logging as log import sqlite3 from jinja2 import Template from modules.jenkins import JenkinsModule from os import path +from shutil import copytree, rmtree ENABLED_MODULES = [JenkinsModule] def sqlite_run(command, db, return_output=False): """Run the given SQLite command on our db command must be a command that SQLite can run db must be a valid path to a db, or it's done in memory """ conn = sqlite3.connect(db) c = conn.cursor() for cmd in command: log.debug("Executing: %s" % cmd) c.execute(cmd) conn.commit() # Make sure we return an output if requested try: if return_output: rows = c.fetchall() return rows except Exception as e: print(e) finally: conn.close() def summary(): """Reading summary_page, generate a summary page using the averages summary_page should be a dict, with keys being the human-readable module name and the value being another dict, which has averages for each day. Example: {"foo": {1: (100, 200, 300)}} Special-casing is done right in the template file, as different modules are going to have different averages. """ # Open the template file as a Jinja2 Template t_path = path.join("templates", "index.html") with open(t_path) as templatef: template = "" for text in templatef.readlines(): template += text template = Template(template) # Render the template with the values from summary_page log.debug("summary_page: " + str(summary_page)) template = template.render(page=summary_page) # Write it back to the output file # We don't have to worry about creating the output dir, since the # module-specific template rendering should already do this for us # # FIXME: Writing to/from files is done in several places, maybe centralize # the code in its own "internal" module? with open(path.join("output", "index.html"), "w+") as f: f.write(template) def main(module): """Given a specific module, set it up and insert recent values""" # Initialize the module module = module() # Stage the setup commands to be ran and run them if not args.no_modify_db: run = [module.sqlite_setup(), module.sqlite_add()] log.debug(sqlite_run(run, db=args.db_location)) # This is going to be a dict of tuples, with the key being the day and # the value being a tuple with the averages _averages = {} # Pull some useful data and have the module render a template # The output is in MODULENAME_DAYday.html # This generates a report for each of the given day windows for day in (1, 7, 30, 90, 180): # Fetch the data and log to debug run = [module.sqlite_time_range(days=day)] data = sqlite_run(run, db=args.db_location, return_output=True) log.debug(data) # Render the template, which also returns the average values _averages[day] = module.render_template(day, data) # Put the values from _averages on the summary page summary_page[module.name] = _averages if __name__ == "__main__": # Parse CLI arguments parser = argparse.ArgumentParser() parser.add_argument("--db-location", type=str, default=":memory:", help="Specify the location for the SQLite database") parser.add_argument("--log", type=str, default="WARNING", help="Default logging level") parser.add_argument("--no-modify-db", action="store_true", help="Don't insert any data into the DB, just read") args = parser.parse_args() # Ensure the logging level is set properly num_level = getattr(log, args.log.upper(), None) if not isinstance(num_level, int): raise ValueError("Invalid log level: %s" % args.log) # Fully configure the logger log.basicConfig(format="%(asctime)s\t%(levelname)s\t%(message)s", level=num_level) # Initialize a dict to store data for the summary page summary_page = {} for module in ENABLED_MODULES: log.info("Working on %s..." % module.__name__) main(module) # Render the summary page summary() + + # Copy the assets + # FIXME: clunky and racey + try: + copytree("assets", "output/assets") + except FileExistsError: + rmtree("output/assets") + copytree("assets", "output/assets") diff --git a/templates/index.html b/templates/index.html index 2cdeca8..db4f22a 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,47 +1,51 @@ + + + + Summary for Lubuntu Project Metrics

Summary for Lubuntu Project Metrics

Jenkins Data

{% for day in page.Jenkins %} {% for avg in page.Jenkins[day] %} {% endfor %} {% endfor %}
Time (days) Average Non-passing Average Failing Average Total Graph for Data
{{ day }}{{ avg }}Here
diff --git a/templates/jenkins.html b/templates/jenkins.html index c39d9a8..c9fdd3b 100644 --- a/templates/jenkins.html +++ b/templates/jenkins.html @@ -1,89 +1,93 @@ + + + + Jenkins data for the past {{ days }} day{{ "s" if days > 1 }}

Jenkins data for the past {{ days }} day(s)


Jenkins data for the past {{ days }} day{{ "s" if days > 1 }}

Average number of failing jobs: {{ average.failing }}

Average number of non-passing jobs: {{ average.nonpassing }}

Average number of total jobs: {{ average.total }}

Back to summary page