Skip to content

Commit

Permalink
feat: replace simple-git with octokit to load fiddle
Browse files Browse the repository at this point in the history
  • Loading branch information
aryanshridhar committed Oct 19, 2022
1 parent caa1f8d commit 1db31f2
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 40 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@
},
"dependencies": {
"@electron/get": "^2.0.0",
"@octokit/rest": "^19.0.4",
"debug": "^4.3.3",
"env-paths": "^2.2.1",
"extract-zip": "^2.0.1",
"fs-extra": "^10.0.0",
"getos": "^3.2.1",
"node-fetch": "^2.6.1",
"semver": "^7.3.5",
"simple-git": "^2.48.0"
"semver": "^7.3.5"
},
"devDependencies": {
"@continuous-auth/semantic-release-npm": "^3.0.0",
Expand Down
85 changes: 69 additions & 16 deletions src/fiddle.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as fs from 'fs-extra';
import * as path from 'path';
import debug from 'debug';
import simpleGit from 'simple-git';
import fetch from 'node-fetch';
import { createHash } from 'crypto';

import { DefaultPaths } from './paths';
import { getOctokit } from './utils/octokit';

function hashString(str: string): string {
const md5sum = createHash('md5');
Expand Down Expand Up @@ -32,10 +33,41 @@ export class Fiddle {
export type FiddleSource = Fiddle | string | Iterable<[string, string]>;

export class FiddleFactory {
private readonly VALID_FILES: Array<string> = [
'main.js',
'renderer.js',
'index.html',
'preload.js',
'styles.css',
];
// Thanks to https://serverfault.com/a/917253
private readonly GITHUB_URL_REGEX = new RegExp(
'^(https|git)(://|@)([^/:]+)[/:]([^/:]+)/(.+).git$',
);

constructor(private readonly fiddles: string = DefaultPaths.fiddles) {}

public async fromGist(gistId: string): Promise<Fiddle> {
return this.fromRepo(`https://gist.github.com/${gistId}.git`);
public async fromGist(gistId: string) {
// stores in format [filename, content]
const gistContents: [string, string][] = [];
const octokit = getOctokit(process.env.FIDDLE_CORE_GITHUB_TOKEN);
const gist = await octokit.gists.get({ gist_id: gistId });

if (gist.data.files === undefined) {
return;
}
// TODO(aryanshridhar): Avoid repetitive undefined/null checks
for (const [, data] of Object.entries(gist.data.files)) {
const fileName = data?.filename;
if (fileName !== undefined && this.VALID_FILES.includes(fileName)) {
if (data?.content === undefined) {
continue;
}
gistContents.push([fileName, data.content]);
}
}

return this.fromEntries(gistContents);
}

public async fromFolder(source: string): Promise<Fiddle> {
Expand All @@ -55,23 +87,44 @@ export class FiddleFactory {
return new Fiddle(path.join(folder, 'main.js'), source);
}

public async fromRepo(url: string, checkout = 'master'): Promise<Fiddle> {
public async fromRepo(url: string) {
const d = debug('fiddle-core:FiddleFactory:fromRepo');
const folder = path.join(this.fiddles, hashString(url));
d({ url, checkout, folder });

// get the repo
if (!fs.existsSync(folder)) {
d(`cloning "${url}" into "${folder}"`);
const git = simpleGit();
await git.clone(url, folder, { '--depth': 1 });
const match = this.GITHUB_URL_REGEX.exec(url);
if (match === null) {
throw new Error(`Invalid github URL`);
}
// TODO (aryanshridhar): better error handling in case of array out
// of bounds (not sure). This has to be done because octokit expects
// an owner and repo keys to be passed instead of just git link.
const user = match[4];
const repo = match[5];
const repoContents: [string, string][] = [];

d({ url, user, repo });
const octokit = getOctokit(process.env.FIDDLE_CORE_GITHUB_TOKEN);
const folder = await octokit.repos.getContent({
owner: user,
repo: repo,
path: '.', // Look for in the base directory only
});

if (!Array.isArray(folder.data)) {
return;
}

const git = simpleGit(folder);
await git.checkout(checkout);
await git.pull('origin', checkout);
for (const file of folder.data) {
if (!this.VALID_FILES.includes(file.name)) {
continue;
}

if (file.download_url) {
const resp = await fetch(file.download_url);
const content = await resp.text();
repoContents.push([file.name, content]);
}
}

return new Fiddle(path.join(folder, 'main.js'), url);
return this.fromEntries(repoContents);
}

public async fromEntries(src: Iterable<[string, string]>): Promise<Fiddle> {
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
compareVersions,
} from './versions';
import { runFromCommandLine } from './command-line';
import { setGithubToken, removeGithubToken } from './utils/env';

export {
BaseVersions,
Expand All @@ -41,6 +42,8 @@ export {
TestResult,
Versions,
compareVersions,
setGithubToken,
removeGithubToken,
runFromCommandLine,
};

Expand Down
7 changes: 7 additions & 0 deletions src/utils/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function setGithubToken(githubToken: string) {
process.env.FIDDLE_CORE_GITHUB_TOKEN = githubToken;
}

export function removeGithubToken() {
delete process.env.FIDDLE_CORE_GITHUB_TOKEN;
}
20 changes: 20 additions & 0 deletions src/utils/octokit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Octokit } from '@octokit/rest';

let _octo: Octokit;
/**
* Returns a loaded Octokit. If state is passed and authentication
* is available, we'll token-authenticate.
* @returns {Octokit}
*/
export function getOctokit(token?: string): Octokit {
// It's possible to load Gists without being authenticated,
// but we get better rate limits when authenticated.
_octo =
_octo || token
? new Octokit({
auth: token,
})
: new Octokit();

return _octo;
}
23 changes: 1 addition & 22 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -789,18 +789,6 @@
"@types/yargs" "^16.0.0"
chalk "^4.0.0"

"@kwsites/file-exists@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@kwsites/file-exists/-/file-exists-1.1.1.tgz#ad1efcac13e1987d8dbaf235ef3be5b0d96faa99"
integrity sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==
dependencies:
debug "^4.1.1"

"@kwsites/promise-deferred@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz#8ace5259254426ccef57f3175bc64ed7095ed919"
integrity sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==

"@microsoft/[email protected]":
version "7.15.3"
resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.15.3.tgz#cf76deeeb2733d974da678f530c2dbaceb18a065"
Expand Down Expand Up @@ -1119,7 +1107,7 @@
node-fetch "^2.6.7"
universal-user-agent "^6.0.0"

"@octokit/rest@^19.0.0":
"@octokit/rest@^19.0.0", "@octokit/rest@^19.0.4":
version "19.0.4"
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-19.0.4.tgz#fd8bed1cefffa486e9ae46a9dc608ce81bcfcbdd"
integrity sha512-LwG668+6lE8zlSYOfwPj4FxWdv/qFXYBpv79TWIQEpBLKA9D/IMcWsF/U9RGpA3YqMVDiTxpgVpEW3zTFfPFTA==
Expand Down Expand Up @@ -6101,15 +6089,6 @@ signale@^1.2.1:
figures "^2.0.0"
pkg-conf "^2.1.0"

simple-git@^2.48.0:
version "2.48.0"
resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-2.48.0.tgz#87c262dba8f84d7b96bb3a713e9e34701c1f6e3b"
integrity sha512-z4qtrRuaAFJS4PUd0g+xy7aN4y+RvEt/QTJpR184lhJguBA1S/LsVlvE/CM95RsYMOFJG3NGGDjqFCzKU19S/A==
dependencies:
"@kwsites/file-exists" "^1.1.1"
"@kwsites/promise-deferred" "^1.1.1"
debug "^4.3.2"

sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
Expand Down

0 comments on commit 1db31f2

Please sign in to comment.