Skip to content
This repository has been archived by the owner on Jun 5, 2021. It is now read-only.

Commit

Permalink
feat: Use react for generating apge
Browse files Browse the repository at this point in the history
  • Loading branch information
floric committed Aug 2, 2020
1 parent b5e4c16 commit 1ced0ff
Show file tree
Hide file tree
Showing 24 changed files with 498 additions and 95 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This Github action generates custom metrics reports including the last releases

The example for the project itself can found at:

https://github.com/floric/repo-monitor-action
https://floric.github.io/repo-monitor-action/

## Usage

Expand Down
40 changes: 40 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const core = require("@actions/core");
const github_1 = require("./io/github");
const updater_1 = require("./template/updater");
async function runAction() {
try {
const context = github_1.getContext();
const key = core.getInput("key");
const value = core.getInput("value");
if (!key || Number.isNaN(Number.parseFloat(value))) {
throw new Error("Invalid arguments delivered");
}
const path = `data/values/${new Date().getUTCFullYear()}/${key}.json`;
const { releaseId, releaseYear } = await github_1.createOrUpdateRelease(context);
const { serializedData, existingSha } = await github_1.getContent(context, path);
let data;
if (!serializedData) {
core.info(`Called with new key "${key}", will create new file.`);
data = { key, type: "scalar", values: [] };
}
else {
core.info(`Extending existing metrics for "${key}"`);
data = JSON.parse(serializedData);
}
data.values.push({
value: Number.parseFloat(value),
timestamp: new Date().getTime(),
releaseId,
});
const content = JSON.stringify(data);
await github_1.createOrUpdateContent(context, path, content, existingSha);
await updater_1.updateTemplate(context, releaseYear);
core.info("Finished processing new metrics");
}
catch (error) {
core.setFailed(error.message);
}
}
runAction();
11 changes: 11 additions & 0 deletions dist/io/encoding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.toBase64 = exports.fromBase64 = void 0;
function fromBase64(content) {
return Buffer.from(content, "base64").toString("ascii");
}
exports.fromBase64 = fromBase64;
function toBase64(content) {
return Buffer.from(content).toString("base64");
}
exports.toBase64 = toBase64;
85 changes: 85 additions & 0 deletions dist/io/github.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createOrUpdateRelease = exports.getContext = exports.createOrUpdateContent = exports.getContent = void 0;
const core = require("@actions/core");
const github = require("@actions/github");
const encoding_1 = require("./encoding");
async function getContent(context, path) {
const { token, owner, repo, branch } = context;
try {
const octokit = github.getOctokit(token);
const res = await octokit.repos.getContent({
owner,
repo,
ref: branch,
branch,
path,
});
if ((res === null || res === void 0 ? void 0 : res.status) == 200) {
return {
serializedData: encoding_1.fromBase64(res.data.content),
existingSha: res.data.sha,
};
}
else {
core.warning(`Unexpected response code ${res === null || res === void 0 ? void 0 : res.status}`);
}
}
catch (err) {
core.error(`Reading from ${path} on ${context.branch} failed: ${err.message}`);
}
return { existingSha: null, serializedData: null };
}
exports.getContent = getContent;
async function createOrUpdateContent(context, path, content, existingSha) {
const { token, owner, repo, branch } = context;
const octokit = github.getOctokit(token);
await octokit.repos.createOrUpdateFileContents({
owner,
repo,
branch,
path,
content: encoding_1.toBase64(content),
sha: existingSha || undefined,
message: existingSha ? "Updated metrics" : "Created metrics",
});
}
exports.createOrUpdateContent = createOrUpdateContent;
function getContext() {
const token = core.getInput("token");
const { owner, repo } = github.context.repo;
const { sha: releaseId } = github.context;
const context = {
releaseId,
token,
owner,
repo,
branch: "gh-pages",
};
return context;
}
exports.getContext = getContext;
async function createOrUpdateRelease(context) {
const now = new Date();
const year = now.getUTCFullYear();
const release = {
id: context.releaseId,
timestamp: now.getTime(),
};
const path = `data/releases/${year}/releases.json`;
const { existingSha, serializedData } = await getContent(context, path);
let releaseYear;
if (!serializedData) {
core.info(`Creating year ${year} for new release`);
releaseYear = { releases: [], year };
}
else {
releaseYear = JSON.parse(serializedData);
core.info(`Extending year ${year} with ${releaseYear.releases.length} existing releases`);
}
releaseYear.releases.push(release);
await createOrUpdateContent(context, path, JSON.stringify(releaseYear), existingSha);
core.info(`Saved release ${release.id}`);
return { releaseYear, releaseId: release.id };
}
exports.createOrUpdateRelease = createOrUpdateRelease;
2 changes: 2 additions & 0 deletions dist/model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
12 changes: 12 additions & 0 deletions dist/template/components/Footer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Footer = void 0;
const React = require("react");
exports.Footer = ({ owner, repo, }) => (React.createElement("div", null,
React.createElement("p", { className: "text-center" },
"Generated $",
new Date().toLocaleString(),
" for $",
owner,
"/$",
repo)));
5 changes: 5 additions & 0 deletions dist/template/components/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Header = void 0;
const React = require("react");
exports.Header = () => (React.createElement("h1", { className: "text-6xl mb-2" }, "Header"));
30 changes: 30 additions & 0 deletions dist/template/components/Releases.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Releases = void 0;
const React = require("react");
const dayjs = require("dayjs");
const relativeTimePlugin = require("dayjs/plugin/relativeTime");
const SubHeader_1 = require("./SubHeader");
dayjs.extend(relativeTimePlugin);
const MAX_ITEMS = 20;
exports.Releases = ({ year }) => {
const newestReleases = year.releases
.sort((a, b) => b.timestamp - a.timestamp)
.slice(0, MAX_ITEMS);
return (React.createElement("div", null,
React.createElement(SubHeader_1.SubHeader, { header: "Releases" }),
React.createElement("table", { className: "table-auto w-full text-left" },
React.createElement("thead", null,
React.createElement("tr", { className: "bg-gray-800 text-gray-100" },
React.createElement("th", { className: "px-4 py-2" }, "#"),
React.createElement("th", { className: "px-4 py-2" }, "Date"),
React.createElement("th", { className: "px-4 py-2" }, "Commit"))),
React.createElement("tbody", { id: "tbl-releases-body" }, newestReleases.map((n, i) => (React.createElement("tr", { className: i % 2 == 0 ? "bg-gray-200" : "bg-gray-300" },
React.createElement("td", { className: "px-4 py-2" }, year.releases.length - i),
React.createElement("td", { className: "px-4 py-2" }, dayjs(n.timestamp).fromNow()),
React.createElement("td", { className: "px-4 py-2" }, n.id)))))),
MAX_ITEMS < year.releases.length ? (React.createElement("p", null,
"Only last ",
MAX_ITEMS,
" items shown.")) : null));
};
5 changes: 5 additions & 0 deletions dist/template/components/SubHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SubHeader = void 0;
const React = require("react");
exports.SubHeader = ({ header }) => (React.createElement("h2", { className: "text-xl mb-2 mt-8 font-bold" }, header));
7 changes: 7 additions & 0 deletions dist/template/components/Values.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Values = void 0;
const React = require("react");
const SubHeader_1 = require("./SubHeader");
exports.Values = () => (React.createElement("div", null,
React.createElement(SubHeader_1.SubHeader, { header: "Values" })));
6 changes: 6 additions & 0 deletions dist/template/components/layout/Page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Page = void 0;
const React = require("react");
exports.Page = ({ children }) => (React.createElement("div", { className: "bg-gray-100 text-gray-900 flex m-4 justify-center" },
React.createElement("div", { className: "w-full max-w-6xl" }, children)));
49 changes: 49 additions & 0 deletions dist/template/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generatePage = void 0;
const React = require("react");
const ReactDOM = require("react-dom/server");
const Footer_1 = require("./components/Footer");
const Header_1 = require("./components/Header");
const Releases_1 = require("./components/Releases");
const Values_1 = require("./components/Values");
const Page_1 = require("./components/layout/Page");
exports.generatePage = (releases, repo) => `<!DOCTYPE html>
<html>
<head>
<title>Metrics</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css"
integrity="sha256-Y4vGjLmrpriLD3X1h1YdyzE2icdiBsJHBXORYXlyDwM="
crossorigin="anonymous"
/>
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dayjs.min.js"
integrity="sha256-ORgF0pKrTKxau29bikHxGniNlpQtd9Ku1vbl5/m+mJE="
crossorigin="anonymous"
></script>
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/plugin/relativeTime.js"
integrity="sha256-tMJ/JI74gvcd/JCL4zekEwHfyHfT2XKUd5GAZn6fJOU="
crossorigin="anonymous"
></script>
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/Chart.min.js"
integrity="sha256-R4pqcOYV8lt7snxMQO/HSbVCFRPMdrhAFMH+vr9giYI="
crossorigin="anonymous"
></script>
<script>
dayjs.extend(window.dayjs_plugin_relativeTime);
</script>
</head>
<body>
${ReactDOM.renderToStaticMarkup(React.createElement(Page_1.Page, null,
React.createElement(Header_1.Header, null),
React.createElement(Releases_1.Releases, { year: releases }),
React.createElement(Values_1.Values, null),
React.createElement(Footer_1.Footer, { owner: repo.owner, repo: repo.repo })))}
</body>
</html>`;
15 changes: 15 additions & 0 deletions dist/template/updater.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateTemplate = void 0;
const core = require("@actions/core");
const github = require("@actions/github");
const github_1 = require("../io/github");
const page_1 = require("./page");
async function updateTemplate(context, releases) {
const { existingSha } = await github_1.getContent(context, "index.html");
const template = page_1.generatePage(releases, github.context.repo);
core.info(`Generated page successfully`);
await github_1.createOrUpdateContent(context, "index.html", template, existingSha);
core.info(`Updated page successfully`);
}
exports.updateTemplate = updateTemplate;
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@
},
"dependencies": {
"@actions/core": "^1.2.4",
"@actions/github": "^4.0.0"
"@actions/github": "^4.0.0",
"@types/react-dom": "^16.9.8",
"dayjs": "^1.8.31",
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"devDependencies": {
"@types/react": "^16.9.44",
"typescript": "^3.9.7"
}
}
12 changes: 12 additions & 0 deletions src/template/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from "react";

export const Footer: React.FC<{ repo: string; owner: string }> = ({
owner,
repo,
}) => (
<div>
<p className="text-center">
Generated ${new Date().toLocaleString()} for ${owner}/${repo}
</p>
</div>
);
5 changes: 5 additions & 0 deletions src/template/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as React from "react";

export const Header: React.FC<{}> = () => (
<h1 className="text-6xl mb-2">Header</h1>
);
43 changes: 43 additions & 0 deletions src/template/components/Releases.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as React from "react";
import * as dayjs from "dayjs";
import * as relativeTimePlugin from "dayjs/plugin/relativeTime";

import { SubHeader } from "./SubHeader";
import { ReleaseYear } from "../../model";

dayjs.extend(relativeTimePlugin);

const MAX_ITEMS = 20;

export const Releases: React.FC<{ year: ReleaseYear }> = ({ year }) => {
const newestReleases = year.releases
.sort((a, b) => b.timestamp - a.timestamp)
.slice(0, MAX_ITEMS);

return (
<div>
<SubHeader header="Releases" />
<table className="table-auto w-full text-left">
<thead>
<tr className="bg-gray-800 text-gray-100">
<th className="px-4 py-2">#</th>
<th className="px-4 py-2">Date</th>
<th className="px-4 py-2">Commit</th>
</tr>
</thead>
<tbody id="tbl-releases-body">
{newestReleases.map((n, i) => (
<tr className={i % 2 == 0 ? "bg-gray-200" : "bg-gray-300"}>
<td className="px-4 py-2">{year.releases.length - i}</td>
<td className="px-4 py-2">{dayjs(n.timestamp).fromNow()}</td>
<td className="px-4 py-2">{n.id}</td>
</tr>
))}
</tbody>
</table>
{MAX_ITEMS < year.releases.length ? (
<p>Only last {MAX_ITEMS} items shown.</p>
) : null}
</div>
);
};
5 changes: 5 additions & 0 deletions src/template/components/SubHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as React from "react";

export const SubHeader: React.FC<{ header: string }> = ({ header }) => (
<h2 className="text-xl mb-2 mt-8 font-bold">{header}</h2>
);
8 changes: 8 additions & 0 deletions src/template/components/Values.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as React from "react";
import { SubHeader } from "./SubHeader";

export const Values: React.FC<{}> = () => (
<div>
<SubHeader header="Values" />
</div>
);
7 changes: 7 additions & 0 deletions src/template/components/layout/Page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from "react";

export const Page: React.FC<{}> = ({ children }) => (
<div className="bg-gray-100 text-gray-900 flex m-4 justify-center">
<div className="w-full max-w-6xl">{children}</div>
</div>
);
Loading

0 comments on commit 1ced0ff

Please sign in to comment.