Skip to content

Instantly share code, notes, and snippets.

@the-vampiire
Created June 10, 2019 19:45
Show Gist options
  • Select an option

  • Save the-vampiire/d0cfc1b31f2cb8139f16187bba0f7872 to your computer and use it in GitHub Desktop.

Select an option

Save the-vampiire/d0cfc1b31f2cb8139f16187bba0f7872 to your computer and use it in GitHub Desktop.
github clone a single file or entire directory. short script with no dependencies
const fs = require("fs");
const https = require("https");
const fetch = url =>
new Promise((res, rej) => {
try {
https.get(url, res);
} catch (error) {
rej(error);
}
});
const isString = sourcePath => sourcePath.length !== undefined;
const getSourcePath = sourcePath =>
isString(sourcePath) ? sourcePath : sourcePath.dirPath;
const buildFilePath = (outputPath, sourcePath) =>
outputPath.concat(
`/${getSourcePath(sourcePath)
.split("/")
.pop()}`,
);
const buildURLPath = config => {
const { owner, repo, branch, urlBase, sourcePath } = config;
return `${urlBase}/${owner}/${repo}/${branch}/${getSourcePath(sourcePath)}`;
};
const streamResponseToFile = (response, config, directoryFile = null) => {
const { outputPath, sourcePath } = config;
const outputFile = buildFilePath(outputPath, sourcePath).concat(
directoryFile ? `/${directoryFile}` : "",
);
return response.pipe(fs.createWriteStream(outputFile));
};
/**
* fetch and write a single file from a GitHub repo
* @param {{ owner: string, repo: string, branch: string, sourcePath: string, outputPath: string }} config
*/
const cloneFile = (config, directoryFile = null) =>
fetch(buildURLPath(config).concat(directoryFile ? `/${directoryFile}` : ""))
.then(res =>
streamResponseToFile(res, config, directoryFile && `/${directoryFile}`),
)
.catch(console.error);
/**
* fetch and write multiple files from a directory in a GitHub repo
* - if sourcePath.index is true the index.js file in the directory is cloned as well
*
* @param {{ url: string, owner: string, repo: string, branch: string,
* sourcePath: { index: boolean, dirPath: string, files: [...string]} }} config
*/
const cloneDirectory = async config => {
const { outputPath, sourcePath } = config;
const dirPath = buildFilePath(outputPath, sourcePath);
await fs.promises
.access(dirPath)
.then(exists => !exists && fs.promises.mkdir(dirPath))
.catch(console.error);
return Promise.all(
sourcePath.files
.concat(sourcePath.index ? "index.js" : [])
.map(directoryFile => cloneFile(config, directoryFile)),
).catch(console.error);
};
module.exports = {
cloneFile,
cloneDirectory,
};
@the-vampiire
Copy link
Author

single file

const config = {
  owner: "org / username",
  repo: "repo name",
  branch: "branch name",
  sourcePath: "path/to/file/in/repo",
  outputPath: "./relative/path or /absolute/path/to/output",
  urlBase: "https://raw.githubusercontent.com",
};

cloneFile(config);

files in a directory

const config = {
  owner: "org / username",
  repo: "repo name",
  branch: "branch name",
  sourcePath: {
    index: true, // clones the index.js file in the directory
    dirPath: "path/to/directory/in/repo",
    files: ["file-name.js", "other-file.js", ...],
  },
  outputPath: "./relative/path or /absolute/path/to/output",
  urlBase: "https://raw.githubusercontent.com",
};

cloneDirectory(config);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment