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 21, 2022
1 parent caa1f8d commit c2eee3e
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 41 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
86 changes: 70 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,43 @@ 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;
}

for (const [, data] of Object.entries(gist.data.files)) {
const fileName = data?.filename;
const content = data?.content;

if (fileName === undefined || content === undefined) {
continue;
}
if (this.VALID_FILES.includes(fileName)) {
gistContents.push([fileName, content]);
}
}

return this.fromEntries(gistContents);
}

public async fromFolder(source: string): Promise<Fiddle> {
Expand All @@ -55,23 +89,43 @@ 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`);
}
// This has to be done because octokit expects an owner and repo
// params to be passed instead of just HTTPs/SSH git link.
const owner = match[4];
const repo = match[5];
const repoContents: [string, string][] = [];

d({ url, owner, repo });
const octokit = getOctokit(process.env.FIDDLE_CORE_GITHUB_TOKEN);
const folder = await octokit.repos.getContent({
owner,
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;
}
10 changes: 9 additions & 1 deletion tests/fiddle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,15 @@ describe('FiddleFactory', () => {
expect(fiddle).toBe(fiddleIn);
});

it.todo('reads fiddles from git repositories');
it('reads fiddles from git repositories', async () => {
const repo = 'https://github.com/electron/electron-quick-start.git';
const fiddle = await fiddleFactory.create(repo);
expect(fiddle).toBeTruthy();
expect(fs.existsSync(fiddle!.mainPath)).toBe(true);
expect(path.basename(fiddle!.mainPath)).toBe('main.js');
expect(path.dirname(path.dirname(fiddle!.mainPath))).toBe(fiddleDir);
});

it.todo('refreshes the cache if given a previously-cached git repository');

it('returns undefined for unknown input', async () => {
Expand Down
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 c2eee3e

Please sign in to comment.