Merge pull request #98 from pomber/providers

Refactor Git Providers
This commit is contained in:
Rodrigo Pombo 2019-02-19 00:09:00 -03:00 committed by GitHub
commit a453fc4266
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 848 additions and 1834 deletions

View File

@ -1,12 +1,11 @@
#!/usr/bin/env node
const runServer = require("./server");
const getCommits = require("./git");
const fs = require("fs");
const path = process.argv[2];
let path = process.argv[2] || "./.";
if (!path || path === "--help") {
if (path === "--help") {
console.log(`Usage:
githistory some/file.ext
@ -19,6 +18,4 @@ if (!fs.existsSync(path)) {
process.exit();
}
const commitsPromise = getCommits(path);
runServer(path, commitsPromise);
runServer(path);

View File

@ -1,47 +1,58 @@
const execa = require("execa");
const pather = require("path");
async function getCommits(path) {
async function getCommits(path, last, before) {
const format = `{"hash":"%h","author":{"login":"%aN"},"date":"%ad"},`;
const { stdout } = await execa("git", [
"log",
// "--follow",
"--reverse",
`--pretty=format:${format}`,
"--date=iso",
"--",
path
]);
const { stdout } = await execa(
"git",
[
"log",
`--max-count=${before ? last + 1 : last}`,
`--pretty=format:${format}`,
"--date=iso",
`${before || "HEAD"}`,
"--",
pather.basename(path)
],
{ cwd: pather.dirname(path) }
);
const json = `[${stdout.slice(0, -1)}]`;
const messagesOutput = await execa("git", [
"log",
// "--follow",
"--reverse",
`--pretty=format:%s`,
"--",
path
]);
const messagesOutput = await execa(
"git",
[
"log",
`--max-count=${last}`,
`--pretty=format:%s`,
`${before || "HEAD"}`,
"--",
pather.basename(path)
],
{ cwd: pather.dirname(path) }
);
const messages = messagesOutput.stdout.replace('"', '\\"').split(/\r?\n/);
const result = JSON.parse(json)
.map((commit, i) => ({
...commit,
date: new Date(commit.date),
message: messages[i]
}))
.slice(-20);
const result = JSON.parse(json).map((commit, i) => ({
...commit,
date: new Date(commit.date),
message: messages[i]
}));
return result;
return before ? result.slice(1) : result;
}
async function getContent(commit, path) {
const { stdout } = await execa("git", ["show", `${commit.hash}:${path}`]);
const { stdout } = await execa(
"git",
["show", `${commit.hash}:./${pather.basename(path)}`],
{ cwd: pather.dirname(path) }
);
return stdout;
}
module.exports = async function(path) {
const commits = await getCommits(path);
module.exports = async function(path, last, before) {
const commits = await getCommits(path, last, before);
await Promise.all(
commits.map(async commit => {
commit.content = await getContent(commit, path);

View File

@ -27,15 +27,18 @@
"dependencies": {
"execa": "^1.0.0",
"get-port": "^4.1.0",
"koa": "^2.7.0",
"koa-router": "^7.4.0",
"koa-static": "^5.0.0",
"open": "^0.0.5",
"serve-handler": "^5.0.8"
},
"scripts": {
"build-site": "cd .. && yarn build && rm -fr cli/site/ && cp -r build/ cli/site/",
"build-site": "cd .. && cross-env REACT_APP_GIT_PROVIDER=cli yarn build && rm -fr cli/site/ && cp -r build/ cli/site/",
"build": "yarn build-site",
"ls-package": "npm pack && tar -xvzf *.tgz && rm -rf package *.tgz"
},
"devDependencies": {
"np": "^4.0.2"
"cross-env": "^5.2.0"
}
}

View File

@ -1,52 +1,35 @@
const fs = require("fs");
const serve = require("koa-static");
const Koa = require("koa");
const pather = require("path");
const getCommits = require("./git");
const getPort = require("get-port");
const open = require("open");
const handler = require("serve-handler");
const http = require("http");
const pather = require("path");
const router = require("koa-router")();
const sitePath = pather.join(__dirname, "site/");
const indexPath = pather.join(sitePath, "index.html");
function getIndex() {
return new Promise((resolve, reject) => {
fs.readFile(indexPath, "utf8", (err, data) => {
if (err) reject(err);
resolve(data);
});
});
}
router.get("/api/commits", async ctx => {
const query = ctx.query;
const { path, last = 10, before = null } = query;
const indexPromise = getIndex();
const commits = await getCommits(path, last, before);
const portPromise = getPort({ port: 3000 });
ctx.body = commits;
});
module.exports = async function runServer(path, commitsPromise) {
const server = http.createServer((request, response) => {
if (request.url === "/") {
Promise.all([indexPromise, commitsPromise]).then(([index, commits]) => {
const newIndex = index.replace(
"<script>window._CLI=null</script>",
`<script>/*<!--*/window._CLI={commits:${JSON.stringify(
commits
)},path:'${path}'}/*-->*/</script>`
);
var headers = { "Content-Type": "text/html" };
response.writeHead(200, headers);
response.write(newIndex);
response.end();
});
} else {
return handler(request, response, { public: sitePath });
}
});
const app = new Koa();
app.use(router.routes());
app.use(serve(sitePath));
app.on("error", err => {
console.error("Server error", err);
console.error(
"Let us know of the error at https://github.com/pomber/git-history/issues"
);
});
const port = await portPromise;
return new Promise(resolve => {
server.listen(port, () => {
console.log("Running at http://localhost:" + port);
open("http://localhost:" + port);
});
});
module.exports = async function runServer(path) {
const port = await getPort({ port: 5000 });
app.listen(port);
console.log("Running at http://localhost:" + port);
open(`http://localhost:${port}/?path=${encodeURIComponent(path)}`);
};

File diff suppressed because it is too large Load Diff

View File

@ -59,10 +59,6 @@
</style>
</head>
<body>
<!-- when served with githistory cli, commits are injected here: -->
<script>
window._CLI = null;
</script>
<div id="root"></div>
<footer>
<a href="https://github.com/pomber/git-history">Git History</a><br />by

View File

@ -1,6 +1,5 @@
import React, { useState, useEffect } from "react";
import { getLanguage, loadLanguage } from "./language-detector";
import { auth, isLoggedIn, getCommits } from "./github";
export function Center({ children }) {
return (
@ -29,7 +28,7 @@ export function Loading({ repo, path }) {
);
}
export function Error({ error }) {
export function Error({ error, gitProvider }) {
if (error.status === 403) {
return (
<Center>
@ -37,7 +36,7 @@ export function Error({ error }) {
GitHub API rate limit exceeded for your IP (60 requests per hour).
</p>
<p>Sign in with GitHub for more:</p>
<GitHubButton onClick={login} />
<GitHubButton onClick={gitProvider.logIn} />
</Center>
);
}
@ -46,10 +45,10 @@ export function Error({ error }) {
return (
<Center>
<p>File not found.</p>
{!isLoggedIn() && (
{gitProvider.isLoggedIn && !gitProvider.isLoggedIn() && (
<React.Fragment>
<p>Is it from a private repo? Sign in with GitHub:</p>
<GitHubButton onClick={login} />
<GitHubButton onClick={gitProvider.login} />
</React.Fragment>
)}
</Center>
@ -92,7 +91,7 @@ function GitHubButton({ onClick }) {
);
}
function useLoader(promiseFactory, deps) {
export function useLoader(promiseFactory, deps) {
const [state, setState] = useState({
data: null,
loading: true,
@ -127,37 +126,8 @@ export function useLanguageLoader(path) {
}, [path]);
}
export function useCommitsFetcher({ repo, sha, path }) {
return useLoader(async () => getCommits(repo, sha, path), [repo, sha, path]);
}
export function useDocumentTitle(title) {
useEffect(() => {
document.title = title;
}, [title]);
}
export function getUrlParams() {
const [
,
owner,
reponame,
action,
sha,
...paths
] = window.location.pathname.split("/");
if (action !== "commits" && action !== "blob") {
return [];
}
return [owner + "/" + reponame, sha, "/" + paths.join("/")];
}
function login() {
auth()
.then(data => {
window.location.reload(false);
})
.catch(console.error);
}

View File

@ -1,76 +1,91 @@
import React from "react";
import React, { useState, useEffect } from "react";
import History from "./history";
import Landing from "./landing";
import {
getUrlParams,
useLanguageLoader,
useCommitsFetcher,
useDocumentTitle,
Loading,
Error
} from "./app-helpers";
const cli = window._CLI;
import getGitProvider from "./git-providers/providers";
export default function App() {
if (cli) {
return <CliApp data={cli} />;
}
const gitProvider = getGitProvider();
const [repo, sha, path] = getUrlParams();
if (!repo) {
if (gitProvider.showLanding()) {
return <Landing />;
} else {
return <GitHubApp repo={repo} sha={sha} path={path} />;
return <InnerApp gitProvider={gitProvider} />;
}
}
function CliApp({ data }) {
let { commits, path } = data;
function InnerApp({ gitProvider }) {
const path = gitProvider.getPath();
const fileName = path.split("/").pop();
useDocumentTitle(`Git History - ${fileName}`);
commits = commits.map(commit => ({ ...commit, date: new Date(commit.date) }));
const [lang, loading, error] = useLanguageLoader(path);
if (error) {
return <Error error={error} />;
}
if (loading) {
return <Loading path={path} />;
}
return <History commits={commits} language={lang} />;
}
function GitHubApp({ repo, sha, path }) {
const fileName = path.split("/").pop();
useDocumentTitle(`Git History - ${fileName}`);
const [lang, langLoading, langError] = useLanguageLoader(path);
const [commits, commitsLoading, commitsError] = useCommitsFetcher({
repo,
sha,
const [commits, commitsLoading, commitsError, loadMore] = useCommitsLoader(
gitProvider,
path
});
);
const [lang, langLoading, langError] = useLanguageLoader(path);
const loading = langLoading || commitsLoading;
const error = langError || commitsError;
if (error) {
return <Error error={error} />;
return <Error error={error} gitProvider={gitProvider} />;
}
if (loading) {
return <Loading repo={repo} path={path} />;
if (!commits && loading) {
return <Loading path={path} />;
}
if (!commits.length) {
return <Error error={{ status: 404 }} />;
return <Error error={{ status: 404 }} gitProvider={gitProvider} />;
}
return <History commits={commits} language={lang} />;
return <History commits={commits} language={lang} loadMore={loadMore} />;
}
function useCommitsLoader(gitProvider, path) {
const [state, setState] = useState({
data: null,
loading: true,
error: null,
last: 10,
noMore: false
});
const loadMore = () => {
setState(old => {
const shouldFetchMore = !old.loading && !old.noMore;
return shouldFetchMore
? { ...old, last: old.last + 10, loading: true }
: old;
});
};
useEffect(() => {
gitProvider
.getCommits(path, state.last)
.then(data => {
setState(old => ({
data,
loading: false,
error: false,
last: old.last,
noMore: data.length < old.last
}));
})
.catch(error => {
setState({
loading: false,
error
});
});
}, [path, state.last]);
return [state.data, state.loading, state.error, loadMore];
}

View File

@ -68,6 +68,7 @@ export function parseLines(codes, language) {
}
export function getSlides(codes, language) {
// codes are in reverse cronological order
const lines = parseLines(codes, language);
// console.log("lines", lines);
return codes.map((_, slideIndex) => {
@ -75,9 +76,9 @@ export function getSlides(codes, language) {
.map((line, lineIndex) => ({
content: line.content,
tokens: line.tokens,
left: line.slides.includes(slideIndex - 1),
left: line.slides.includes(slideIndex + 1),
middle: line.slides.includes(slideIndex),
right: line.slides.includes(slideIndex + 1),
right: line.slides.includes(slideIndex - 1),
key: lineIndex
}))
.filter(line => line.middle || line.left || line.right);

106
src/duotoneLight.js Normal file
View File

@ -0,0 +1,106 @@
// Duotone Light
// Author: Simurai, adapted from DuoTone themes for Atom (http://simurai.com/projects/2016/01/01/duotone-themes)
// Conversion: Bram de Haan (http://atelierbram.github.io/Base2Tone-prism/output/prism/prism-base2tone-evening-dark.css)
// Generated with Base16 Builder (https://github.com/base16-builder/base16-builder)
var theme /*: PrismTheme */ = {
plain: {
backgroundColor: "#faf8f5",
color: "#728fcb"
},
styles: [
{
types: ["comment", "prolog", "doctype", "cdata", "punctuation"],
style: {
color: "#b6ad9a"
}
},
{
types: ["namespace"],
style: {
opacity: 0.7
}
},
{
types: ["tag", "operator", "number"],
style: {
color: "#063289"
}
},
{
types: ["property", "function"],
style: {
color: "#b29762"
}
},
{
types: ["tag-id", "selector", "atrule-id"],
style: {
color: "#2d2006"
}
},
{
types: ["attr-name"],
style: {
color: "#896724"
}
},
{
types: [
"boolean",
"string",
"entity",
"url",
"attr-value",
"keyword",
"control",
"directive",
"unit",
"statement",
"regex",
"at-rule"
],
style: {
color: "#728fcb"
}
},
{
types: ["placeholder", "variable"],
style: {
color: "#93abdc"
}
},
{
types: ["deleted"],
style: {
textDecorationLine: "line-through"
}
},
{
types: ["inserted"],
style: {
textDecorationLine: "underline"
}
},
{
types: ["italic"],
style: {
fontStyle: "italic"
}
},
{
types: ["important", "bold"],
style: {
fontWeight: "bold"
}
},
{
types: ["important"],
style: {
color: "#896724"
}
}
]
};
module.exports = theme;

View File

@ -0,0 +1,24 @@
function getPath() {
return new URLSearchParams(window.location.search).get("path");
}
function showLanding() {
return false;
}
async function getCommits(path, last) {
// TODO cache
const response = await fetch(
`/api/commits?path=${encodeURIComponent(path)}&last=${last}`
);
const commits = await response.json();
commits.forEach(c => (c.date = new Date(c.date)));
return commits;
}
export default {
showLanding,
getPath,
getCommits
};

View File

@ -0,0 +1,124 @@
import netlify from "netlify-auth-providers";
import { Base64 } from "js-base64";
const TOKEN_KEY = "github-token";
function getHeaders() {
const token = window.localStorage.getItem(TOKEN_KEY);
return token ? { Authorization: `bearer ${token}` } : {};
}
function isLoggedIn() {
return !!window.localStorage.getItem(TOKEN_KEY);
}
async function getContent(repo, sha, path) {
const contentResponse = await fetch(
`https://api.github.com/repos/${repo}/contents${path}?ref=${sha}`,
{ headers: getHeaders() }
);
if (!contentResponse.ok) {
throw contentResponse;
}
const contentJson = await contentResponse.json();
const content = Base64.decode(contentJson.content);
return { content, url: contentJson.html_url };
}
function getUrlParams() {
const [
,
owner,
reponame,
action,
sha,
...paths
] = window.location.pathname.split("/");
if (action !== "commits" && action !== "blob") {
return [];
}
return [owner + "/" + reponame, sha, "/" + paths.join("/")];
}
function getPath() {
const [, , path] = getUrlParams();
return path;
}
function showLanding() {
const [repo, ,] = getUrlParams();
return !repo;
}
const cache = {};
async function getCommits(path, last) {
const [repo, sha] = getUrlParams();
if (!cache[path]) {
const commitsResponse = await fetch(
`https://api.github.com/repos/${repo}/commits?sha=${sha}&path=${path}`,
{ headers: getHeaders() }
);
if (!commitsResponse.ok) {
throw commitsResponse;
}
const commitsJson = await commitsResponse.json();
cache[path] = commitsJson.map(commit => ({
sha: commit.sha,
date: new Date(commit.commit.author.date),
author: {
login: commit.author ? commit.author.login : commit.commit.author.name,
avatar: commit.author
? commit.author.avatar_url
: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
},
commitUrl: commit.html_url,
message: commit.commit.message
}));
}
const commits = cache[path].slice(0, last);
await Promise.all(
commits.map(async commit => {
if (!commit.content) {
const info = await getContent(repo, commit.sha, path);
commit.content = info.content;
commit.fileUrl = info.url;
}
})
);
return commits;
}
function logIn() {
// return new Promise((resolve, reject) => {
var authenticator = new netlify({
site_id: "ccf3a0e2-ac06-4f37-9b17-df1dd41fb1a6"
});
authenticator.authenticate({ provider: "github", scope: "repo" }, function(
err,
data
) {
if (err) {
console.error(err);
return;
}
window.localStorage.setItem(TOKEN_KEY, data.token);
window.location.reload(false);
});
// });
}
export default {
showLanding,
getPath,
getCommits,
logIn,
isLoggedIn
};

View File

@ -0,0 +1,14 @@
import cliProvider from "./cli-provider";
import githubProvider from "./github-provider";
import vscodeProvider from "./vscode-provider";
export default function getGitProvider() {
switch (process.env.REACT_APP_GIT_PROVIDER) {
case "cli":
return cliProvider;
case "vscode":
return vscodeProvider;
default:
return githubProvider;
}
}

View File

@ -0,0 +1,37 @@
const vscode = window.vscode;
function getPath() {
return window._PATH;
}
function showLanding() {
return false;
}
function getCommits(path, last) {
return new Promise((resolve, reject) => {
window.addEventListener(
"message",
event => {
const commits = event.data;
commits.forEach(c => (c.date = new Date(c.date)));
resolve(commits);
},
{ once: true }
);
vscode.postMessage({
command: "commits",
params: {
path,
last
}
});
});
}
export default {
showLanding,
getPath,
getCommits
};

View File

@ -1,83 +0,0 @@
import netlify from "netlify-auth-providers";
import { Base64 } from "js-base64";
const TOKEN_KEY = "github-token";
function getHeaders() {
const token = window.localStorage.getItem(TOKEN_KEY);
return token ? { Authorization: `bearer ${token}` } : {};
}
export function isLoggedIn() {
return !!window.localStorage.getItem(TOKEN_KEY);
}
async function getContent(repo, sha, path) {
const contentResponse = await fetch(
`https://api.github.com/repos/${repo}/contents${path}?ref=${sha}`,
{ headers: getHeaders() }
);
if (!contentResponse.ok) {
throw contentResponse;
}
const contentJson = await contentResponse.json();
const content = Base64.decode(contentJson.content);
return { content, url: contentJson.html_url };
}
export async function getCommits(repo, sha, path, top = 10) {
const commitsResponse = await fetch(
`https://api.github.com/repos/${repo}/commits?sha=${sha}&path=${path}`,
{ headers: getHeaders() }
);
if (!commitsResponse.ok) {
throw commitsResponse;
}
const commitsJson = await commitsResponse.json();
const commits = commitsJson
.slice(0, top)
.map(commit => ({
sha: commit.sha,
date: new Date(commit.commit.author.date),
author: {
login: commit.author ? commit.author.login : commit.commit.author.name,
avatar: commit.author
? commit.author.avatar_url
: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
},
commitUrl: commit.html_url,
message: commit.commit.message
}))
.sort(function(a, b) {
return a.date - b.date;
});
await Promise.all(
commits.map(async commit => {
const info = await getContent(repo, commit.sha, path);
commit.content = info.content;
commit.fileUrl = info.url;
})
);
return commits;
}
export function auth() {
return new Promise((resolve, reject) => {
var authenticator = new netlify({
site_id: "ccf3a0e2-ac06-4f37-9b17-df1dd41fb1a6"
});
authenticator.authenticate({ provider: "github", scope: "repo" }, function(
err,
data
) {
if (err) {
reject(err);
}
window.localStorage.setItem(TOKEN_KEY, data.token);
resolve(data);
});
});
}

View File

@ -69,7 +69,7 @@ function CommitInfo({ commit, move, onClick }) {
function CommitList({ commits, currentIndex, selectCommit }) {
const mouseWheelEvent = e => {
e.preventDefault();
selectCommit(currentIndex + (e.deltaX + e.deltaY) / 100);
selectCommit(currentIndex - (e.deltaX + e.deltaY) / 100);
};
return (
<div
@ -87,7 +87,7 @@ function CommitList({ commits, currentIndex, selectCommit }) {
{commits.map((commit, commitIndex) => (
<CommitInfo
commit={commit}
move={commitIndex - currentIndex}
move={currentIndex - commitIndex}
key={commitIndex}
onClick={() => selectCommit(commitIndex)}
/>
@ -96,20 +96,26 @@ function CommitList({ commits, currentIndex, selectCommit }) {
);
}
export default function History({ commits, language }) {
export default function History({ commits, language, loadMore }) {
const codes = commits.map(commit => commit.content);
const slideLines = getSlides(codes, language);
return <Slides slideLines={slideLines} commits={commits} />;
return (
<Slides slideLines={slideLines} commits={commits} loadMore={loadMore} />
);
}
function Slides({ commits, slideLines }) {
const [current, target, setTarget] = useSliderSpring(commits.length - 1);
const setClampedTarget = newTarget =>
function Slides({ commits, slideLines, loadMore }) {
const [current, target, setTarget] = useSliderSpring(0);
const setClampedTarget = newTarget => {
setTarget(Math.min(commits.length - 0.75, Math.max(-0.25, newTarget)));
if (newTarget >= commits.length - 5) {
loadMore();
}
};
const index = Math.round(current);
const nextSlide = () => setClampedTarget(Math.round(target + 0.51));
const prevSlide = () => setClampedTarget(Math.round(target - 0.51));
const nextSlide = () => setClampedTarget(Math.round(target - 0.51));
const prevSlide = () => setClampedTarget(Math.round(target + 0.51));
useEffect(() => {
document.body.onkeydown = function(e) {
if (e.keyCode === 39) {
@ -130,7 +136,7 @@ function Slides({ commits, slideLines }) {
selectCommit={index => setClampedTarget(index)}
/>
<Swipeable onSwipedLeft={nextSlide} onSwipedRight={prevSlide}>
<Slide time={current - index} lines={slideLines[index]} />
<Slide time={index - current} lines={slideLines[index]} />
</Swipeable>
</React.Fragment>
);

View File

@ -1,6 +1,5 @@
import React from "react";
import demo from "./demo.gif";
import { Center } from "./app-helpers";
export default function Landing() {
const url = `${window.location.protocol}//${
@ -74,6 +73,7 @@ export default function Landing() {
<img
src="https://opencollective.com/git-history/donate/button.png?color=white"
width="300"
alt="donate"
/>
</a>
</div>

View File

@ -43,28 +43,37 @@ function activate(context) {
);
const index = fs.readFileSync(indexPath, "utf-8");
const newIndex = index
.replace(
"<body>",
`<body><script>/*<!--*/window.vscode=acquireVsCodeApi();window._PATH='${currentPath}'/*-->*/</script>`
)
.replace(
"<head>",
`<head><base href="${vscode.Uri.file(
path.join(context.extensionPath, "site")
).with({
scheme: "vscode-resource"
})}/"/>`
);
getCommits(currentPath)
.then(commits => {
const newIndex = index
.replace(
"<script>window._CLI=null</script>",
`<script>/*<!--*/window._CLI={commits:${JSON.stringify(
commits
)},path:'${currentPath}'}/*-->*/</script>`
)
.replace(
"<head>",
`<head><base href="${vscode.Uri.file(
path.join(context.extensionPath, "site")
).with({
scheme: "vscode-resource"
})}/"/>`
);
panel.webview.html = newIndex;
panel.webview.html = newIndex;
})
.catch(console.error);
panel.webview.onDidReceiveMessage(
message => {
switch (message.command) {
case "commits":
const { path, last = 15, before = null } = message.params;
getCommits(path, last, before)
.then(commits => {
panel.webview.postMessage(commits);
})
.catch(console.error);
}
},
undefined,
context.subscriptions
);
} catch (e) {
console.error(e);
throw e;

View File

@ -1,16 +1,16 @@
const execa = require("execa");
const pather = require("path");
async function getCommits(path) {
async function getCommits(path, last, before) {
const format = `{"hash":"%h","author":{"login":"%aN"},"date":"%ad"},`;
const { stdout } = await execa(
"git",
[
"log",
// "--follow",
"--reverse",
`--max-count=${before ? last + 1 : last}`,
`--pretty=format:${format}`,
"--date=iso",
`${before || "HEAD"}`,
"--",
pather.basename(path)
],
@ -22,9 +22,9 @@ async function getCommits(path) {
"git",
[
"log",
// "--follow",
"--reverse",
`--max-count=${last}`,
`--pretty=format:%s`,
`${before || "HEAD"}`,
"--",
pather.basename(path)
],
@ -33,15 +33,13 @@ async function getCommits(path) {
const messages = messagesOutput.stdout.replace('"', '\\"').split(/\r?\n/);
const result = JSON.parse(json)
.map((commit, i) => ({
...commit,
date: new Date(commit.date),
message: messages[i]
}))
.slice(-20);
const result = JSON.parse(json).map((commit, i) => ({
...commit,
date: new Date(commit.date),
message: messages[i]
}));
return result;
return before ? result.slice(1) : result;
}
async function getContent(commit, path) {
@ -53,8 +51,8 @@ async function getContent(commit, path) {
return stdout;
}
module.exports = async function(path) {
const commits = await getCommits(path);
module.exports = async function(path, last, before) {
const commits = await getCommits(path, last, before);
await Promise.all(
commits.map(async commit => {
commit.content = await getContent(commit, path);

View File

@ -38,7 +38,7 @@
]
},
"scripts": {
"build-site": "cd .. && cross-env PUBLIC_URL=. yarn build && rm -fr vscode-ext/site/ && cp -r build/ vscode-ext/site/",
"build-site": "cd .. && cross-env PUBLIC_URL=. REACT_APP_GIT_PROVIDER=vscode yarn build && rm -fr vscode-ext/site/ && cp -r build/ vscode-ext/site/",
"build": " yarn build-site",
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "node ./node_modules/vscode/bin/test",

17
vscode-ext/test-git.js Normal file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env node
// node test-git.js extension.js 2 94c91d9
const getCommits = require("./git");
const [, , path, last, before] = process.argv;
getCommits(path, last, before).then(cs =>
console.log(
cs
.map(c => {
return `${c.hash} ${c.date.toDateString()} ${c.message}`;
})
.join("\n")
)
);