Skip to content

Commit

Permalink
tiny tweaks to cci interfaces
Browse files Browse the repository at this point in the history
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
  • Loading branch information
vsoch committed Jun 25, 2021
1 parent 51983c5 commit 6f477e5
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 23 deletions.
10 changes: 9 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,15 @@ inputs:
update:
description: "Update an existing Contributor CI interface."
required: false


update_random:
description: Only update a random selection of N extractors. This is intended for large projects.
required: false

update_cfa:
description: "Find and generate CFAs for new repos."
required: false

config_file:
description: "The contributor-ci.yaml file with organization metadata."
required: true
Expand Down
2 changes: 1 addition & 1 deletion contributor_ci/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def get_parser():
ui.add_argument(
"--cfa",
dest="include_cfa",
help="include contributor friendliness assessments for generate.",
help="include contributor friendliness assessments for generate or update.",
default=False,
action="store_true",
)
Expand Down
32 changes: 29 additions & 3 deletions contributor_ci/client/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,26 @@
__license__ = "MPL 2.0"

from contributor_ci.logger import logger
import random
import os


def parse_option(options, option):
"""
Parse an option into a name and value
"""
# Currently supported options
if not option.startswith("random"):
logger.exit("%s is not a supported option." % option)
if ":" in option:
name, value = option.split(":", 1)
else:
name = option
value = random.choice(range(2, 4))
options[name] = int(value)
return options


def main(args, parser, extra, subparser):

from contributor_ci.main import Client
Expand All @@ -16,13 +33,22 @@ def main(args, parser, extra, subparser):

# By default, generate or update in PWD if nothing provided
dirname = os.getcwd()
if args.ui_command:
dirname = args.ui_command.pop(0)

# We only accept a directory name for generate
if command == "generate":
if args.ui_command:
dirname = args.ui_command.pop(0)
cli.ui_generate(dirname, include_cfa=args.include_cfa)

elif command == "update":
cli.ui_update(dirname)

# If we have another argument
options = {}
while args.ui_command:
option = args.ui_command.pop(0)
options = parse_option(options, option)

# Assume directory is PWD
cli.ui_update(dirname=".", options=options, include_cfa=args.include_cfa)
else:
logger.exit("%s is not a known user interface command." % command)
32 changes: 27 additions & 5 deletions contributor_ci/main/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import os
import shutil
import sys
import random


class Client:
Expand Down Expand Up @@ -90,12 +91,13 @@ def ui_generate(self, dirname, include_cfa=False):
# Copy the entire contents of the site folder here
site = os.path.join(utils.get_installdir(), "site")
utils.copytree(site, dirname)
self.ui_update(dirname)
self.ui_update(dirname, include_cfa=include_cfa)

def ui_update(self, dirname):
def ui_update(self, dirname, options=None, include_cfa=False):
"""
Update an existing user interface.
"""
options = options or {}
dirname = os.path.abspath(dirname)

# We've already checked for a config file!
Expand All @@ -106,7 +108,12 @@ def ui_update(self, dirname):

# Data is expected to be in cci
self._out_dir = os.path.join(dirname, "cci")
self.extract_all()

# Do we want to extract a random number?
if "random" in options:
self.extract_random(options["random"])
else:
self.extract_all()

# CFA files will be here if they exist
outdir = os.path.join(dirname, "_cfa")
Expand All @@ -117,8 +124,9 @@ def ui_update(self, dirname):
return

# Provide a different data directory
cfa = CFA(data_dir=self._out_dir)
cfa.run_all(outdir)
if include_cfa:
cfa = CFA(data_dir=self._out_dir)
cfa.run_all(outdir)

def cfa(self, repo, save=False):
"""
Expand Down Expand Up @@ -194,6 +202,20 @@ def extract(self, method):
if not ran:
logger.info("Extractor runs are up to date.")

def extract_random(self, number):
"""
Extract a random selection.
"""
names = list(self.extractors.keys())
for _ in range(number):

# Cut out early if we run out!
if not names:
return
choice = random.choice(names)
names.pop(names.index(choice))
self.extract(choice)

def __repr__(self):
return str(self)

Expand Down
1 change: 1 addition & 0 deletions contributor_ci/site/.github/workflows/update-ui.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
update: true
update_random: 4
7 changes: 7 additions & 0 deletions contributor_ci/site/_layouts/api.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{"data": [{% for cfa in site.cfa %}{% assign array = cfa.content | jsonify | split: "\n" %}{% assign number_checked = 0 %}{% for item in array %}{% if item contains "checked" %}{% assign number_checked = number_checked | plus:1 %}{% endif %}{% endfor %}
{
"id": "{{ cfa.title | replace:'/','-' }}",
"checked": {{ number_checked }},
"url": "{{ site.url }}{{ site.baseurl }}{{ cfa.url }}"
}{% if forloop.last %}{% else %},{% endif %}
{% endfor %}]}
96 changes: 96 additions & 0 deletions contributor_ci/site/_layouts/cfa.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,104 @@
layout: page
---

<a target="_blank" style="position:absolute; top:10px; padding-left:400px; padding-bottom:10px" href="https://github.com/{{ page.title }}/">{{ page.title }}</a>

<a style="position:absolute; top:10px; padding-left:10px; padding-bottom:10px" href="{{ site.baseurl }}/cfa/">< back</a>
<a style="position:absolute; top:10px; padding-left:200px; padding-bottom:10px" href="{{ site.baseurl }}/cfa/">About the CFA</a>

<div id="app">

<br />

<svg id="svg" class="svg" xmlns="http://www.w3.org/2000/svg" width="200" height="35" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200.58699 34.999">
<path d="M 0,0 H 146.01893 V 35 H 0 Z" fill="#333" style="color:#000" stroke-width="1.46415269" />
<text y="22" x="65.093933" font-size="13" font-family="ITCGothicBold.ttf" text-anchor="middle" fill="#ffffff">software checklist</text>
<path id="svg-color" d="m 146.01893,0 h 55.57 v 35 h -55.57 z" />
<text id="svg-score" font-size="13" y="22" x="173.22897" font-family="ITCGothicBold.ttf" text-anchor="middle" fill="#ffffff">0</text>

{{ content }}

<h2>Badge</h2>

Want to include this badge with your project?

<blockquote class="markdown" style="display:none; overflow:hidden">
</blockquote>


</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {

// Current user score
score: 0,
points: 0,
total: 0,
title: "{{ page.title }}",
color: null,

// Must be same length as number of points
colors: ["#B43C3C","#BB473E","#BF5340","#BF6240","#BF6F40","#BF7540","#BF7D40","#BF8440","#BF8E40","#BF9740","#BF9F40","#BFAA40","#BFB540","#BFBB40","#AEBF40","#9FBF40","#80BF40","#59BF40"]
},
// The view will trigger these methods on click

methods: {

populateScore: function() {
// Get all of the unique ids
var checked = document.querySelectorAll('input.task-list-item-checkbox[type="checkbox"]:checked')

// Don't continue if no points checked!
if (checked.length == 0) {
$(".markdown").text("This project does not have enough criteria checked to create a badge.");
$(".markdown").show();
return
}

console.log(this.colors);
console.log(this.points)

// Need to scale points from 1-18
var color_index = parseInt((this.points / this.total) * 18)

// Prepare badge images
var badgeColor = this.colors[color_index];
this.color = badgeColor;
var badgeScore = Math.round(this.score) + "%25"
var badgeUrl = "https://img.shields.io/badge/software%20checklist-" + badgeScore + "-" + badgeColor.replace("#", "");

// Prepare badge link (summary page with badge and ids
var badgeLink = "{{ site.url }}{{ site.baseurl }}/{{ page.url }}"

var result = "[![" + badgeUrl + "](" + badgeUrl + ")](" + badgeLink + ")"
$(".markdown").text(result);
$(".markdown").show();

},

generateBadge:function() {
// Update the svg score
console.log("Updating score to " + this.points + "/" + this.total);
$("#svg-score").text(this.points + "/" + this.total);
$("#svg-color").attr("fill", this.color);
},
countPoints: function() {
this.total = document.querySelectorAll('input.task-list-item-checkbox[type="checkbox"]').length;
this.points = document.querySelectorAll('input.task-list-item-checkbox[type="checkbox"]:checked').length;
this.score = (100 * (this.points / document.querySelectorAll('input.task-list-item-checkbox[type="checkbox"]').length)).toFixed(2);
$('#svg-score').text(Math.round(this.score) + "%")
$('#svg-color').attr("fill", this.colors[this.points - 1])
}
},
mounted(){
this.countPoints();
this.populateScore();
this.generateBadge();
},
});
</script>

4 changes: 4 additions & 0 deletions contributor_ci/site/pages/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
layout: api
permalink: /api/
---
51 changes: 48 additions & 3 deletions contributor_ci/site/pages/cfa.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ permalink: /cfa/

# {{ page.title }}

**contributor ci** is a <a href="https://contributor-ci.readthedocs.io" target="_blank">library for extracting contributor metadata</a> and then visualizing the data and providing an interface to keep track of project contributor friendliness. This is the visualization portal, which is under development.

**contributor ci** is a <a href="https://contributor-ci.readthedocs.io" target="_blank">library for extracting contributor metadata</a> and then visualizing the data and providing an interface to keep track of project contributor friendliness. This is the visualization portal for LLNL, which is under development.
{:.larger.text}

## The Contributor Friendliness Assessment
Expand Down Expand Up @@ -40,7 +39,53 @@ More specifically, the Contributor Friendliness Assessment (CFA) is an effort to

Most of these assessments are currently manual, and will be automated in time. You can read more about the CFA <a href="https://contributor-ci.readthedocs.io/en/latest/getting_started/user-guide.html#contributor-friendliness-assessment" target="_blank">here</a>, and we invite you to explore the following contributor friendliness assessments

{% include ordered_child_list.liquid docs=site.cfa %}
<div class="ui bulleted link list" id="app">
</div>

This aspect of the interface is under development, so you can expect the design
of these pages to change. Return back to the <a href="{{ site.baseurl }}/">index here</a>.

<script>
function loadJSON(path, success, error)
{
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function()
{
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
if (success)
success(JSON.parse(xhr.responseText));
} else {
if (error)
error(xhr);
}
}
};
xhr.open("GET", path, true);
xhr.send();
}


var colors = ["#B43C3C","#BB473E","#BF5340","#BF6240","#BF6F40","#BF7540","#BF7D40","#BF8440","#BF8E40","#BF9740","#BF9F40","#BFAA40","#BFB540","#BFBB40","#AEBF40","#9FBF40","#80BF40","#59BF40"];
var total = 47;

loadJSON('{{ site.baseurl }}/api/',
function(data) {

var items = [];
$.each(data['data'], function(i, item) {
console.log(item);
// Prepare badge images
var color_index = parseInt((item['checked'] / total) * colors.length)
var badgeColor = colors[color_index];
var score = (100 * (item['checked'] / total)).toFixed(2);
var badgeScore = Math.round(score) + "%25"
var badgeUrl = "https://img.shields.io/badge/software%20checklist-" + badgeScore + "-" + badgeColor.replace("#", "");
$("#app").append( "<a href='"+ item['url'] + "' class='item' id='" + item['id'] + "'><img style='padding-right:15px' src='"+ badgeUrl + "'>" + item['id'] + "</a>" );
});

},
function(xhr) { console.error(xhr); }
);

</script>
24 changes: 19 additions & 5 deletions docs/getting_started/user-guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,13 @@ change this:
$ cci ui generate ./docs
If you want to also generate files for the contributor friendliness assessment, you can add --cfa:
Whether you are generating or updating, if you want to also generate new files
for the contributor friendliness assessment, you can add --cfa:

.. code-block:: console
$ cci ui --cfa generate
Once you have an interface, it has a GitHub action that will run an update
command on a nightly basis to generate new data for it. But you can also
run this locally or manually. It takes the same argument for a directory
Expand All @@ -201,10 +201,24 @@ or defaults to the present working directory.
$ cci ui update
And akin to generate, you can specify to generate new CFA files (default will not):

.. code-block:: console
$ cci ui --cfa update
For update and the GitHub action, the default will be to run all extractors.
However for large projects you might instead want to choose a random subset:

.. code-block:: console
$ cci ui update random:4
For update and the GitHub action, by default, if it finds that CFA files have been generated
for the site, it will look for new repos to add and generate for. You
are of course free to customize the interface to your pleasing. For example,
Once you have your interface, it's recommended to update your ``GITHUB_TOKEN``
to a personal access token ``CCI_GITHUB_TOKEN`` that will work for all extractors.
You are of course free to customize the interface to your pleasing. For example,
you will likely want to change the site baseurl (the name of your repository where
you will serve it), site metadata, and the sidebar highlight color:

Expand Down

0 comments on commit 6f477e5

Please sign in to comment.