Skip to content

Commit

Permalink
Few minor improvements.
Browse files Browse the repository at this point in the history
  • Loading branch information
neonexus committed Oct 5, 2023
1 parent 3115888 commit fcc6923
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 25 deletions.
89 changes: 82 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# dzfg - Download Zipball From GitHub



## How to use

The idea of this package, is to make downloading / extracting / installing a GitHub repo's latest release a breeze. Both in the terminal, and programmatically if you are into that kind of thing...
The idea of this package, is to make downloading / extracting / installing a GitHub repo's latest release a breeze (without creating a new repo, or Git for that matter). Both in the terminal, and programmatically, if you are into that kind of thing...

### Terminal Usage

Expand All @@ -19,9 +21,12 @@ npx dzfg my-new-site neonexus/sails-react-bootstrap-webpack
#### A little more advanced...

You can disable the `npm install` after extraction:

`npx dzfg <new-folder> <github-repo> <no-npm?>`

You can also provide a specific version to download / extract: `npx dzfg <new-folder> <github-repo> <version?> <no-npm?>`
You can also provide a specific version to download / extract:

`npx dzfg <new-folder> <github-repo> <version?> <no-npm?>`

This will download `v4.2.0`, and will skip the `npm install` step:
```shell
Expand All @@ -35,7 +40,7 @@ Using `.then()`:
```javascript
const dzfg = require('dzfg');

dzfg.downloadAndExtract('destination-folder', 'username/my-repo').then(() => {});
dzfg.downloadAndExtract('new-folder', 'username/my-repo').then(() => {});

// OR

Expand All @@ -49,7 +54,7 @@ Using `await`:
```javascript
const dzfg = require('dzfg');

await dzfg.downloadAndExtract('destination-folder', 'username/my-repo');
await dzfg.downloadAndExtract('new-folder', 'username/my-repo');

// OR

Expand All @@ -59,13 +64,13 @@ await dzfg.downloadAndExtract({
});
```

Advanced usage:
#### Advanced usage:

```javascript
const dzfg = require('dzfg');

// Parameters are: destination-folder, repo, version, skipNpmInstall
await dzfg.downloadAndExtract('destination-folder', 'username/my-repo', 'v1.0.1', true);
await dzfg.downloadAndExtract('new-folder', 'username/my-repo', 'v1.0.1', true);

// OR
await dzfg.downloadAndExtract({
Expand All @@ -76,8 +81,78 @@ await dzfg.downloadAndExtract({
});
```

#### Getting version info for a repo:

```javascript
const dzfg = require('dzfg');

const latestVersionInfo = await dzfg.getVersionAndUrls('username/my-repo');

// OR

dzfg.getVersionAndUrls('username/my-repo').then((latestVersionInfo) => {
// Do stuff with the info...
});
```

`latestVersionInfo` will look something like:

```json5
{
name: 'v1.0.1 (2023-10-01)',
description: 'The version description body. This will likely contain markdown.',
version: 'v1.0.1',
isDraft: false,
isPrerelease: false,
createdAt: '2023-10-01T04:19:00Z',
publishedAt: '2023-10-01T04:19:00Z',

// `userSite` is the HTML URL for human use:
userSite: 'https://github.com/{username/repo}/releases/tag/v1.0.1',

// `zipball` is the URL dzfg will use internally to download the repo:
zipball: 'https://api.github.com/repos/{username/repo}/zipball/v1.0.1'
}
```

Get info for a specific version:

```javascript
const dzfg = require('dzfg');

const latestVersionInfo = await dzfg.getVersionAndUrls('username/my-repo', 'v1.0.1');
```

#### Don't forget to handle errors...

```javascript
const dzfg = require('dzfg');

dzfg.downloadAndExtract('new-folder', 'username/my-repo')
.then((successMessage) => {})
.catch((e) => {});

dzfg.getVersionAndUrls('username/my-repo')
.then((latestVersionInfo) => {})
.catch((e) => {});

// OR

try {
const successMessage = await dzfg.downloadAndExtract('new-folder', 'username/my-repo');
} catch (e) {
// Display the error...
}

try {
const latestVersionInfo = await dzfg.getVersionAndUrls('username/my-repo');
} catch (e) {
// Display the error...
}
```

## This works for ALMOST any GitHub repo...

As long as the repository is using GitHub's releases feature correctly, this script will work.

If a call to `https://api.github.com/repos/{repo-name-here}/releases/latest` returns a `name` and `zipball_url` properties, then the script will download the zipball from `zipball_url`.
If a call to `https://api.github.com/repos/{username/repo}/releases/latest` returns a `tag_name` and `zipball_url`, then the script will download the zipball from `zipball_url`.
47 changes: 32 additions & 15 deletions lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ const unzip = require('extract-zip');
const {spawn} = require('child_process');
const currentVersion = require('./package.json').version;

const zipFilePath = path.join(process.cwd(), 'latest-release-dzfg.zip');
const extractionPoint = path.join(process.cwd(), 'temp-extraction-dzfg');
const zipFilePath = path.join(process.cwd(), 'dzfg-temp.zip');
const extractionPoint = path.join(process.cwd(), 'dzfg-temp-extraction');

const reqOptions = {
headers: {
Expand Down Expand Up @@ -109,7 +109,7 @@ const dzfg = {
* @property {boolean} [skipInstall=false] - Whether to skip `npm install` or not.
*/
/**
* Download and Extract the zipball from a GitHub repo. Defaults to the latest release.
* Download and extract the zipball from a GitHub repo. Defaults to the latest release.
*
* @param {string|optionsObj} destinationFolder - The place to extract the repo into. Relative to the current working directory.
* @param {string} repo - The GitHub repo to download / clone. Should be in the form: repo/my-awesome-repo
Expand All @@ -121,7 +121,7 @@ const dzfg = {
downloadAndExtract: (destinationFolder, repo, version = 'latest', skipInstall = false) => new Promise(async (resolve, reject) => {
if (typeof destinationFolder === 'object') {
if (!destinationFolder.repo || destinationFolder.repo === '' || !destinationFolder.destinationFolder || destinationFolder.destinationFolder === '') {
return reject('When calling `dzfg.downloadZipballFromGitHub(options)`, `options.repo` and `options.destinationFolder` are required!');
return reject('When calling `dzfg.downloadAndExtract(options)`, `options.repo` and `options.destinationFolder` are required!');
}

repo = destinationFolder.repo;
Expand All @@ -130,15 +130,15 @@ const dzfg = {
destinationFolder = destinationFolder.destinationFolder;
}

const release = await dzfg.getVersionAndZipballUrl(repo, version).catch((e) => {
const release = await dzfg.getVersionAndUrls(repo, version).catch((e) => {
return reject(e);
});

if (release) {
lib.downloadZipball(release.zipball).then(() => {
lib.extractZipball(destinationFolder).then(async () => {
if (!skipInstall && fs.existsSync(path.join(process.cwd(), destinationFolder, 'package.json'))) {
await lib.runNpmInstall(destinationFolder).catch((e) => {});
await lib.runNpmInstall(destinationFolder).catch(() => {});
}

return resolve(release.version);
Expand All @@ -152,19 +152,26 @@ const dzfg = {
}),

/**
* @typedef versionAndZipUrl
* @typedef versionAndUrls
* @property {string} name - The name of the version. Likely the same as the version tag.
* @property {string} description - The version description. Will likely contain markdown.
* @property {string} version - The version returned from the API.
* @property {boolean} isDraft - If the version is a draft or not.
* @property {boolean} isPrerelease - If this version is a prerelease version or not.
* @property {string} createdAt - The datetime stamp of the version creation.
* @property {string} publishedAt - The datetime stamp of the version publication.
* @property {string} userSite - An HTML URL for human use, to view this version info.
* @property {string} zipball - The URL for the zipball.
*/
/**
* Get Version and Zipball URL
* Get version data and URLs
*
* @param {string} repo - The GitHub repo to get info for.
* @param {string} [version=latest] - The version to get the zipball URL for.
*
* @returns {Promise<versionAndZipUrl>}
* @returns {Promise<versionAndUrls>}
*/
getVersionAndZipballUrl: (repo, version = 'latest') => new Promise((resolve, reject) => {
getVersionAndUrls: (repo, version = 'latest') => new Promise((resolve, reject) => {
if (!version || version === '') {
version = 'latest';
}
Expand All @@ -173,7 +180,8 @@ const dzfg = {
version = 'tags/' + version; // Why GitHub, why?...
}

https.get('https://api.github.com/repos/' + repo + '/releases/' + version, reqOptions, (res) => {
const reqUrl = 'https://api.github.com/repos/' + repo + '/releases/' + version;
https.get(reqUrl, reqOptions, (res) => {
let data = '';

res.on('data', (chunk) => {
Expand All @@ -183,13 +191,22 @@ const dzfg = {
res.on('end', () => {
const release = JSON.parse(data);

if (release.message === 'Not Found' || !release.name || release.name === '' || !release.zipball_url || release.zipball_url === '') {
console.log(release);
return reject('The repo "' + repo + '" does not appear to be using GitHub releases, does not exist, or the version requested does not exist.');
if (release.message === 'Not Found' || !release.tag_name || release.tag_name === '' || !release.zipball_url || release.zipball_url === '') {
return reject(
'\nVersion "' + version.replace('tags/', '') + '" of the repo "' + repo + '" does not seem to exist. Make sure the repo is using GitHub Releases.' +
'\n\nRequest made to: ' + reqUrl + '\n'
);
}

return resolve({
version: release.name,
name: release.name,
description: release.body,
version: release.tag_name,
isDraft: release.draft,
isPrerelease: release.prerelease,
createdAt: release.created_at,
publishedAt: release.published_at,
userSite: release.html_url,
zipball: release.zipball_url
});
});
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dzfg",
"version": "0.0.2",
"version": "0.0.3",
"description": "Download Zipball From GitHub, and extract it into a new directory.",
"bin": "./bin.js",
"main": "./lib.js",
Expand Down

0 comments on commit fcc6923

Please sign in to comment.