fix: fix all linting errors
This commit is contained in:
parent
9b7e616ab6
commit
23f0cff306
465
gulpfile.js
465
gulpfile.js
|
@ -1,21 +1,20 @@
|
||||||
// Require dependencies
|
// Require dependencies
|
||||||
const
|
const path = require('path');
|
||||||
cheerio = require('cheerio'),
|
const cheerio = require('cheerio');
|
||||||
df = require('date-format'),
|
const df = require('date-format');
|
||||||
{Feed} = require('feed'),
|
const {Feed} = require('feed');
|
||||||
fs = require('fs-extra'),
|
const fs = require('fs-extra');
|
||||||
gitlab = require('gitlab/dist/es5').default,
|
const GitLab = require('gitlab/dist/es5').default;
|
||||||
gulp = require('gulp'),
|
const gulp = require('gulp');
|
||||||
htmlclean = require('gulp-htmlclean'),
|
const htmlclean = require('gulp-htmlclean');
|
||||||
klaw = require('klaw-sync'),
|
const klaw = require('klaw-sync');
|
||||||
log = require('fancy-log'),
|
const log = require('fancy-log');
|
||||||
merge2 = require('merge2'),
|
const merge2 = require('merge2');
|
||||||
path = require('path'),
|
const scss = require('gulp-sass');
|
||||||
scss = require('gulp-sass'),
|
const sync = require('browser-sync');
|
||||||
sync = require('browser-sync')
|
|
||||||
|
|
||||||
// Require statistic functions
|
// Require statistic functions
|
||||||
const { avgTime, freqUsers, labelsAlphabet, changedLines, uniqueContributors } = require('./statistics')
|
const {avgTime, freqUsers, labelsAlphabet, changedLines, uniqueContributors} = require('./statistics');
|
||||||
|
|
||||||
// Define paths that are gonna be used commonly
|
// Define paths that are gonna be used commonly
|
||||||
const paths = {
|
const paths = {
|
||||||
|
@ -24,35 +23,35 @@ const paths = {
|
||||||
issues: {
|
issues: {
|
||||||
open: path.join(__dirname, 'data/issues/open/'),
|
open: path.join(__dirname, 'data/issues/open/'),
|
||||||
closed: path.join(__dirname, 'data/issues/closed/'),
|
closed: path.join(__dirname, 'data/issues/closed/'),
|
||||||
out: path.join(__dirname, 'data/issues/out/'),
|
out: path.join(__dirname, 'data/issues/out/')
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
extra: path.join(__dirname, 'src/favicons/**'),
|
extra: path.join(__dirname, 'src/favicons/**'),
|
||||||
html: {
|
html: {
|
||||||
index: path.join(__dirname, 'src/index.html'),
|
index: path.join(__dirname, 'src/index.html'),
|
||||||
posts: path.join(__dirname, 'src/posts/*.html'),
|
posts: path.join(__dirname, 'src/posts/*.html')
|
||||||
},
|
},
|
||||||
out: path.join(__dirname, 'public/'),
|
out: path.join(__dirname, 'public/'),
|
||||||
scss: path.join(__dirname, 'src/scss/*.scss'),
|
scss: path.join(__dirname, 'src/scss/*.scss')
|
||||||
}
|
};
|
||||||
|
|
||||||
// Define options for Node Sass and Browser Sync
|
// Define options for Node Sass and Browser Sync
|
||||||
const opts = {
|
const opts = {
|
||||||
scss: {
|
scss: {
|
||||||
outputStyle: 'compressed',
|
outputStyle: 'compressed'
|
||||||
},
|
},
|
||||||
sync: {
|
sync: {
|
||||||
server: {
|
server: {
|
||||||
baseDir: paths.out,
|
baseDir: paths.out
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// The data to download from specified month, months are zero-based zo January would be 0
|
// The data to download from specified month, months are zero-based zo January would be 0
|
||||||
// Make sure both of these are **numbers**, if they are strings it won't work properly!
|
// Make sure both of these are **numbers**, if they are strings it won't work properly!
|
||||||
const wantedMonth = new Date().getMonth()
|
const wantedMonth = new Date().getMonth();
|
||||||
// Since we've passed from 2018 into 2019 we also have to start checking for year now
|
// Since we've passed from 2018 into 2019 we also have to start checking for year now
|
||||||
const wantedYear = new Date().getFullYear()
|
const wantedYear = new Date().getFullYear();
|
||||||
|
|
||||||
// Init the months array, probably a way to do this with Dates but this works too
|
// Init the months array, probably a way to do this with Dates but this works too
|
||||||
const months = [
|
const months = [
|
||||||
|
@ -67,31 +66,31 @@ const months = [
|
||||||
'September',
|
'September',
|
||||||
'October',
|
'October',
|
||||||
'November',
|
'November',
|
||||||
'December',
|
'December'
|
||||||
]
|
];
|
||||||
|
|
||||||
// Add the year and month to the open/closed/out path so they're easy to identify
|
// Add the year and month to the open/closed/out path so they're easy to identify
|
||||||
const commitsPath = `${paths.data.commits}${wantedYear}/${months[wantedMonth]}/`
|
const commitsPath = `${paths.data.commits}${wantedYear}/${months[wantedMonth]}/`;
|
||||||
const openIssuesPath = `${paths.data.issues.open}${wantedYear}/${months[wantedMonth]}/` // folder
|
const openIssuesPath = `${paths.data.issues.open}${wantedYear}/${months[wantedMonth]}/`; // Folder
|
||||||
const closedIssuesPath = `${paths.data.issues.closed}${wantedYear}/${months[wantedMonth]}/` // folder
|
const closedIssuesPath = `${paths.data.issues.closed}${wantedYear}/${months[wantedMonth]}/`; // Folder
|
||||||
const outIssuesPath = `${paths.data.issues.out}${months[wantedMonth]}${wantedYear}` // will become table and statistics files
|
const outIssuesPath = `${paths.data.issues.out}${months[wantedMonth]}${wantedYear}`; // Will become table and statistics files
|
||||||
|
|
||||||
// Make the directories using fs-extra's "mkdir -p" equivalent
|
// Make the directories using fs-extra's "mkdir -p" equivalent
|
||||||
// It will make any directory that doesn't yet exist in the path
|
// It will make any directory that doesn't yet exist in the path
|
||||||
fs.mkdirpSync(commitsPath)
|
fs.mkdirpSync(commitsPath);
|
||||||
fs.mkdirpSync(openIssuesPath)
|
fs.mkdirpSync(openIssuesPath);
|
||||||
fs.mkdirpSync(closedIssuesPath)
|
fs.mkdirpSync(closedIssuesPath);
|
||||||
fs.mkdirpSync(paths.data.issues.out)
|
fs.mkdirpSync(paths.data.issues.out);
|
||||||
|
|
||||||
// Create the browser sync server, it only starts when using `gulp watch` however
|
// Create the browser sync server, it only starts when using `gulp watch` however
|
||||||
const server = sync.create()
|
const server = sync.create();
|
||||||
|
|
||||||
// Copy over the HTML, using merge2 to use Gulp's async completion and multiple src's
|
// Copy over the HTML, using merge2 to use Gulp's async completion and multiple src's
|
||||||
function buildHTML() {
|
function buildHTML() {
|
||||||
return merge2([
|
return merge2([
|
||||||
gulp.src(paths.html.index).pipe(htmlclean()).pipe(gulp.dest(paths.out)),
|
gulp.src(paths.html.index).pipe(htmlclean()).pipe(gulp.dest(paths.out)),
|
||||||
gulp.src(paths.html.posts).pipe(htmlclean()).pipe(gulp.dest(paths.out + 'posts/')),
|
gulp.src(paths.html.posts).pipe(htmlclean()).pipe(gulp.dest(paths.out + 'posts/'))
|
||||||
])
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the CSS
|
// Build the CSS
|
||||||
|
@ -99,33 +98,33 @@ function buildCSS() {
|
||||||
return gulp
|
return gulp
|
||||||
.src(paths.scss)
|
.src(paths.scss)
|
||||||
.pipe(scss(opts.scss))
|
.pipe(scss(opts.scss))
|
||||||
.pipe(gulp.dest(paths.out + 'css/'))
|
.pipe(gulp.dest(paths.out + 'css/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the extra stuff, for now only the favicons
|
// Build the extra stuff, for now only the favicons
|
||||||
function buildExtra() {
|
function buildExtra() {
|
||||||
return gulp
|
return gulp
|
||||||
.src(paths.extra)
|
.src(paths.extra)
|
||||||
.pipe(gulp.dest(paths.out))
|
.pipe(gulp.dest(paths.out));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the Browser Sync server and watch individual file types with appropriate build functions
|
// Start the Browser Sync server and watch individual file types with appropriate build functions
|
||||||
function watch() {
|
function watch() {
|
||||||
server.init(opts.sync)
|
server.init(opts.sync);
|
||||||
gulp.watch([ paths.html.index, paths.html.posts ], gulp.series(buildHTML, createFeeds, reload))
|
gulp.watch([paths.html.index, paths.html.posts], gulp.series(buildHTML, createFeeds, reload));
|
||||||
gulp.watch(paths.scss, gulp.series(buildCSS, reload))
|
gulp.watch(paths.scss, gulp.series(buildCSS, reload));
|
||||||
gulp.watch(paths.extra, gulp.series(buildExtra, reload))
|
gulp.watch(paths.extra, gulp.series(buildExtra, reload));
|
||||||
}
|
}
|
||||||
|
|
||||||
// To use Gulp's async completion system this has to be done, it's ugly but can't do without it
|
// To use Gulp's async completion system this has to be done, it's ugly but can't do without it
|
||||||
function reload(callback) {
|
function reload(callback) {
|
||||||
server.reload()
|
server.reload();
|
||||||
callback()
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
function download() {
|
function download() {
|
||||||
// Create the API with the token
|
// Create the API with the token
|
||||||
const api = new gitlab({ token: require('./config.json').token })
|
const api = new GitLab({token: require('./config.json').token});
|
||||||
|
|
||||||
// Return a new Promise so we can take advantage of Gulp's async completion system
|
// Return a new Promise so we can take advantage of Gulp's async completion system
|
||||||
// We'll reject whenever there is an error and resolve when everything is completed
|
// We'll reject whenever there is an error and resolve when everything is completed
|
||||||
|
@ -133,240 +132,253 @@ function download() {
|
||||||
// The Node GitLab API is a bit weird, first we have to find the project Tildes/Tildes
|
// The Node GitLab API is a bit weird, first we have to find the project Tildes/Tildes
|
||||||
api.Projects
|
api.Projects
|
||||||
.show('tildes/tildes')
|
.show('tildes/tildes')
|
||||||
.catch((error) => reject(new Error('There was an error fetching the project:', error)))
|
.catch(error => reject(new Error('There was an error fetching the project:', error)))
|
||||||
.then((project) => {
|
.then(project => {
|
||||||
log('Found project, downloading issues...')
|
log('Found project, downloading issues...');
|
||||||
// Then once we find the project we can use it and its ID to download the issues
|
// Then once we find the project we can use it and its ID to download the issues
|
||||||
api.Issues
|
api.Issues
|
||||||
.all({projectId: project.id})
|
.all({projectId: project.id})
|
||||||
.catch((error) => reject(new Error('There was an error downloading the issues:', error)))
|
.catch(error => reject(new Error('There was an error downloading the issues:', error)))
|
||||||
.then((issues) => {
|
.then(issues => {
|
||||||
// And then once we've downloaded all the issues we can write them to file appropriately
|
// And then once we've downloaded all the issues we can write them to file appropriately
|
||||||
log(`Downloaded issues, saving opened and closed issues from ${months[wantedMonth]} ${wantedYear} to file...`)
|
log(`Downloaded issues, saving opened and closed issues from ${months[wantedMonth]} ${wantedYear} to file...`);
|
||||||
for (const issue of issues) {
|
for (const issue of issues) {
|
||||||
const createdDate = new Date(issue.created_at)
|
const createdDate = new Date(issue.created_at);
|
||||||
if (createdDate.getFullYear() === wantedYear &&
|
if (createdDate.getFullYear() === wantedYear &&
|
||||||
createdDate.getMonth() === wantedMonth) {
|
createdDate.getMonth() === wantedMonth) {
|
||||||
fs.writeFileSync(openIssuesPath + `${issue.iid}.json`, JSON.stringify(issue, null, 2))
|
fs.writeFileSync(openIssuesPath + `${issue.iid}.json`, JSON.stringify(issue, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
const closedDate = new Date(issue.closed_at)
|
const closedDate = new Date(issue.closed_at);
|
||||||
if (issue.closed_at !== null &&
|
if (issue.closed_at !== null &&
|
||||||
closedDate.getFullYear() === wantedYear &&
|
closedDate.getFullYear() === wantedYear &&
|
||||||
closedDate.getMonth() === wantedMonth) {
|
closedDate.getMonth() === wantedMonth) {
|
||||||
fs.writeFileSync(closedIssuesPath + `${issue.iid}.json`, JSON.stringify(issue, null, 2))
|
fs.writeFileSync(closedIssuesPath + `${issue.iid}.json`, JSON.stringify(issue, null, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log('Finished writing issues to file.')
|
|
||||||
log('Downloading commits...')
|
log('Finished writing issues to file.');
|
||||||
|
log('Downloading commits...');
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
api.Commits.all(project.id, {ref_name: 'master', with_stats: true})
|
api.Commits.all(project.id, {ref_name: 'master', with_stats: true})
|
||||||
.catch((error) => reject(new Error('There was an error downloading the commits:', error)))
|
.catch(error => reject(new Error('There was an error downloading the commits:', error)))
|
||||||
.then((commits) => {
|
.then(commits => {
|
||||||
log(`Downloaded commits, saving commits from ${months[wantedMonth]} ${wantedYear} to file...`)
|
log(`Downloaded commits, saving commits from ${months[wantedMonth]} ${wantedYear} to file...`);
|
||||||
for (const commit of commits) {
|
for (const commit of commits) {
|
||||||
const authoredDate = new Date(commit.authored_date)
|
const authoredDate = new Date(commit.authored_date);
|
||||||
if (authoredDate.getFullYear() === wantedYear &&
|
if (authoredDate.getFullYear() === wantedYear &&
|
||||||
authoredDate.getMonth() === wantedMonth) {
|
authoredDate.getMonth() === wantedMonth) {
|
||||||
fs.writeFileSync(commitsPath + `${commit.short_id}.json`, JSON.stringify(commit, null, 2))
|
fs.writeFileSync(commitsPath + `${commit.short_id}.json`, JSON.stringify(commit, null, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log('Finished writing commits to file.')
|
|
||||||
resolve()
|
log('Finished writing commits to file.');
|
||||||
})
|
resolve();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createIssueTable() {
|
function createIssueTable() {
|
||||||
// Using a Promise again for Gulp's async completion
|
// Using a Promise again for Gulp's async completion
|
||||||
return new Promise((resolve) => {
|
return new Promise(resolve => {
|
||||||
// Klaw returns all files in a directory recursively so we're getting all opened and closed issue files
|
// Klaw returns all files in a directory recursively so we're getting all opened and closed issue files
|
||||||
let opened = klaw(openIssuesPath)
|
const opened = klaw(openIssuesPath);
|
||||||
let closed = klaw(closedIssuesPath)
|
const closed = klaw(closedIssuesPath);
|
||||||
|
|
||||||
// Then we want to sort all of these issue files in their arrays
|
// Then we want to sort all of these issue files in their arrays
|
||||||
opened.sort(function(a, b) {
|
opened.sort((a, b) => {
|
||||||
const aFile = require(a.path)
|
const aFile = require(a.path);
|
||||||
const bFile = require(b.path)
|
const bFile = require(b.path);
|
||||||
return (aFile.iid > bFile.iid) ? 1 : ((bFile.iid > aFile.iid) ? -1 : 0)
|
return (aFile.iid > bFile.iid) ? 1 : ((bFile.iid > aFile.iid) ? -1 : 0);
|
||||||
})
|
});
|
||||||
|
|
||||||
closed.sort(function(a, b) {
|
closed.sort((a, b) => {
|
||||||
const aFile = require(a.path)
|
const aFile = require(a.path);
|
||||||
const bFile = require(b.path)
|
const bFile = require(b.path);
|
||||||
return (aFile.iid > bFile.iid) ? 1 : ((bFile.iid > aFile.iid) ? -1 : 0)
|
return (aFile.iid > bFile.iid) ? 1 : ((bFile.iid > aFile.iid) ? -1 : 0);
|
||||||
})
|
});
|
||||||
|
|
||||||
// And then generate the Issue Table HTML, which is kind of a mess to do
|
// And then generate the Issue Table HTML, which is kind of a mess to do
|
||||||
let table = '<article id="issue-table">\n'
|
let table = '<article id="issue-table">\n';
|
||||||
table += ' <h2>Issue Table</h2>\n'
|
table += ' <h2>Issue Table</h2>\n';
|
||||||
|
|
||||||
table += ' <h3 id="opened">Opened</h3>\n'
|
table += ' <h3 id="opened">Opened</h3>\n';
|
||||||
table += ' <table>\n'
|
table += ' <table>\n';
|
||||||
table += ' <thead>\n'
|
table += ' <thead>\n';
|
||||||
table += ' <tr>\n'
|
table += ' <tr>\n';
|
||||||
table += ' <td>Issue</td>\n'
|
table += ' <td>Issue</td>\n';
|
||||||
table += ' <td>Title</td>\n'
|
table += ' <td>Title</td>\n';
|
||||||
table += ' <td>Author</td>\n'
|
table += ' <td>Author</td>\n';
|
||||||
table += ' <td>Opened</td>\n'
|
table += ' <td>Opened</td>\n';
|
||||||
table += ' <td>Closed</td>\n'
|
table += ' <td>Closed</td>\n';
|
||||||
table += ' </tr>\n'
|
table += ' </tr>\n';
|
||||||
table += ' </thead>\n'
|
table += ' </thead>\n';
|
||||||
table += ' <tbody>\n'
|
table += ' <tbody>\n';
|
||||||
|
|
||||||
for (const file of opened) {
|
for (const file of opened) {
|
||||||
const issue = require(file.path)
|
const issue = require(file.path);
|
||||||
table += ' <tr>\n'
|
table += ' <tr>\n';
|
||||||
table += ` <td><a href="${issue.web_url}">${issue.iid}</a></td>\n`
|
table += ` <td><a href="${issue.web_url}">${issue.iid}</a></td>\n`;
|
||||||
|
|
||||||
let title
|
let title;
|
||||||
if (issue.title.length >= 50) {
|
if (issue.title.length >= 50) {
|
||||||
// We're going to be replacing all instances of <> signs to make sure nobody can add
|
// We're going to be replacing all instances of <> signs to make sure nobody can add
|
||||||
// <script></script> in their issue title and run JS on the site or mess up the layout or something
|
// <script></script> in their issue title and run JS on the site or mess up the layout or something
|
||||||
// I do check myself before I commit and push anything but I'd rather be completely sure.
|
// I do check myself before I commit and push anything but I'd rather be completely sure.
|
||||||
title = issue.title.substring(0, 47).replace(/[<>]/g, '') + '...'
|
title = issue.title.substring(0, 47).replace(/[<>]/g, '') + '...';
|
||||||
} else {
|
} else {
|
||||||
title = issue.title.replace(/[<>]/g, '')
|
title = issue.title.replace(/[<>]/g, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
table += ` <td>${title}</td>\n`
|
table += ` <td>${title}</td>\n`;
|
||||||
table += ` <td><a href="${issue.author.web_url}">${issue.author.username}</a></td>\n`
|
table += ` <td><a href="${issue.author.web_url}">${issue.author.username}</a></td>\n`;
|
||||||
table += ` <td>${df.asString('yyyy/MM/dd hh:mm:ss', new Date(issue.created_at))}</td>\n`
|
table += ` <td>${df.asString('yyyy/MM/dd hh:mm:ss', new Date(issue.created_at))}</td>\n`;
|
||||||
|
|
||||||
let closedAt
|
let closedAt;
|
||||||
if (issue.closed_at === null) {
|
if (issue.closed_at === null) {
|
||||||
closedAt = ''
|
closedAt = '';
|
||||||
} else {
|
} else {
|
||||||
closedAt = df.asString('yyyy/MM/dd hh:mm:ss', new Date(issue.closed_at))
|
closedAt = df.asString('yyyy/MM/dd hh:mm:ss', new Date(issue.closed_at));
|
||||||
}
|
}
|
||||||
|
|
||||||
table += ` <td>${closedAt}</td>\n`
|
table += ` <td>${closedAt}</td>\n`;
|
||||||
table += ' </tr>\n'
|
table += ' </tr>\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
table += ' </tbody>\n'
|
table += ' </tbody>\n';
|
||||||
table += ' </table>\n\n'
|
table += ' </table>\n\n';
|
||||||
|
|
||||||
table += ' <h3 id="closed">Closed</h3>\n'
|
table += ' <h3 id="closed">Closed</h3>\n';
|
||||||
table += ' <table>\n'
|
table += ' <table>\n';
|
||||||
table += ' <thead>\n'
|
table += ' <thead>\n';
|
||||||
table += ' <tr>\n'
|
table += ' <tr>\n';
|
||||||
table += ' <td>Issue</td>\n'
|
table += ' <td>Issue</td>\n';
|
||||||
table += ' <td>Title</td>\n'
|
table += ' <td>Title</td>\n';
|
||||||
table += ' <td>Author</td>\n'
|
table += ' <td>Author</td>\n';
|
||||||
table += ' <td>Opened</td>\n'
|
table += ' <td>Opened</td>\n';
|
||||||
table += ' <td>Closed</td>\n'
|
table += ' <td>Closed</td>\n';
|
||||||
table += ' </tr>\n'
|
table += ' </tr>\n';
|
||||||
table += ' <thead>\n'
|
table += ' <thead>\n';
|
||||||
table += ' <tbody>\n'
|
table += ' <tbody>\n';
|
||||||
|
|
||||||
for (const file of closed) {
|
for (const file of closed) {
|
||||||
const issue = require(file.path)
|
const issue = require(file.path);
|
||||||
table += ' <tr>\n'
|
table += ' <tr>\n';
|
||||||
table += ` <td><a href="${issue.web_url}">${issue.iid}</a></td>\n`
|
table += ` <td><a href="${issue.web_url}">${issue.iid}</a></td>\n`;
|
||||||
|
|
||||||
let title
|
let title;
|
||||||
if (issue.title.length >= 50) {
|
if (issue.title.length >= 50) {
|
||||||
title = issue.title.substring(0, 47).replace(/[<>]/g, '') + '...'
|
title = issue.title.substring(0, 47).replace(/[<>]/g, '') + '...';
|
||||||
} else {
|
} else {
|
||||||
title = issue.title.replace(/[<>]/g, '')
|
title = issue.title.replace(/[<>]/g, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
table += ` <td>${title}\n`
|
table += ` <td>${title}\n`;
|
||||||
table += ` <td><a href="${issue.author.web_url}">${issue.author.username}</a>\n`
|
table += ` <td><a href="${issue.author.web_url}">${issue.author.username}</a>\n`;
|
||||||
table += ` <td>${df.asString('yyyy/MM/dd hh:mm:ss', new Date(issue.created_at))}</td>\n`
|
table += ` <td>${df.asString('yyyy/MM/dd hh:mm:ss', new Date(issue.created_at))}</td>\n`;
|
||||||
|
|
||||||
let closedAt
|
let closedAt;
|
||||||
if (issue.closed_at === null) {
|
if (issue.closed_at === null) {
|
||||||
closedAt = ''
|
closedAt = '';
|
||||||
} else {
|
} else {
|
||||||
closedAt = df.asString('yyyy/MM/dd hh:mm:ss', new Date(issue.closed_at))
|
closedAt = df.asString('yyyy/MM/dd hh:mm:ss', new Date(issue.closed_at));
|
||||||
}
|
}
|
||||||
|
|
||||||
table += ` <td>${closedAt}</td>\n`
|
table += ` <td>${closedAt}</td>\n`;
|
||||||
table += ' </tr>\n'
|
table += ' </tr>\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
table += ' </tbody>\n'
|
table += ' </tbody>\n';
|
||||||
table += ' </table>\n'
|
table += ' </table>\n';
|
||||||
table += '</article>\n'
|
table += '</article>\n';
|
||||||
|
|
||||||
// And finally when the HTML is done generating we can write it and resolve that Promise we made
|
// And finally when the HTML is done generating we can write it and resolve that Promise we made
|
||||||
fs.writeFileSync(outIssuesPath + '_table.html', table, { encoding: 'UTF-8' })
|
fs.writeFileSync(outIssuesPath + '_table.html', table, {encoding: 'UTF-8'});
|
||||||
resolve()
|
resolve();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createStatistics() {
|
function createStatistics() {
|
||||||
return new Promise((resolve) => {
|
return new Promise(resolve => {
|
||||||
// Same process as the Issue Table generation
|
// Same process as the Issue Table generation
|
||||||
let commits = klaw(commitsPath)
|
const commits = klaw(commitsPath);
|
||||||
let opened = klaw(openIssuesPath)
|
const opened = klaw(openIssuesPath);
|
||||||
let closed = klaw(closedIssuesPath)
|
const closed = klaw(closedIssuesPath);
|
||||||
|
|
||||||
let statistics = '<article id="statistics">\n'
|
let statistics = '<article id="statistics">\n';
|
||||||
statistics += ' <h2>Statistics</h2>\n'
|
statistics += ' <h2>Statistics</h2>\n';
|
||||||
|
|
||||||
const commitStats = changedLines(commits)
|
const commitStats = changedLines(commits);
|
||||||
const contributors = uniqueContributors(commits)
|
const contributors = uniqueContributors(commits);
|
||||||
|
|
||||||
statistics += ` <p>In the month of ${months[wantedMonth]}, `
|
statistics += ` <p>In the month of ${months[wantedMonth]}, `;
|
||||||
statistics += `${commits.length} commits were made by ${contributors.length} contributors, `
|
statistics += `${commits.length} commits were made by ${contributors.length} contributors, `;
|
||||||
statistics += `changing a total of ${Math.abs(commitStats.total)} (+${commitStats.added}|-${commitStats.deleted}) lines. `
|
statistics += `changing a total of ${Math.abs(commitStats.total)} (+${commitStats.added}|-${commitStats.deleted}) lines. `;
|
||||||
statistics += `${opened.length} issues were opened and `
|
statistics += `${opened.length} issues were opened and `;
|
||||||
statistics += `${closed.length} issues were closed.</p>\n`
|
statistics += `${closed.length} issues were closed.</p>\n`;
|
||||||
|
|
||||||
statistics += ` <p>An average of ${(opened.length / 30).toFixed(2)} issues were opened `
|
statistics += ` <p>An average of ${(opened.length / 30).toFixed(2)} issues were opened `;
|
||||||
statistics += `and ${(closed.length / 30).toFixed(2)} issues were closed each day.</p>\n`
|
statistics += `and ${(closed.length / 30).toFixed(2)} issues were closed each day.</p>\n`;
|
||||||
|
|
||||||
statistics += ` <p>The average time to close issues was ${avgTime(closed, 'days')} days `
|
statistics += ` <p>The average time to close issues was ${avgTime(closed, 'days')} days `;
|
||||||
statistics += `or ${avgTime(closed, 'hours')} hours.</p>\n`
|
statistics += `or ${avgTime(closed, 'hours')} hours.</p>\n`;
|
||||||
|
|
||||||
const topUsers = freqUsers(opened, 3)
|
const topUsers = freqUsers(opened, 3);
|
||||||
statistics += ' <p>Top 3 issue creators:</p>\n'
|
statistics += ' <p>Top 3 issue creators:</p>\n';
|
||||||
statistics += ' <ol>\n'
|
statistics += ' <ol>\n';
|
||||||
for (const user in topUsers) {
|
for (const user in topUsers) {
|
||||||
statistics += ' <li>\n'
|
statistics += ' <li>\n';
|
||||||
statistics += ` <a href="https://gitlab.com/${user}">${user}</a>`
|
statistics += ` <a href="https://gitlab.com/${user}">${user}</a>`;
|
||||||
statistics += ' with '
|
statistics += ' with ';
|
||||||
statistics += `<a href="https://gitlab.com/tildes/tildes/issues?state=all&author_username=${user}">${topUsers[user]} issues created</a>.\n`
|
statistics += `<a href="https://gitlab.com/tildes/tildes/issues?state=all&author_username=${user}">${topUsers[user]} issues created</a>.\n`;
|
||||||
statistics += ' </li>\n'
|
statistics += ' </li>\n';
|
||||||
}
|
}
|
||||||
statistics += ' </ol>\n'
|
|
||||||
|
|
||||||
let labels = labelsAlphabet(opened, true)
|
statistics += ' </ol>\n';
|
||||||
statistics += ' <p>Amount of labels assigned to currently open issues:</p>\n'
|
|
||||||
statistics += ' <ul>\n'
|
let labels = labelsAlphabet(opened, true);
|
||||||
|
statistics += ' <p>Amount of labels assigned to currently open issues:</p>\n';
|
||||||
|
statistics += ' <ul>\n';
|
||||||
for (const label in labels) {
|
for (const label in labels) {
|
||||||
statistics += ' <li>\n'
|
statistics += ' <li>\n';
|
||||||
statistics += ` <a href="https://gitlab.com/tildes/tildes/issues?state=opened&label_name%5B%5D=${label.replace(' ', '+')}")>${label}</a>:`
|
statistics += ` <a href="https://gitlab.com/tildes/tildes/issues?state=opened&label_name%5B%5D=${label.replace(' ', '+')}")>${label}</a>:`;
|
||||||
statistics += `${labels[label]} `
|
statistics += `${labels[label]} `;
|
||||||
if (labels[label] === 1) statistics += 'time.\n'
|
if (labels[label] === 1) {
|
||||||
else statistics += 'times.\n'
|
statistics += 'time.\n';
|
||||||
statistics += ' </li>\n'
|
} else {
|
||||||
|
statistics += 'times.\n';
|
||||||
}
|
}
|
||||||
statistics += ' </ul>\n'
|
|
||||||
|
|
||||||
labels = labelsAlphabet(closed, false)
|
statistics += ' </li>\n';
|
||||||
statistics += ' <p>Amount of labels assigned to closed issues:</p>\n'
|
}
|
||||||
statistics += ' <ul>\n'
|
|
||||||
|
statistics += ' </ul>\n';
|
||||||
|
|
||||||
|
labels = labelsAlphabet(closed, false);
|
||||||
|
statistics += ' <p>Amount of labels assigned to closed issues:</p>\n';
|
||||||
|
statistics += ' <ul>\n';
|
||||||
for (const label in labels) {
|
for (const label in labels) {
|
||||||
statistics += ' <li>\n'
|
statistics += ' <li>\n';
|
||||||
statistics += ` <a href="https://gitlab.com/tildes/tildes/issues?state=opened&label_name%5B%5D=${label.replace(' ', '+')}")>${label}</a>:`
|
statistics += ` <a href="https://gitlab.com/tildes/tildes/issues?state=opened&label_name%5B%5D=${label.replace(' ', '+')}")>${label}</a>:`;
|
||||||
statistics += `${labels[label]} `
|
statistics += `${labels[label]} `;
|
||||||
if (labels[label] === 1) statistics += 'time.\n'
|
if (labels[label] === 1) {
|
||||||
else statistics += 'times.\n'
|
statistics += 'time.\n';
|
||||||
statistics += ' </li>\n'
|
} else {
|
||||||
|
statistics += 'times.\n';
|
||||||
}
|
}
|
||||||
statistics += ' </ul>\n'
|
|
||||||
statistics += '</article>\n'
|
|
||||||
|
|
||||||
fs.writeFileSync(outIssuesPath + '_statistics.html', statistics, { encoding: 'UTF-8' })
|
statistics += ' </li>\n';
|
||||||
resolve()
|
}
|
||||||
})
|
|
||||||
|
statistics += ' </ul>\n';
|
||||||
|
statistics += '</article>\n';
|
||||||
|
|
||||||
|
fs.writeFileSync(outIssuesPath + '_statistics.html', statistics, {encoding: 'UTF-8'});
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFeeds() {
|
function createFeeds() {
|
||||||
|
@ -383,47 +395,47 @@ function createFeeds() {
|
||||||
feedLinks: {
|
feedLinks: {
|
||||||
atom: 'https://til.bauke.xyz/feed.atom',
|
atom: 'https://til.bauke.xyz/feed.atom',
|
||||||
json: 'https://til.bauke.xyz/feed.json',
|
json: 'https://til.bauke.xyz/feed.json',
|
||||||
rss: 'https://til.bauke.xyz/feed.rss',
|
rss: 'https://til.bauke.xyz/feed.rss'
|
||||||
},
|
},
|
||||||
author: {
|
author: {
|
||||||
name: 'Bauke',
|
name: 'Bauke',
|
||||||
email: 'me@bauke.xyz',
|
email: 'me@bauke.xyz',
|
||||||
link: 'https://bauke.xyz',
|
link: 'https://bauke.xyz'
|
||||||
},
|
}
|
||||||
})
|
});
|
||||||
const posts = fs.readdirSync(path.join(paths.out, 'posts'))
|
const posts = fs.readdirSync(path.join(paths.out, 'posts'));
|
||||||
// Sort the posts descending year and month
|
// Sort the posts descending year and month
|
||||||
posts.sort((a, b) => {
|
posts.sort((a, b) => {
|
||||||
const yearA = Number(a.replace(/\D/g, ''))
|
const yearA = Number(a.replace(/\D/g, ''));
|
||||||
const yearB = Number(b.replace(/\D/g, ''))
|
const yearB = Number(b.replace(/\D/g, ''));
|
||||||
if (yearA === yearB) {
|
if (yearA === yearB) {
|
||||||
const monthA = months.join(',').toLowerCase().split(',').indexOf(a.substring(0, a.indexOf('-'))) + 1
|
const monthA = months.join(',').toLowerCase().split(',').indexOf(a.substring(0, a.indexOf('-'))) + 1;
|
||||||
const monthB = months.join(',').toLowerCase().split(',').indexOf(b.substring(0, b.indexOf('-'))) + 1
|
const monthB = months.join(',').toLowerCase().split(',').indexOf(b.substring(0, b.indexOf('-'))) + 1;
|
||||||
return monthB - monthA
|
return monthB - monthA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return yearB - yearA
|
return yearB - yearA;
|
||||||
})
|
});
|
||||||
for (const post of posts) {
|
for (const post of posts) {
|
||||||
// Skip the template, that doesn't need to be included
|
// Skip the template, that doesn't need to be included
|
||||||
if (post.includes('template')) {
|
if (post.includes('template')) {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = fs.readFileSync(path.join(paths.out, 'posts', post), 'UTF8')
|
const html = fs.readFileSync(path.join(paths.out, 'posts', post), 'UTF8');
|
||||||
const $ = cheerio.load(html)
|
const $ = cheerio.load(html);
|
||||||
const title = $('#wrapper>h1').text()
|
const title = $('#wrapper>h1').text();
|
||||||
const id = `https://til.bauke.xyz/posts/${post}`
|
const id = `https://til.bauke.xyz/posts/${post}`;
|
||||||
const date = new Date(Date.UTC(
|
const date = new Date(Date.UTC(
|
||||||
Number(post.replace(/\D/g, '')),
|
Number(post.replace(/\D/g, '')),
|
||||||
// Add one to the month since UTC months are 0 based and since we set the
|
// Add one to the month since UTC months are 0 based and since we set the
|
||||||
// day as 0 we'll get the Date back as the last day of the previous month
|
// day as 0 we'll get the Date back as the last day of the previous month
|
||||||
months.join(',').toLowerCase().split(',').indexOf(post.substring(0, post.indexOf('-'))) + 1,
|
months.join(',').toLowerCase().split(',').indexOf(post.substring(0, post.indexOf('-'))) + 1,
|
||||||
0, 23, 59, 59
|
0, 23, 59, 59
|
||||||
))
|
));
|
||||||
const content = $('#post')
|
const content = $('#post')
|
||||||
.html()
|
.html()
|
||||||
.replace(/<article id="toc">.+?<\/article>/g, '') // Remove the TOC
|
.replace(/<article id="toc">.+?<\/article>/g, ''); // Remove the TOC
|
||||||
feed.addItem({
|
feed.addItem({
|
||||||
title,
|
title,
|
||||||
id,
|
id,
|
||||||
|
@ -432,16 +444,17 @@ function createFeeds() {
|
||||||
published: date,
|
published: date,
|
||||||
description: `${title}'s Issue Log`,
|
description: `${title}'s Issue Log`,
|
||||||
content,
|
content,
|
||||||
image: 'https://til.bauke.xyz/android-chrome-192x192.png',
|
image: 'https://til.bauke.xyz/android-chrome-192x192.png'
|
||||||
})
|
});
|
||||||
}
|
|
||||||
fs.writeFileSync(path.join(paths.out, 'feed.atom'), feed.atom1())
|
|
||||||
fs.writeFileSync(path.join(paths.out, 'feed.json'), feed.json1())
|
|
||||||
fs.writeFileSync(path.join(paths.out, 'feed.rss'), feed.rss2())
|
|
||||||
return Promise.resolve()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.build = gulp.series(gulp.parallel(buildHTML, buildCSS, buildExtra), createFeeds)
|
fs.writeFileSync(path.join(paths.out, 'feed.atom'), feed.atom1());
|
||||||
exports.download = gulp.series(download, gulp.parallel(createIssueTable, createStatistics))
|
fs.writeFileSync(path.join(paths.out, 'feed.json'), feed.json1());
|
||||||
exports.no_download = gulp.parallel(createIssueTable, createStatistics)
|
fs.writeFileSync(path.join(paths.out, 'feed.rss'), feed.rss2());
|
||||||
exports.watch = gulp.series(gulp.parallel(buildHTML, buildCSS, buildExtra), createFeeds, watch)
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.build = gulp.series(gulp.parallel(buildHTML, buildCSS, buildExtra), createFeeds);
|
||||||
|
exports.download = gulp.series(download, gulp.parallel(createIssueTable, createStatistics));
|
||||||
|
exports.no_download = gulp.parallel(createIssueTable, createStatistics);
|
||||||
|
exports.watch = gulp.series(gulp.parallel(buildHTML, buildCSS, buildExtra), createFeeds, watch);
|
||||||
|
|
|
@ -40,6 +40,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"xo": {
|
"xo": {
|
||||||
"space": true
|
"space": true,
|
||||||
|
"rules": {
|
||||||
|
"camelcase": "off",
|
||||||
|
"guard-for-in": "off"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
@import 'colors';
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: $cyan;
|
color: $cyan;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
|
@ -3,7 +3,7 @@ $background: #282a36;
|
||||||
$selection: #44475a;
|
$selection: #44475a;
|
||||||
$comment: #6272a4;
|
$comment: #6272a4;
|
||||||
|
|
||||||
$red: #ff5555;
|
$red: #f55;
|
||||||
$orange: #ffb86c;
|
$orange: #ffb86c;
|
||||||
$yellow: #f1fa8c;
|
$yellow: #f1fa8c;
|
||||||
$green: #50fa7b;
|
$green: #50fa7b;
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
width: 95vw;
|
width: 95vw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 500px) {
|
@media screen and (max-width: 500px) {
|
||||||
#post > #toc {
|
#post > #toc {
|
||||||
|
// stylelint-disable-next-line property-blacklist
|
||||||
float: none;
|
float: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
@import 'anchor';
|
|
||||||
@import 'colors';
|
@import 'colors';
|
||||||
|
@import 'anchor';
|
||||||
|
|
||||||
html, body, p, ul, ol, li,
|
html,
|
||||||
h1, h2, h3, h4, h5 {
|
body,
|
||||||
|
p,
|
||||||
|
ul,
|
||||||
|
ol,
|
||||||
|
li,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
@ -30,8 +39,8 @@ body {
|
||||||
|
|
||||||
> h3 {
|
> h3 {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 10px 4px 10px;
|
margin: 0 10px 4px;
|
||||||
padding: 0 4px 4px 4px;
|
padding: 0 4px 4px;
|
||||||
border-bottom: 4px solid;
|
border-bottom: 4px solid;
|
||||||
|
|
||||||
&:nth-child(7n + 1) {
|
&:nth-child(7n + 1) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@import 'anchor';
|
|
||||||
@import 'colors';
|
@import 'colors';
|
||||||
|
@import 'anchor';
|
||||||
|
|
||||||
#posts {
|
#posts {
|
||||||
background-color: rgba(0, 0, 0, 0.25);
|
background-color: rgba(0, 0, 0, 0.25);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@import 'anchor';
|
|
||||||
@import 'colors';
|
@import 'colors';
|
||||||
|
@import 'anchor';
|
||||||
|
|
||||||
#post {
|
#post {
|
||||||
> #toc {
|
> #toc {
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
border: 4px solid $yellow;
|
border: 4px solid $yellow;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
|
// stylelint-disable-next-line property-blacklist
|
||||||
float: right;
|
float: right;
|
||||||
background-color: $background;
|
background-color: $background;
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:before {
|
&::before {
|
||||||
content: '>';
|
content: '>';
|
||||||
padding-right: 0.5em;
|
padding-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,7 @@
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:before {
|
&::before {
|
||||||
content: '>>';
|
content: '>>';
|
||||||
padding-right: 0.5em;
|
padding-right: 0.5em;
|
||||||
padding-left: 0.5em;
|
padding-left: 0.5em;
|
||||||
|
@ -52,10 +53,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
> *:not(#toc) {
|
> *:not(#toc) {
|
||||||
padding: 1em 1em;
|
padding: 1em;
|
||||||
background-color: rgba(0, 0, 0, 0.25);
|
background-color: rgba(0, 0, 0, 0.25);
|
||||||
|
|
||||||
p, ol, ul {
|
p,
|
||||||
|
ol,
|
||||||
|
ul {
|
||||||
padding: 0.2em 0;
|
padding: 0.2em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +83,7 @@
|
||||||
h3 {
|
h3 {
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
padding: 2px 0;
|
padding: 2px 0;
|
||||||
margin: 1em 0 0.4em 0;
|
margin: 1em 0 0.4em;
|
||||||
border-bottom: 4px solid $red;
|
border-bottom: 4px solid $red;
|
||||||
width: 25%;
|
width: 25%;
|
||||||
}
|
}
|
||||||
|
@ -89,7 +92,8 @@
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol, ul {
|
ol,
|
||||||
|
ul {
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
margin-bottom: 0.2em;
|
margin-bottom: 0.2em;
|
||||||
|
|
||||||
|
@ -105,7 +109,7 @@
|
||||||
ul {
|
ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
|
|
||||||
> li:before {
|
> li::before {
|
||||||
content: '>';
|
content: '>';
|
||||||
padding-left: 0.5em;
|
padding-left: 0.5em;
|
||||||
padding-right: 0.5em;
|
padding-right: 0.5em;
|
||||||
|
|
135
statistics.js
135
statistics.js
|
@ -7,20 +7,28 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function avgTime(data, time) {
|
function avgTime(data, time) {
|
||||||
if (time !== 'hours' && time !== 'days') return Error('avgTime(data, time): time should be "hours" or "days"')
|
if (time !== 'hours' && time !== 'days') {
|
||||||
let avg
|
return new Error('avgTime(data, time): time should be "hours" or "days"');
|
||||||
for (const file of data) {
|
|
||||||
const issue = require(file.path)
|
|
||||||
const openDate = new Date(issue.created_at)
|
|
||||||
const closeDate = new Date(issue.closed_at)
|
|
||||||
let diff
|
|
||||||
if (time === 'days') diff = (closeDate - openDate) / (1000 * 60 * 60 * 24)
|
|
||||||
else if (time === 'hours') diff = (closeDate - openDate) / (1000 * 60 * 60)
|
|
||||||
avg = (typeof avg === 'undefined')
|
|
||||||
? avg = diff
|
|
||||||
: avg += diff
|
|
||||||
}
|
}
|
||||||
return (avg / data.length).toFixed(2)
|
|
||||||
|
let avg;
|
||||||
|
for (const file of data) {
|
||||||
|
const issue = require(file.path);
|
||||||
|
const openDate = new Date(issue.created_at);
|
||||||
|
const closeDate = new Date(issue.closed_at);
|
||||||
|
let diff;
|
||||||
|
if (time === 'days') {
|
||||||
|
diff = (closeDate - openDate) / (1000 * 60 * 60 * 24);
|
||||||
|
} else if (time === 'hours') {
|
||||||
|
diff = (closeDate - openDate) / (1000 * 60 * 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
avg = (typeof avg === 'undefined') ?
|
||||||
|
avg = diff :
|
||||||
|
avg += diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (avg / data.length).toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,20 +40,31 @@ function avgTime(data, time) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function freqUsers(data, maxUsers) {
|
function freqUsers(data, maxUsers) {
|
||||||
if (typeof maxUsers === 'undefined') maxUsers = 3
|
if (typeof maxUsers === 'undefined') {
|
||||||
let userCounts = {}
|
maxUsers = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userCounts = {};
|
||||||
for (const file of data) {
|
for (const file of data) {
|
||||||
const issue = require(file.path)
|
const issue = require(file.path);
|
||||||
if (typeof userCounts[issue.author.username] === 'undefined') userCounts[issue.author.username] = 1
|
if (typeof userCounts[issue.author.username] === 'undefined') {
|
||||||
else userCounts[issue.author.username]++
|
userCounts[issue.author.username] = 1;
|
||||||
|
} else {
|
||||||
|
userCounts[issue.author.username]++;
|
||||||
}
|
}
|
||||||
const sortedArray = Object.keys(userCounts).sort((a, b) => userCounts[b] - userCounts[a])
|
}
|
||||||
const sortedObject = {}
|
|
||||||
|
const sortedArray = Object.keys(userCounts).sort((a, b) => userCounts[b] - userCounts[a]);
|
||||||
|
const sortedObject = {};
|
||||||
for (let i = 0; i < maxUsers; i++) {
|
for (let i = 0; i < maxUsers; i++) {
|
||||||
if (typeof sortedArray[i] === 'undefined') break
|
if (typeof sortedArray[i] === 'undefined') {
|
||||||
sortedObject[sortedArray[i]] = userCounts[sortedArray[i]]
|
break;
|
||||||
}
|
}
|
||||||
return sortedObject
|
|
||||||
|
sortedObject[sortedArray[i]] = userCounts[sortedArray[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortedObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,61 +76,75 @@ function freqUsers(data, maxUsers) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function labelsAlphabet(data, checkNull) {
|
function labelsAlphabet(data, checkNull) {
|
||||||
if (typeof checkNull === 'undefined') checkNull = false
|
if (typeof checkNull === 'undefined') {
|
||||||
const labels = {}
|
checkNull = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const labels = {};
|
||||||
for (const file of data) {
|
for (const file of data) {
|
||||||
const issue = require(file.path)
|
const issue = require(file.path);
|
||||||
if (checkNull && issue.closed_at !== null) continue
|
if (checkNull && issue.closed_at !== null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (const label of issue.labels) {
|
for (const label of issue.labels) {
|
||||||
if (typeof labels[label] === 'undefined') labels[label] = 1
|
if (typeof labels[label] === 'undefined') {
|
||||||
else labels[label]++
|
labels[label] = 1;
|
||||||
|
} else {
|
||||||
|
labels[label]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const labelsOrdered = {}
|
}
|
||||||
Object.keys(labels).sort().forEach(label => labelsOrdered[label] = labels[label])
|
|
||||||
return labelsOrdered
|
const labelsOrdered = {};
|
||||||
|
Object.keys(labels).sort().forEach(label => {
|
||||||
|
labelsOrdered[label] = labels[label];
|
||||||
|
});
|
||||||
|
return labelsOrdered;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function changedLines
|
* @function changedLines
|
||||||
* @description Returns the number of added, deleted and total lines changed
|
* @description Returns the number of added, deleted and total lines changed
|
||||||
* @param {Array} data Array with paths leading to GitLab Commit .json files (with stats)
|
* @param {Array} data Array with paths leading to GitLab Commit .json files (with stats)
|
||||||
* @returns {Object}
|
* @returns {Object} Object with added/deleted/total lines changed
|
||||||
*/
|
*/
|
||||||
function changedLines(data) {
|
function changedLines(data) {
|
||||||
const stats = {
|
const stats = {
|
||||||
added: 0,
|
added: 0,
|
||||||
deleted: 0,
|
deleted: 0,
|
||||||
total: 0,
|
total: 0
|
||||||
}
|
};
|
||||||
for (const file of data) {
|
for (const file of data) {
|
||||||
const commit = require(file.path)
|
const commit = require(file.path);
|
||||||
stats.added += commit.stats.additions
|
stats.added += commit.stats.additions;
|
||||||
stats.deleted += commit.stats.deletions
|
stats.deleted += commit.stats.deletions;
|
||||||
stats.total += commit.stats.additions - commit.stats.deletions
|
stats.total += commit.stats.additions - commit.stats.deletions;
|
||||||
}
|
}
|
||||||
return stats
|
|
||||||
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function uniqueContributors
|
* @function uniqueContributors
|
||||||
* @description Returns the names of all contributors
|
* @description Returns the names of all contributors
|
||||||
* @param {Array} data Array with paths leading to GitLab Commit .json files (with stats)
|
* @param {Array} data Array with paths leading to GitLab Commit .json files (with stats)
|
||||||
* @returns {Array}
|
* @returns {Array} Array with names of all contributors
|
||||||
*/
|
*/
|
||||||
function uniqueContributors(data) {
|
function uniqueContributors(data) {
|
||||||
const contributors = []
|
const contributors = [];
|
||||||
for (const file of data) {
|
for (const file of data) {
|
||||||
const commit = require(file.path)
|
const commit = require(file.path);
|
||||||
if (!contributors.includes(commit.author_name)) {
|
if (!contributors.includes(commit.author_name)) {
|
||||||
contributors.push(commit.author_name)
|
contributors.push(commit.author_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return contributors
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.avgTime = avgTime
|
return contributors;
|
||||||
exports.freqUsers = freqUsers
|
}
|
||||||
exports.labelsAlphabet = labelsAlphabet
|
|
||||||
exports.changedLines = changedLines
|
exports.avgTime = avgTime;
|
||||||
exports.uniqueContributors = uniqueContributors
|
exports.freqUsers = freqUsers;
|
||||||
|
exports.labelsAlphabet = labelsAlphabet;
|
||||||
|
exports.changedLines = changedLines;
|
||||||
|
exports.uniqueContributors = uniqueContributors;
|
||||||
|
|
Reference in New Issue