Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
1896e57
Reduce json diff to simple passthrough
ayjayt May 2, 2025
2fb5ebd
Factor diffs out fo _audit to cmp
ayjayt May 2, 2025
20969f8
Change name of audit-repos to audit-rulesets
ayjayt May 2, 2025
f070b71
Fix up test.sh
ayjayt May 2, 2025
6a41d0a
Merge branch 'main' into andrew/refactor_audit
ayjayt May 2, 2025
db37441
Improve remove_excluded_keys
ayjayt May 2, 2025
47e9b58
Better organize call
ayjayt May 3, 2025
e2fd5bd
Refactor table generation for audit_ruleset
ayjayt May 3, 2025
9e241dd
Fix function name
ayjayt May 3, 2025
4ceb360
Readd missing cmp.json_diff section and cmp/
ayjayt May 12, 2025
8a1176f
Refactor _check_options
davidangarita1 May 12, 2025
f22deb7
Create base html for rulesets
davidangarita1 May 12, 2025
3ea9273
Create repos file for template
davidangarita1 May 12, 2025
fbc3bfd
Change function name
davidangarita1 May 12, 2025
c408ea6
Move repo logic from init to repos file
davidangarita1 May 12, 2025
29ba061
Rename repo call for repo template
davidangarita1 May 12, 2025
7e5ddc3
Implement html for rulesets
davidangarita1 May 12, 2025
03f88d8
Create RulesetRow class
davidangarita1 May 12, 2025
728b003
Create common styles
davidangarita1 May 12, 2025
69bc1b4
Add html url option for rulesets
davidangarita1 May 12, 2025
a967cab
Add ipdb dev dependency
davidangarita1 May 12, 2025
a60592d
Add logic base for rulesets table
davidangarita1 May 12, 2025
2140ef6
Add table headers
davidangarita1 May 13, 2025
4c7517b
Add styles for table and theads
davidangarita1 May 13, 2025
2c079df
Remove test class
davidangarita1 May 13, 2025
cf76abf
Add table col class
davidangarita1 May 13, 2025
e4c098c
Add table col code class
davidangarita1 May 13, 2025
d2736bd
Change table-col-code styles
davidangarita1 May 13, 2025
a79af05
Implement highlighjs library for json
davidangarita1 May 14, 2025
01fdebd
Add headers for html table
davidangarita1 May 14, 2025
19fc384
Make the search bar sticky
davidangarita1 May 14, 2025
d61f1f6
Add better styles for filters
davidangarita1 May 14, 2025
1a3166e
Add encoding for load file
davidangarita1 May 14, 2025
df5ef0c
Add hover to badges
davidangarita1 May 14, 2025
42dd9a7
Create sort btn for repos
davidangarita1 May 14, 2025
251d314
Remove bg color for search bar
davidangarita1 May 14, 2025
045850e
Create sort script for repos
davidangarita1 May 14, 2025
aa4ca32
Make sort function reusable
davidangarita1 May 14, 2025
5b2b601
Add bg color to search bar
davidangarita1 May 14, 2025
fd177a3
Create utils script
davidangarita1 May 14, 2025
68b005a
Fix topic styles
davidangarita1 May 14, 2025
79059d8
Remove class from repository
davidangarita1 May 14, 2025
59d1209
Move table styles for common styles
davidangarita1 May 14, 2025
b7f4566
Add table styles for repos
davidangarita1 May 14, 2025
c5b6327
Modify table styles for rulesets
davidangarita1 May 14, 2025
4121f93
Change theader color and padding
davidangarita1 May 14, 2025
b23ab5b
Merge pull request #66 from geopozo/david/html-audit-rulesets
ayjayt May 14, 2025
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
6 changes: 3 additions & 3 deletions src/integration_test/test.sh → integration_test/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ run_basic_commands() {
"releases -r $REPO"
"pypi -r $REPO"
"audit-releases -r $REPO"
"audit-repo -r $REPO"
"audit-rulesets -r $REPO"
"audit-versions -r $REPO"
)

Expand All @@ -59,7 +59,7 @@ run_pretty_commands() {
"releases -r $REPO"
"pypi -r $REPO"
"audit-releases -r $REPO"
"audit-repo -r $REPO"
"audit-rulesets -r $REPO"
"audit-versions -r $REPO"
)

Expand All @@ -81,7 +81,7 @@ run_pretty_json_commands() {
"releases -r $REPO"
"pypi -r $REPO"
"audit-releases -r $REPO"
"audit-repo -r $REPO"
"audit-rulesets -r $REPO"
"audit-versions -r $REPO"
)

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ dev = [
"poethepoet>=0.30.0",
"types-tabulate>=0.9.0.20241207",
"types-aiofiles>=24.1.0.20250326",
"ipdb>=0.13.13",
]

#docs = [
Expand Down
23 changes: 19 additions & 4 deletions src/github_helper/_adapters/api_to_cli.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import urllib.parse
from pprint import pformat

import logistro

Expand All @@ -12,11 +13,12 @@ class GHAdapter:
"""Allows the CLI to transform the data as required."""

def _check_options(self, formatters):
allowed_commands = {"repos", "audit-rulesets"}
formats = {k for k, v in formatters.items() if v}
invalid_formats = {"html", "url"} & formats
if (
(self._command == "auth-status" and formats)
or (self._command != "repos" and invalid_formats)
or (self._command not in allowed_commands and invalid_formats)
or (self._command == "audit-releases" and self._json)
):
raise NotImplementedError(
Expand Down Expand Up @@ -74,7 +76,7 @@ async def transform_scopes_data(self, scopes_data):

async def transform_repos_data(self, repos_data):
if self._html:
generated_html = str(await to_html.repos(repos_data))
generated_html = str(await to_html.repos_template(repos_data))
if not self._url:
return generated_html
encoded = urllib.parse.quote(generated_html)
Expand Down Expand Up @@ -168,10 +170,23 @@ async def transform_audit_releases_data(self, releases_data):
)

async def transform_audit_rulesets_data(self, audit_rulesets_data):
if self._html:
generated_html = str(
await to_html.rulesets_template(audit_rulesets_data),
)
if not self._url:
return generated_html
encoded = urllib.parse.quote(generated_html)
return f"data:text/html;charset=utf-8,{encoded}"

if self._json:
return to_json.format_json(audit_rulesets_data, pretty=self._pretty)
for rule in audit_rulesets_data:
rule["template"] = rule["template"][:24]

audit_rulesets_data["diffs"] = [
pformat(d) if not isinstance(d, str) else d
for d in audit_rulesets_data.get("diffs")
]

return to_table.format_table(audit_rulesets_data, pretty=self._pretty)

async def transform_audit_versions_data(self, version_data):
Expand Down
200 changes: 3 additions & 197 deletions src/github_helper/_adapters/to_html/__init__.py
Original file line number Diff line number Diff line change
@@ -1,198 +1,4 @@
from collections.abc import MutableMapping
from dataclasses import dataclass
from pathlib import Path
from .repos import repos_template
from .rulesets import rulesets_template

import logistro
from htmy import Component, Context, component, html

from github_helper._adapters.to_html import _components
from github_helper._utils import load_file

_logger = logistro.getLogger(__name__)

github_com = r"https://www.github.com"
_HTML_DIR = Path(__file__).resolve().parent
_STYLES_PATH = _HTML_DIR / "_styles"
_JS_PATH = _HTML_DIR / "_js"


@dataclass(frozen=True, kw_only=True, slots=True)
class RepoRow:
repo: MutableMapping

def _error_printer(self, s):
return html.span(str(type(s).__name__), title=str(s))

async def htmy(self, context: Context) -> Component: # noqa: ARG002
repo = self.repo
permission_msg = {
0: "Can read and clone this repository.",
1: "Can pull and also manage issues and pull requests.",
2: "Can read, clone, and push to this repository",
3: "Can also manage issues, pull requests, and some repository settings.",
4: "Full access to the repository, including settings and collaborators.",
}

_logger.debug(f"Building html row for {repo['name']}")
return html.tr(
html.td(html.span("📌" if repo["pinned"] else "")),
html.td(
html.a(
repo["owner"],
href=f"{github_com}/{repo['owner']}",
target="_blank",
),
class_="owner",
),
html.td(html.span("/")),
html.td(
html.a(
repo["name"],
href=f"{github_com}/{repo['owner']}/{repo['name']}",
target="_blank",
),
class_="repo",
),
html.td(html.span(repo["version"]), class_="text-center"),
html.td(html.span("⑂" if repo["fork"] else "")),
html.td(
html.span(repo["description"] or ""),
class_="description",
),
html.td(
html.a(
"🔧",
href=f"{github_com}/{repo['owner']}/{repo['name']}/settings/access",
target="_blank",
),
*[
self._error_printer(s)
if isinstance(s, Exception)
else html.a(
s["user"],
html.sup(
str(s["permission"]),
class_="badge",
),
href=f"{github_com}/{s['user']}",
class_="collaborator",
target="_blank",
title=permission_msg[s["permission"]],
)
if isinstance(s, dict)
else s
for s in (
sorted(
repo["collaborators"],
key=lambda d: d["permission"],
reverse=True,
)
if repo["collaborators"]
and isinstance(repo["collaborators"][0], dict)
else repo["collaborators"]
)
],
class_="collaborators",
),
html.td(
html.a(
"🔧",
href=f"{github_com}/{repo['owner']}/{repo['name']}",
target="_blank",
),
*[html.span(s, class_=f"topic {s}") for s in repo["topics"]],
class_="topics",
),
class_=(
"repo-row "
f"{repo['visibility']} "
f"{'archived' if repo['archived'] else ''}"
),
)


@component
def repo_rows(repos, context: Context) -> Component: # noqa: ARG001
return [RepoRow(repo=repo) for repo in repos]


async def repos(repos_data):
_logger.debug("Building table.")
styles = html.style(await load_file(_STYLES_PATH / "repos.css"))
table = html.table(repo_rows(repos_data), class_="mx-auto")
modal_iframe = _components.modal(
"my-modal",
"closeModal()",
html.iframe(src="", height="500", class_="w-full"),
)
_logger.debug("Building page.")
scripts = [
html.script(
html.SafeStr(
"\n".join(
[
await load_file(_JS_PATH / "repos.js"),
await load_file(_JS_PATH / "modal.js"),
],
),
),
),
]
content = [
html.div(
html.label(
html.input_(
type_="checkbox",
id_="toggle-public",
checked=True,
),
" Show Public",
),
html.label(
html.input_(
type_="checkbox",
id_="toggle-private",
checked=True,
style="margin-left:1rem;",
),
" Show Private",
),
html.label(
html.input_(
type_="checkbox",
id_="toggle-archive",
checked=True,
style="margin-left:1rem;",
),
" Show Archived",
),
html.br(),
html.label(
" Owner",
html.input_(
type_="text",
id_="owner-filter",
name="owner-filter",
placeholder="Owner",
class_="rounded shadow-sm sm:text-sm p-1",
),
),
html.label(
" Repo",
html.input_(
type_="text",
id_="repo-filter",
name="repo-filter",
placeholder="Repo",
class_="rounded shadow-sm sm:text-sm p-1",
),
),
style="margin-bottom: 1rem;",
class_="mx-auto",
id_="controls",
),
table,
modal_iframe,
*scripts,
]
return await _components.render_page([styles], content)
__all__ = ["repos_template", "rulesets_template"]
1 change: 1 addition & 0 deletions src/github_helper/_adapters/to_html/_js/repos.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const privateCheckbox = document.getElementById('toggle-private');
const archivedCheckbox = document.getElementById('toggle-archive');
const ownerInput = document.getElementById('owner-filter');
const repoInput = document.getElementById('repo-filter');
const tbody = document.querySelector("tbody");

function filterAll() {
console.log("Filtering All.")
Expand Down
21 changes: 21 additions & 0 deletions src/github_helper/_adapters/to_html/_js/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const sortTableBy = (btnId, filter) => {
const filterBtn = document.getElementById(btnId);
const order = filterBtn.dataset.order === "asc" ? "desc" : "asc";
filterBtn.dataset.order = order;
isAsc = order === "asc"
filterBtn.textContent = `${isAsc ? "⬆️" : "⬇️"}`;
filterBtn.title = `Sort by ${isAsc ? "asc" : "desc"}`;

const rows = Array.from(tbody.querySelectorAll("tr"));

rows.sort((a, b) => {
const nameA = a.querySelector(filter).textContent.trim().toLowerCase();
const nameB = b.querySelector(filter).textContent.trim().toLowerCase();
return order === "asc"
? nameA.localeCompare(nameB)
: nameB.localeCompare(nameA);
});

rows.forEach(row => tbody.appendChild(row));
updateVisibleRowClasses();
}
28 changes: 28 additions & 0 deletions src/github_helper/_adapters/to_html/_styles/common.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
body {
overflow-x: auto;
width: 100%;
}

table {
width: max-content;
}

tr.even {
background-color: #f0f0f0;
}

tr.odd {
background-color: #ffffff;
}

.table {
@apply table-auto mx-auto my-4 border border-gray-300 shadow-md rounded-md overflow-hidden text-sm;
}

.table-header {
@apply text-center px-4 py-2 text-sm font-semibold text-gray-700 bg-gray-300 border-r;
}

.table-col {
@apply px-2 py-2 align-top border-t border-gray-200 border-r;
}
17 changes: 0 additions & 17 deletions src/github_helper/_adapters/to_html/_styles/repos.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,6 @@ tr.repo-row td a:active {
color: black;
}

body {
overflow-x: auto;
width: 100%;
}

table {
width: max-content;
}

tr.even {
background-color: #f0f0f0;
}

tr.odd {
background-color: #ffffff;
}

tr.repo-row.private {
font-weight: 350;
}
Expand Down
Loading