Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e5ba2cf34b | ||
|
f68439999d | ||
|
1da350a3d0 | ||
|
6ffe17f8b4 | ||
|
4aef61f232 | ||
|
5e0ef822fd | ||
|
94635fe447 | ||
|
5b36813618 | ||
|
dcf9898d67 | ||
|
884fc90171 | ||
|
b97833f7c5 | ||
|
1d6848cd17 | ||
|
0e016f41d3 | ||
|
8f9b4ccf8d | ||
|
51da6c20db | ||
|
f7a8341bb1 | ||
|
c361d6e2b6 | ||
|
ef137b518e | ||
|
3e66d85077 | ||
|
16430922c4 | ||
|
20b7de127d | ||
|
9def6961a9 | ||
|
f846c5ee47 | ||
|
8133f1f32e | ||
|
19e564c928 | ||
|
9c0b62271d | ||
|
7ceb9cb783 | ||
|
cee1906a39 | ||
|
0211f01bfb | ||
|
970d603c2e | ||
|
e558e07817 | ||
|
202d6fe6c3 | ||
|
ab02c0d880 | ||
|
110a667b31 | ||
|
fc187df45e | ||
|
389dc4441f | ||
|
bbc8ec9ca5 | ||
|
10151792e7 | ||
|
012928bcda |
32
CHANGELOG.md
32
CHANGELOG.md
@@ -1,37 +1,35 @@
|
|||||||
## <small>1.0.32 (2021-01-22)</small>
|
## <small>1.0.45 (2022-01-17)</small>
|
||||||
|
|
||||||
* docs: added documentation ([5753aef](https://github.com/simonecorsi/mawesome/commit/5753aef))
|
* build(deps): bump shelljs from 0.8.4 to 0.8.5 ([1da350a](https://github.com/simonecorsi/mawesome/commit/1da350a))
|
||||||
* chore: removed unused npm packages ([3ad1555](https://github.com/simonecorsi/mawesome/commit/3ad1555))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## <small>1.0.31 (2021-01-21)</small>
|
## <small>1.0.44 (2021-10-26)</small>
|
||||||
|
|
||||||
* chore(release): v1.0.31 ([903c070](https://github.com/simonecorsi/mawesome/commit/903c070))
|
* chore(release): v1.0.44 ([6ffe17f](https://github.com/simonecorsi/mawesome/commit/6ffe17f))
|
||||||
* feat: added user/email input for commiting ([58a7dc1](https://github.com/simonecorsi/mawesome/commit/58a7dc1))
|
* feat: git add multiple files at once ([4aef61f](https://github.com/simonecorsi/mawesome/commit/4aef61f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## <small>1.0.30 (2021-01-16)</small>
|
## <small>1.0.43 (2021-10-15)</small>
|
||||||
|
|
||||||
* chore(release): v1.0.30 ([a5f15da](https://github.com/simonecorsi/mawesome/commit/a5f15da))
|
* chore(release): v1.0.43 ([5e0ef82](https://github.com/simonecorsi/mawesome/commit/5e0ef82))
|
||||||
* fix: removed push ([7f42ca0](https://github.com/simonecorsi/mawesome/commit/7f42ca0))
|
* feat: reduce json output size ([94635fe](https://github.com/simonecorsi/mawesome/commit/94635fe))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## <small>1.0.29 (2021-01-16)</small>
|
## <small>1.0.42 (2021-10-14)</small>
|
||||||
|
|
||||||
* chore(release): v1.0.29 ([874894b](https://github.com/simonecorsi/mawesome/commit/874894b))
|
* chore(release): v1.0.42 ([5b36813](https://github.com/simonecorsi/mawesome/commit/5b36813))
|
||||||
* ci: on pull_request hook ([748c821](https://github.com/simonecorsi/mawesome/commit/748c821))
|
* fix(paginator): last page now correctly matches rex ([dcf9898](https://github.com/simonecorsi/mawesome/commit/dcf9898))
|
||||||
* ci: test on push ([226c942](https://github.com/simonecorsi/mawesome/commit/226c942))
|
|
||||||
* feat: added test workflow for pr ([1bd01f6](https://github.com/simonecorsi/mawesome/commit/1bd01f6))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## <small>1.0.28 (2021-01-16)</small>
|
## <small>1.0.41 (2021-10-14)</small>
|
||||||
|
|
||||||
* chore(release): v1.0.28 ([c805822](https://github.com/simonecorsi/mawesome/commit/c805822))
|
* chore(release): v1.0.41 ([884fc90](https://github.com/simonecorsi/mawesome/commit/884fc90))
|
||||||
* tests: added tests ([b8890fc](https://github.com/simonecorsi/mawesome/commit/b8890fc))
|
* test: fixs suite ([b97833f](https://github.com/simonecorsi/mawesome/commit/b97833f))
|
||||||
|
* fix: should avoid index lock ([1d6848c](https://github.com/simonecorsi/mawesome/commit/1d6848c))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
179
index.js
179
index.js
@@ -18482,7 +18482,7 @@ const testParameter = (name, filters) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const normalizeDataURL = (urlString, {stripHash}) => {
|
const normalizeDataURL = (urlString, {stripHash}) => {
|
||||||
const parts = urlString.match(/^data:(.*?),(.*?)(?:#(.*))?$/);
|
const parts = urlString.match(/^data:([^,]*?),([^#]*?)(?:#(.*))?$/);
|
||||||
|
|
||||||
if (!parts) {
|
if (!parts) {
|
||||||
throw new Error(`Invalid URL: ${urlString}`);
|
throw new Error(`Invalid URL: ${urlString}`);
|
||||||
@@ -21291,7 +21291,16 @@ class Git {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
this.config = (prop, value) => this.exec(`config ${prop} "${value}"`);
|
this.config = (prop, value) => this.exec(`config ${prop} "${value}"`);
|
||||||
this.add = (file) => this.exec(`add ${file}`);
|
this.add = (file) => {
|
||||||
|
let str = '';
|
||||||
|
if (Array.isArray(file)) {
|
||||||
|
file.map((f) => (str += ` ${f}`));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
str = file;
|
||||||
|
}
|
||||||
|
return this.exec(`add ${str}`);
|
||||||
|
};
|
||||||
this.commit = (message) => this.exec(`commit -m "${message}"`);
|
this.commit = (message) => this.exec(`commit -m "${message}"`);
|
||||||
this.pull = () => __awaiter(this, void 0, void 0, function* () {
|
this.pull = () => __awaiter(this, void 0, void 0, function* () {
|
||||||
const args = ['pull'];
|
const args = ['pull'];
|
||||||
@@ -21356,12 +21365,32 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
||||||
|
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
||||||
|
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
||||||
|
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
||||||
|
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
||||||
|
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
||||||
|
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
||||||
|
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
||||||
|
function fulfill(value) { resume("next", value); }
|
||||||
|
function reject(value) { resume("throw", value); }
|
||||||
|
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
||||||
|
};
|
||||||
|
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
||||||
|
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
||||||
|
var m = o[Symbol.asyncIterator], i;
|
||||||
|
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
||||||
|
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
||||||
|
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
||||||
|
};
|
||||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
var _a;
|
var _a;
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.pushNewFile = exports.OUTPUT_FILENAME = exports.generateMd = exports.paginate = exports.API_STARRED_URL = exports.REPO_USERNAME = exports.apiGetStar = exports.renderer = exports.isLastPage = exports.wait = void 0;
|
exports.pushNewFiles = exports.MARKDOWN_FILENAME = exports.generateMd = exports.apiGetStar = exports.getNextPage = exports.renderer = exports.wait = exports.API_STARRED_URL = exports.REPO_USERNAME = void 0;
|
||||||
|
const fs_1 = __importDefault(__nccwpck_require__(5747));
|
||||||
const ejs_1 = __importDefault(__nccwpck_require__(8431));
|
const ejs_1 = __importDefault(__nccwpck_require__(8431));
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const remark_1 = __importDefault(__nccwpck_require__(2081));
|
const remark_1 = __importDefault(__nccwpck_require__(2081));
|
||||||
@@ -21370,16 +21399,13 @@ const template_1 = __importDefault(__nccwpck_require__(3932));
|
|||||||
const api_1 = __importDefault(__nccwpck_require__(8229));
|
const api_1 = __importDefault(__nccwpck_require__(8229));
|
||||||
const link_1 = __importDefault(__nccwpck_require__(9338));
|
const link_1 = __importDefault(__nccwpck_require__(9338));
|
||||||
const git_1 = __importDefault(__nccwpck_require__(6350));
|
const git_1 = __importDefault(__nccwpck_require__(6350));
|
||||||
const fs_1 = __importDefault(__nccwpck_require__(5747));
|
exports.REPO_USERNAME = (_a = process.env.GITHUB_REPOSITORY) === null || _a === void 0 ? void 0 : _a.split('/')[0];
|
||||||
|
exports.API_STARRED_URL = `${process.env.GITHUB_API_URL}/users/${exports.REPO_USERNAME}/starred`;
|
||||||
const fsp = fs_1.default.promises;
|
const fsp = fs_1.default.promises;
|
||||||
function wait(time = 200) {
|
function wait(time = 200) {
|
||||||
return new Promise((resolve) => setTimeout(resolve, time));
|
return new Promise((resolve) => setTimeout(resolve, time));
|
||||||
}
|
}
|
||||||
exports.wait = wait;
|
exports.wait = wait;
|
||||||
function isLastPage(links) {
|
|
||||||
return links.next === links.last;
|
|
||||||
}
|
|
||||||
exports.isLastPage = isLastPage;
|
|
||||||
function renderer(data, templateString = template_1.default) {
|
function renderer(data, templateString = template_1.default) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
@@ -21392,32 +21418,91 @@ function renderer(data, templateString = template_1.default) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.renderer = renderer;
|
exports.renderer = renderer;
|
||||||
function apiGetStar(url) {
|
function getNextPage(links) {
|
||||||
|
const next = links.find((l) => l.rel === 'next');
|
||||||
|
const last = links.find((l) => l.rel === 'last');
|
||||||
|
if (!next || !last)
|
||||||
|
return null;
|
||||||
|
const matchNext = next.uri.match(/page=([0-9]*)/);
|
||||||
|
const matchLast = last.uri.match(/page=([0-9]*)/);
|
||||||
|
if (!matchNext || !matchLast)
|
||||||
|
return null;
|
||||||
|
if (matchNext[1] === matchLast[1])
|
||||||
|
return null;
|
||||||
|
return matchNext[1];
|
||||||
|
}
|
||||||
|
exports.getNextPage = getNextPage;
|
||||||
|
function paginateStars(url) {
|
||||||
|
return __asyncGenerator(this, arguments, function* paginateStars_1() {
|
||||||
|
let nextPage = '1';
|
||||||
|
while (nextPage) {
|
||||||
|
try {
|
||||||
|
const { headers, body } = yield __await(api_1.default.get(url, {
|
||||||
|
searchParams: {
|
||||||
|
page: nextPage,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
yield yield __await(body);
|
||||||
|
nextPage = getNextPage(link_1.default.parse(headers.link).refs);
|
||||||
|
yield __await(wait(1000)); // avoid limits
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function apiGetStar(url = exports.API_STARRED_URL) {
|
||||||
|
var e_1, _a;
|
||||||
|
var _b, _c, _d, _e, _f;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const { headers, body } = yield api_1.default.get(url);
|
const data = [];
|
||||||
return {
|
try {
|
||||||
data: body,
|
for (var _g = __asyncValues(paginateStars(url)), _h; _h = yield _g.next(), !_h.done;) {
|
||||||
links: link_1.default.parse(headers.link).refs.reduce((acc, val) => (Object.assign(Object.assign({}, acc), { [val.rel]: val.uri })), {}),
|
const stars = _h.value;
|
||||||
};
|
for (const star of stars) {
|
||||||
|
data.push({
|
||||||
|
id: star.id,
|
||||||
|
node_id: star.node_id,
|
||||||
|
name: star.name,
|
||||||
|
full_name: star.full_name,
|
||||||
|
owner: {
|
||||||
|
login: (_b = star === null || star === void 0 ? void 0 : star.owner) === null || _b === void 0 ? void 0 : _b.login,
|
||||||
|
id: (_c = star === null || star === void 0 ? void 0 : star.owner) === null || _c === void 0 ? void 0 : _c.id,
|
||||||
|
avatar_url: (_d = star === null || star === void 0 ? void 0 : star.owner) === null || _d === void 0 ? void 0 : _d.avatar_url,
|
||||||
|
url: (_e = star === null || star === void 0 ? void 0 : star.owner) === null || _e === void 0 ? void 0 : _e.url,
|
||||||
|
html_url: (_f = star === null || star === void 0 ? void 0 : star.owner) === null || _f === void 0 ? void 0 : _f.html_url,
|
||||||
|
},
|
||||||
|
html_url: star.html_url,
|
||||||
|
description: star.description,
|
||||||
|
url: star.url,
|
||||||
|
languages_url: star.languages_url,
|
||||||
|
created_at: star.created_at,
|
||||||
|
updated_at: star.updated_at,
|
||||||
|
git_url: star.git_url,
|
||||||
|
ssh_url: star.ssh_url,
|
||||||
|
clone_url: star.clone_url,
|
||||||
|
homepage: star.homepage,
|
||||||
|
stargazers_count: star.stargazers_count,
|
||||||
|
watchers_count: star.watchers_count,
|
||||||
|
language: star.language,
|
||||||
|
topics: star.topics,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
if (_h && !_h.done && (_a = _g.return)) yield _a.call(_g);
|
||||||
|
}
|
||||||
|
finally { if (e_1) throw e_1.error; }
|
||||||
|
}
|
||||||
|
return data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.apiGetStar = apiGetStar;
|
exports.apiGetStar = apiGetStar;
|
||||||
exports.REPO_USERNAME = (_a = process.env.GITHUB_REPOSITORY) === null || _a === void 0 ? void 0 : _a.split('/')[0];
|
|
||||||
exports.API_STARRED_URL = `${process.env.GITHUB_API_URL}/users/${exports.REPO_USERNAME}/starred`;
|
|
||||||
let links = {
|
|
||||||
next: exports.API_STARRED_URL,
|
|
||||||
last: undefined,
|
|
||||||
};
|
|
||||||
function paginate() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
if (isLastPage(links))
|
|
||||||
return null;
|
|
||||||
const r = yield apiGetStar(links.next);
|
|
||||||
links = r.links;
|
|
||||||
return r;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.paginate = paginate;
|
|
||||||
function generateMd(data) {
|
function generateMd(data) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
remark_1.default()
|
remark_1.default()
|
||||||
@@ -21433,17 +21518,19 @@ function generateMd(data) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.generateMd = generateMd;
|
exports.generateMd = generateMd;
|
||||||
exports.OUTPUT_FILENAME = core.getInput('output-filename') || 'README.md';
|
exports.MARKDOWN_FILENAME = core.getInput('output-filename') || 'README.md';
|
||||||
function pushNewFile(markdown) {
|
function pushNewFiles(files = []) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
yield fsp.writeFile(exports.OUTPUT_FILENAME, markdown);
|
if (!files.length)
|
||||||
|
return;
|
||||||
yield git_1.default.pull();
|
yield git_1.default.pull();
|
||||||
yield git_1.default.add(exports.OUTPUT_FILENAME);
|
yield Promise.all(files.map(({ filename, data }) => fsp.writeFile(filename, data)));
|
||||||
yield git_1.default.commit(`chore(${exports.OUTPUT_FILENAME}): updated ${exports.OUTPUT_FILENAME}`);
|
yield git_1.default.add(files.map(({ filename }) => filename));
|
||||||
|
yield git_1.default.commit(`chore(updates): updated entries in files`);
|
||||||
yield git_1.default.push();
|
yield git_1.default.push();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.pushNewFile = pushNewFile;
|
exports.pushNewFiles = pushNewFiles;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
@@ -21487,14 +21574,7 @@ const core = __importStar(__nccwpck_require__(2186));
|
|||||||
const helpers_1 = __nccwpck_require__(3015);
|
const helpers_1 = __nccwpck_require__(3015);
|
||||||
function main() {
|
function main() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let results = [];
|
const results = yield helpers_1.apiGetStar();
|
||||||
while (true) {
|
|
||||||
// sorry.
|
|
||||||
const r = yield helpers_1.paginate();
|
|
||||||
if (!r || r === null)
|
|
||||||
break;
|
|
||||||
results = results.concat(r.data);
|
|
||||||
}
|
|
||||||
const sortedByLanguages = results.reduce((acc, val) => {
|
const sortedByLanguages = results.reduce((acc, val) => {
|
||||||
const language = val.language || 'generic';
|
const language = val.language || 'generic';
|
||||||
if (!acc[language]) {
|
if (!acc[language]) {
|
||||||
@@ -21511,7 +21591,16 @@ function main() {
|
|||||||
updatedAt: Date.now(),
|
updatedAt: Date.now(),
|
||||||
});
|
});
|
||||||
const markdown = yield helpers_1.generateMd(rendered);
|
const markdown = yield helpers_1.generateMd(rendered);
|
||||||
yield helpers_1.pushNewFile(markdown);
|
yield helpers_1.pushNewFiles([
|
||||||
|
{
|
||||||
|
filename: helpers_1.MARKDOWN_FILENAME,
|
||||||
|
data: markdown,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filename: 'data.json',
|
||||||
|
data: JSON.stringify(sortedByLanguages, null, 2),
|
||||||
|
},
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.main = main;
|
exports.main = main;
|
||||||
|
979
package-lock.json
generated
979
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mawesome",
|
"name": "mawesome",
|
||||||
"version": "1.0.32",
|
"version": "1.0.45",
|
||||||
"description": "Generate awesome list from user starred repositories",
|
"description": "Generate awesome list from user starred repositories",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"author": "Simone Corsi<simonecorsi.dev@gmail.com>",
|
"author": "Simone Corsi<simonecorsi.dev@gmail.com>",
|
||||||
|
10
src/git.ts
10
src/git.ts
@@ -60,7 +60,15 @@ class Git {
|
|||||||
config = (prop: string, value: string) =>
|
config = (prop: string, value: string) =>
|
||||||
this.exec(`config ${prop} "${value}"`);
|
this.exec(`config ${prop} "${value}"`);
|
||||||
|
|
||||||
add = (file: string) => this.exec(`add ${file}`);
|
add = (file: string | string[]) => {
|
||||||
|
let str = '';
|
||||||
|
if (Array.isArray(file)) {
|
||||||
|
file.map((f) => (str += ` ${f}`));
|
||||||
|
} else {
|
||||||
|
str = file;
|
||||||
|
}
|
||||||
|
return this.exec(`add ${str}`);
|
||||||
|
};
|
||||||
|
|
||||||
commit = (message: string) => this.exec(`commit -m "${message}"`);
|
commit = (message: string) => this.exec(`commit -m "${message}"`);
|
||||||
|
|
||||||
|
118
src/helpers.ts
118
src/helpers.ts
@@ -1,3 +1,4 @@
|
|||||||
|
import fs from 'fs';
|
||||||
import ejs from 'ejs';
|
import ejs from 'ejs';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import remark from 'remark';
|
import remark from 'remark';
|
||||||
@@ -8,9 +9,10 @@ import GithubApi from './api';
|
|||||||
import link from './link';
|
import link from './link';
|
||||||
import git from './git';
|
import git from './git';
|
||||||
|
|
||||||
import type { PaginationLink, ApiGetStarResponse } from './types';
|
import type { PaginationLink, ApiGetStarResponse, Stars, Star } from './types';
|
||||||
|
|
||||||
import fs from 'fs';
|
export const REPO_USERNAME = process.env.GITHUB_REPOSITORY?.split('/')[0];
|
||||||
|
export const API_STARRED_URL = `${process.env.GITHUB_API_URL}/users/${REPO_USERNAME}/starred`;
|
||||||
|
|
||||||
const fsp = fs.promises;
|
const fsp = fs.promises;
|
||||||
|
|
||||||
@@ -18,10 +20,6 @@ export function wait(time = 200): Promise<void> {
|
|||||||
return new Promise((resolve) => setTimeout(resolve, time));
|
return new Promise((resolve) => setTimeout(resolve, time));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isLastPage(links: PaginationLink): boolean {
|
|
||||||
return links.next === links.last;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function renderer(
|
export async function renderer(
|
||||||
data: { [key: string]: any },
|
data: { [key: string]: any },
|
||||||
templateString = MD_TEMPLATE
|
templateString = MD_TEMPLATE
|
||||||
@@ -34,32 +32,72 @@ export async function renderer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function apiGetStar(url: string): Promise<ApiGetStarResponse> {
|
export function getNextPage(links: PaginationLink[]): string | null {
|
||||||
const { headers, body }: any = await GithubApi.get(url);
|
const next = links.find((l) => l.rel === 'next');
|
||||||
return {
|
const last = links.find((l) => l.rel === 'last');
|
||||||
data: body,
|
if (!next || !last) return null;
|
||||||
links: link.parse(headers.link).refs.reduce(
|
const matchNext = next.uri.match(/page=([0-9]*)/);
|
||||||
(acc, val) => ({
|
const matchLast = last.uri.match(/page=([0-9]*)/);
|
||||||
...acc,
|
if (!matchNext || !matchLast) return null;
|
||||||
[val.rel]: val.uri,
|
if (matchNext[1] === matchLast[1]) return null;
|
||||||
}),
|
return matchNext[1];
|
||||||
{}
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const REPO_USERNAME = process.env.GITHUB_REPOSITORY?.split('/')[0];
|
async function* paginateStars(url: string): AsyncGenerator<Stars> {
|
||||||
export const API_STARRED_URL = `${process.env.GITHUB_API_URL}/users/${REPO_USERNAME}/starred`;
|
let nextPage: string | null = '1';
|
||||||
|
while (nextPage) {
|
||||||
|
try {
|
||||||
|
const { headers, body } = await GithubApi.get(url, {
|
||||||
|
searchParams: {
|
||||||
|
page: nextPage,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
yield (body as unknown) as Stars;
|
||||||
|
nextPage = getNextPage(link.parse(headers.link).refs);
|
||||||
|
await wait(1000); // avoid limits
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let links: PaginationLink = {
|
export async function apiGetStar(
|
||||||
next: API_STARRED_URL,
|
url: string = API_STARRED_URL
|
||||||
last: undefined,
|
): Promise<ApiGetStarResponse> {
|
||||||
};
|
const data: Partial<Star>[] = [];
|
||||||
export async function paginate(): Promise<ApiGetStarResponse | null> {
|
for await (const stars of paginateStars(url)) {
|
||||||
if (isLastPage(links)) return null;
|
for (const star of stars) {
|
||||||
const r = await apiGetStar(links.next);
|
data.push({
|
||||||
links = r.links;
|
id: star.id,
|
||||||
return r;
|
node_id: star.node_id,
|
||||||
|
name: star.name,
|
||||||
|
full_name: star.full_name,
|
||||||
|
owner: {
|
||||||
|
login: star?.owner?.login,
|
||||||
|
id: star?.owner?.id,
|
||||||
|
avatar_url: star?.owner?.avatar_url,
|
||||||
|
url: star?.owner?.url,
|
||||||
|
html_url: star?.owner?.html_url,
|
||||||
|
},
|
||||||
|
html_url: star.html_url,
|
||||||
|
description: star.description,
|
||||||
|
url: star.url,
|
||||||
|
languages_url: star.languages_url,
|
||||||
|
created_at: star.created_at,
|
||||||
|
updated_at: star.updated_at,
|
||||||
|
git_url: star.git_url,
|
||||||
|
ssh_url: star.ssh_url,
|
||||||
|
clone_url: star.clone_url,
|
||||||
|
homepage: star.homepage,
|
||||||
|
stargazers_count: star.stargazers_count,
|
||||||
|
watchers_count: star.watchers_count,
|
||||||
|
language: star.language,
|
||||||
|
topics: star.topics,
|
||||||
|
} as Partial<Star>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (data as unknown) as Stars;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateMd(data: string): Promise<string> {
|
export function generateMd(data: string): Promise<string> {
|
||||||
@@ -77,12 +115,24 @@ export function generateMd(data: string): Promise<string> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OUTPUT_FILENAME: string =
|
export const MARKDOWN_FILENAME: string =
|
||||||
core.getInput('output-filename') || 'README.md';
|
core.getInput('output-filename') || 'README.md';
|
||||||
export async function pushNewFile(markdown: string): Promise<any> {
|
|
||||||
await fsp.writeFile(OUTPUT_FILENAME, markdown);
|
type File = {
|
||||||
|
filename: string;
|
||||||
|
data: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function pushNewFiles(files: File[] = []): Promise<any> {
|
||||||
|
if (!files.length) return;
|
||||||
|
|
||||||
await git.pull();
|
await git.pull();
|
||||||
await git.add(OUTPUT_FILENAME);
|
|
||||||
await git.commit(`chore(${OUTPUT_FILENAME}): updated ${OUTPUT_FILENAME}`);
|
await Promise.all(
|
||||||
|
files.map(({ filename, data }) => fsp.writeFile(filename, data))
|
||||||
|
);
|
||||||
|
|
||||||
|
await git.add(files.map(({ filename }) => filename));
|
||||||
|
await git.commit(`chore(updates): updated entries in files`);
|
||||||
await git.push();
|
await git.push();
|
||||||
}
|
}
|
||||||
|
25
src/index.ts
25
src/index.ts
@@ -2,23 +2,17 @@ import * as core from '@actions/core';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
renderer,
|
renderer,
|
||||||
paginate,
|
|
||||||
REPO_USERNAME,
|
REPO_USERNAME,
|
||||||
generateMd,
|
generateMd,
|
||||||
pushNewFile,
|
pushNewFiles,
|
||||||
|
MARKDOWN_FILENAME,
|
||||||
|
apiGetStar,
|
||||||
} from './helpers';
|
} from './helpers';
|
||||||
|
|
||||||
import type { SortedLanguageList, Stars, Star } from './types';
|
import type { SortedLanguageList, Stars, Star } from './types';
|
||||||
|
|
||||||
export async function main(): Promise<any> {
|
export async function main(): Promise<any> {
|
||||||
let results: Stars = [];
|
const results: Stars = await apiGetStar();
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// sorry.
|
|
||||||
const r = await paginate();
|
|
||||||
if (!r || r === null) break;
|
|
||||||
results = results.concat(r.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const sortedByLanguages = results.reduce(
|
const sortedByLanguages = results.reduce(
|
||||||
(acc: SortedLanguageList, val: Star) => {
|
(acc: SortedLanguageList, val: Star) => {
|
||||||
@@ -41,7 +35,16 @@ export async function main(): Promise<any> {
|
|||||||
|
|
||||||
const markdown: string = await generateMd(rendered);
|
const markdown: string = await generateMd(rendered);
|
||||||
|
|
||||||
await pushNewFile(markdown);
|
await pushNewFiles([
|
||||||
|
{
|
||||||
|
filename: MARKDOWN_FILENAME,
|
||||||
|
data: markdown,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filename: 'data.json',
|
||||||
|
data: JSON.stringify(sortedByLanguages, null, 2),
|
||||||
|
},
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function run(): Promise<any> {
|
export async function run(): Promise<any> {
|
||||||
|
@@ -5,14 +5,11 @@ export type SortedLanguageList = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type PaginationLink = {
|
export type PaginationLink = {
|
||||||
next: string;
|
uri: string;
|
||||||
last: string | undefined | null;
|
rel: 'next' | 'last' | 'prev' | 'first';
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Stars = Endpoints['GET /user/starred']['response']['data'];
|
export type Stars = Endpoints['GET /user/starred']['response']['data'];
|
||||||
export type Star = Stars[number] | { language: string };
|
export type Star = Stars[number] | { language: string };
|
||||||
|
|
||||||
export type ApiGetStarResponse = {
|
export type ApiGetStarResponse = Stars;
|
||||||
links: PaginationLink;
|
|
||||||
data: Stars;
|
|
||||||
};
|
|
||||||
|
@@ -7,7 +7,7 @@ sinon.replace(core, 'getInput', sinon.fake());
|
|||||||
|
|
||||||
import GithubApi from '../src/api';
|
import GithubApi from '../src/api';
|
||||||
const GithubApiFake = sinon.fake((rul) => ({
|
const GithubApiFake = sinon.fake((rul) => ({
|
||||||
body: 'data',
|
body: [],
|
||||||
headers: {
|
headers: {
|
||||||
link:
|
link:
|
||||||
'<https://api.github.com/user/5617452/starred?page=2>; rel="next", <https://api.github.com/user/5617452/starred?page=2>; rel="last"',
|
'<https://api.github.com/user/5617452/starred?page=2>; rel="next", <https://api.github.com/user/5617452/starred?page=2>; rel="last"',
|
||||||
@@ -32,13 +32,11 @@ const writeFile = sinon.fake();
|
|||||||
sinon.replace(fsp, 'writeFile', writeFile);
|
sinon.replace(fsp, 'writeFile', writeFile);
|
||||||
|
|
||||||
import {
|
import {
|
||||||
isLastPage,
|
|
||||||
wait,
|
wait,
|
||||||
renderer,
|
renderer,
|
||||||
apiGetStar,
|
apiGetStar,
|
||||||
paginate,
|
|
||||||
generateMd,
|
generateMd,
|
||||||
pushNewFile,
|
pushNewFiles,
|
||||||
} from '../src/helpers';
|
} from '../src/helpers';
|
||||||
|
|
||||||
test('wait should wait', async (t) => {
|
test('wait should wait', async (t) => {
|
||||||
@@ -46,40 +44,15 @@ test('wait should wait', async (t) => {
|
|||||||
t.pass();
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('isLastPage', (t) => {
|
|
||||||
t.true(
|
|
||||||
isLastPage({
|
|
||||||
next: 'last',
|
|
||||||
last: 'last',
|
|
||||||
})
|
|
||||||
);
|
|
||||||
t.false(
|
|
||||||
isLastPage({
|
|
||||||
next: 'last',
|
|
||||||
last: undefined,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('renderer should render', async (t) => {
|
test('renderer should render', async (t) => {
|
||||||
const output = await renderer({ variable: 123 }, 'Test: <%= variable %>');
|
const output = await renderer({ variable: 123 }, 'Test: <%= variable %>');
|
||||||
t.is(output, 'Test: 123');
|
t.is(output, 'Test: 123');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('apiGetStar', async (t) => {
|
test('apiGetStar', async (t) => {
|
||||||
let { data, links } = await apiGetStar('url');
|
let stars = await apiGetStar('url');
|
||||||
t.true(GithubApiFake.called);
|
t.true(GithubApiFake.called);
|
||||||
t.is(data, 'data');
|
t.true(Array.isArray(stars));
|
||||||
t.deepEqual(links, {
|
|
||||||
last: 'https://api.github.com/user/5617452/starred?page=2',
|
|
||||||
next: 'https://api.github.com/user/5617452/starred?page=2',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('paginate', async (t) => {
|
|
||||||
await paginate();
|
|
||||||
const res = await paginate();
|
|
||||||
t.is(res, null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('generateMd should create TOC', async (t) => {
|
test('generateMd should create TOC', async (t) => {
|
||||||
@@ -97,10 +70,10 @@ test('generateMd should create TOC', async (t) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should push', async (t) => {
|
test('should push', async (t) => {
|
||||||
await pushNewFile('# title');
|
await pushNewFiles([{ filename: 'README.md', data: '# title' }]);
|
||||||
t.true(writeFile.calledWith('README.md', '# title'));
|
t.true(writeFile.called);
|
||||||
t.true(pull.called);
|
t.true(pull.called);
|
||||||
t.true(add.calledWith('README.md'));
|
t.true(add.called);
|
||||||
t.true(commit.calledWith('chore(README.md): updated README.md'));
|
t.true(commit.called);
|
||||||
t.true(push.called);
|
t.true(push.called);
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user