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

[WIP] Add a GUI #59

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
fc3d95a
[Feature]: Add a POC for the web app
CapriciousRebel Oct 26, 2021
6f41c1e
[Feature]: Add purge configuration to remove unused tailwindcss classes
CapriciousRebel Oct 27, 2021
c3e725e
\n issue fixed
rosekamallove Nov 10, 2021
57863d2
[Feature]: Add express server to expose an api
CapriciousRebel Nov 15, 2021
7e45b9d
Rebase with remote
CapriciousRebel Nov 15, 2021
eb59c43
[Feat]: Add input command box
CapriciousRebel Dec 7, 2021
caad47a
[Refactor]: Remove unused repos
CapriciousRebel Dec 8, 2021
f6d2c4e
[Refactor]: Update CSS
CapriciousRebel Dec 8, 2021
0ec8e68
[Refactor]: Remove unnecessary files and config
CapriciousRebel Dec 8, 2021
091e52d
Remove DS_Store file
CapriciousRebel Dec 8, 2021
c310dda
Add DSStore to gitignore
CapriciousRebel Dec 8, 2021
48c02af
add doubt comments
CapriciousRebel Dec 8, 2021
274d813
add sample env file and update setup instructions in readme
CapriciousRebel Dec 8, 2021
127c05f
[Fix]: border issue
CapriciousRebel Dec 8, 2021
1eb0712
center the circles in the table
CapriciousRebel Dec 8, 2021
4af652b
Add a status indicator
CapriciousRebel Dec 8, 2021
6f68b03
Add eslint disable for magic numbers
CapriciousRebel Dec 8, 2021
365ce21
Add newline to end of files
CapriciousRebel Dec 9, 2021
df5fd26
Merge branch 'main' into add-gui
CapriciousRebel Dec 9, 2021
e65d0ed
Fix merge errors
CapriciousRebel Dec 9, 2021
c1e3a14
Update to align with the format of the latest main branch
CapriciousRebel Dec 9, 2021
89c44e4
[Feature]: Add table clear feature before loading new table
CapriciousRebel Dec 9, 2021
8384471
[Fix]: Seperate the styles into another file
CapriciousRebel Dec 28, 2021
da8ca7e
[Fix]: apply formatting on index.html
CapriciousRebel Dec 28, 2021
b040819
[Fix]: remove hardcoded url
CapriciousRebel Dec 28, 2021
1d2f06a
[Fix]: remove unnecessary implicit string conversion
CapriciousRebel Dec 28, 2021
84ff4d8
[Fix]: remove unnecessary implicit string conversion
CapriciousRebel Dec 28, 2021
124f9f7
[Fix]: add GITHUB_TOKEN along with GH_TOKEN
CapriciousRebel Dec 28, 2021
9cd20ba
[Refactor]: remove unnecessary forEach loop
CapriciousRebel Dec 28, 2021
bf53a70
[Refactor]: generateGui
CapriciousRebel Dec 28, 2021
e24218a
Merge branch 'main' into add-gui
CapriciousRebel Dec 28, 2021
d7b8e79
[Refactor]: utils file
CapriciousRebel Dec 29, 2021
295eac2
[Revert]: remove DS_Store from gitignore
CapriciousRebel Dec 29, 2021
ebe3900
[Refactor]: conversion of table output to sting
CapriciousRebel Dec 29, 2021
5e3df41
[Refactor]: remove unnecessary branch from detail.js
CapriciousRebel Dec 29, 2021
0a87131
[Refactor]: server/app.js
CapriciousRebel Dec 29, 2021
bf7726c
[Fix, Refactor]: server import fix and better syntax to check for array
CapriciousRebel Dec 29, 2021
d88896d
[Refactor]: better export syntax
CapriciousRebel Dec 29, 2021
568e7e0
[Refactor]: remove css variables
CapriciousRebel Jan 1, 2022
b57f665
[Fix, Refactor, Feature]: fix token issue, refactor css file, add err…
CapriciousRebel Jan 1, 2022
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 .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
GH_TOKEN=<Your Github Token>
port=3000
XDG_CONFIG_HOME=
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@

[![npm badge][npm-badge-png]][package-url]


CLI to list all repos a user has access to, and report on their configuration in aggregate.

# Installation

- `npm install` to install all dependencies
- create `.env` file and initialize `GH_TOKEN` or `GITHUB_TOKEN` (in order of precedence) with your Github token
- run `cp .env.sample .env` and initialize GH_TOKEN or GITHUB_TOKEN (in order of precedence) with your Github token, set the port on which the gui will be served (default=3000) in the newly generated `.env` file.

# Usage (for public)

Expand Down
3 changes: 3 additions & 0 deletions bin/commands/detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ module.exports.builder = (yargs) => {
describe: 'Show available metrics',
type: 'boolean',
})
.option('gui', {
describe: 'Show output in the form of a webpage',
})
.help('help')
.strict();

Expand Down
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,18 @@
"private": false,
"dependencies": {
"@octokit/graphql": "^4.8.0",
"axios": "^0.24.0",
"cli-table": "^0.3.11",
"colors": "^1.4.0",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"http-status-codes": "^2.2.0",
"jsonschema": "^1.4.0",
"minimatch": "^3.0.4",
"mkdirp": "^1.0.4",
"yargs": "^17.3.0"
"open": "^8.3.0",
"yargs": "^17.3.0",
"yargs-parser": "^20.2.9"
},
"devDependencies": {
"@ljharb/eslint-config": "^20.0.0",
Expand Down
8 changes: 7 additions & 1 deletion src/commands/detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const {
generateDetailTable,
} = require('../utils');

const server = require('../server/app.js');
const getMetrics = require('../metrics');
const Metrics = require('../../config/metrics.js');

Expand Down Expand Up @@ -124,7 +125,12 @@ module.exports = async function detail(flags) {
});

if (table) {
console.log(String(table));
if (flags.gui) {
server();
} else {
console.log(String(table));
}

}

printAPIPoints(points);
Expand Down
20 changes: 20 additions & 0 deletions src/server/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

const express = require('express');
const { executeCommand } = require('./controllers');
const path = require('path');
const open = require('open');

module.exports = function server() {
const app = express();
const { port } = process.env;
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use('/', express.static(path.join(__dirname, '../static')));
app.post('/command', executeCommand);
app.listen(port, () => {
console.log(`Api is listening on port ${port}`);
console.log(`View the gui on: http://localhost:${port}/`);
});
open(`http://localhost:${port}/`);
};
194 changes: 194 additions & 0 deletions src/server/controllers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/* eslint-disable no-magic-numbers */

'use strict';

const { StatusCodes } = require('http-status-codes');

const parse = require('yargs-parser');
const {
listMetrics,
getRepositories,
generateDetailTable,
generateGui,
} = require('../utils');

const getMetrics = require('../metrics');

// Metric names and their extraction method to be used on the query result (Order is preserved)
const metricNames = [
Copy link
Owner

Choose a reason for hiding this comment

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

seems like this file contains a lot of copied code from elsewhere in the repo?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, it is the code from the details.js file. Kindly consider this commit as an intermediate step. I was having some trouble with the exports(for some reason importing the detail function gave errors, saying detail wasn't a function). So I just copy-pasted the code instead to make things work for the time being. I will fix this in a future commit and perhaps squash this commit.

Copy link
Owner

Choose a reason for hiding this comment

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

Sounds good :-) just calling it out so it's not forgotten.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is still a doubt for me, could you probably suggest me a fix for this? I'm not sure why importing from detail.js is not working. Perhaps there is some issue with express js? Not really sure

Copy link
Owner

Choose a reason for hiding this comment

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

I'm not sure either. Can you restore the import, and i'll try it locally?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Let's address this issue at the very end of this PR, once we have everything in working order.

'Repository',
'isFork',
'Access',
'IssuesEnabled',
'ProjectsEnabled',
'WikiEnabled',
'AllowsForking',
'Archived',
'AutoMergeAllowed',
'BlankIssuesEnabled',
'SecurityPolicyEnabled',
'License',
'MergeStrategies',
'DeleteOnMerge',
'HasStarred',
'Subscription',
'DefBranch',
'AllowsForcePushes',
'AllowsDeletions',
'DismissesStaleReviews',
'ReqApprovingReviewCount',
'ReqApprovingReviews',
'ReqCodeOwnerReviews',
'ReqConversationResolution',
'isPrivate',
];

const generateQuery = (endCursor, {
f,
}) => {
let showForks = false;
let showSources = true;
let showPrivate = false;
let showPublic = true;
if (Array.isArray(f)) {
showForks = f.includes('forks');
showSources = f.includes('sources');
showPrivate = f.includes('private');
showPublic = f.includes('public');
}
return (
`query {
viewer {
repositories(
first: 100
affiliations: [OWNER, ORGANIZATION_MEMBER, COLLABORATOR]
${endCursor ? `after: "${endCursor}"` : ''}
${showForks === showSources ? '' : showForks ? 'isFork: true' : 'isFork: false'}
${showPrivate === showPublic ? '' : showPublic ? 'privacy: PUBLIC' : 'privacy: PRIVATE'}
) {
totalCount
pageInfo {
endCursor
hasNextPage
}
nodes {
name
nameWithOwner
defaultBranchRef {
name
branchProtectionRule {
allowsForcePushes
allowsDeletions
dismissesStaleReviews
requiredApprovingReviewCount
requiresApprovingReviews
requiresCodeOwnerReviews
requiresConversationResolution
restrictsPushes
}
}
deleteBranchOnMerge
hasIssuesEnabled
hasProjectsEnabled
hasWikiEnabled
forkingAllowed
isArchived
autoMergeAllowed
isBlankIssuesEnabled
isFork
isPrivate
isSecurityPolicyEnabled
isTemplate
licenseInfo {
name
}
mergeCommitAllowed
owner {
login
}
rebaseMergeAllowed
squashMergeAllowed
createdAt
updatedAt
pushedAt
viewerHasStarred
viewerPermission
viewerSubscription
}
}
}
rateLimit {
cost
remaining
}
}
`);
};

/*
* DOUBT: Copy-Pasted this function here as I was having issues with importing the function
* from src/commands/detail.js
*/
const detail = async (flags) => {
Comment on lines +128 to +132
Copy link
Owner

Choose a reason for hiding this comment

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

i'm still not sure what the issue would be - what happens if you require('../commands/detail')?

if (flags.m) {
return listMetrics(getMetrics(metricNames));
}
let metrics;
if (flags.p?.length > 0) {
metrics = getMetrics([
'Repository',
'isFork',
'isPrivate',
...metricNames.filter((name) => flags.p.includes(name)),
]);
} else {
metrics = getMetrics(metricNames);
}

// Additional Filter on repos
let filter;
if (flags.f?.length === 1 && flags.f[0] === 'templates') {
filter = (repo) => repo.isTemplate;
}
// Get all repositories
const { repositories } = await getRepositories(generateQuery, flags, filter);
if (!flags.s) {
repositories.sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt));
}
// Generate output table
const table = generateDetailTable(metrics, repositories, {
actual: flags.actual, all: flags.all, goodness: flags.goodness, sort: flags.s, unactionable: flags.unactionable,
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
actual: flags.actual, all: flags.all, goodness: flags.goodness, sort: flags.s, unactionable: flags.unactionable,
actual: flags.actual,
all: flags.all,
goodness: flags.goodness,
sort: flags.s,
unactionable: flags.unactionable,

});

return table || null;
};

const executeCommand = async (req, res) => {
const { command } = req.body;
const argv = parse(command);
argv.goodness = true;

if (!argv.token) {
// token not present, so check positional argument to check if GH_TOKEN or GITHUB_TOKEN is present
argv._.forEach((element) => {
const [key, val] = element.split('=');
if (key === 'GH_TOKEN' || key === 'GITHUB_TOKEN') {
argv.token = val;
}
});
if (!argv.token) {
// no token provided in frontend, hence return 403
return res.status(StatusCodes.FORBIDDEN).json({
msg: 'env variable GH_TOKEN or GITHUB_TOKEN, or `--token` argument, not found.',
success: 0,
});
}
}
let output = await detail(argv);
output = generateGui(output);
return res.status(StatusCodes.OK).json({ output });
};

module.exports = {
executeCommand,
};
Loading