├── .gitignore ├── README.md ├── index.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | test.js 3 | startTest.bat 4 | node_modules/ 5 | testing/ 6 | tmp/ 7 | .vscode 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Auto Git Update 3 | a node.js module used for automatically updating projects from a git repository. 4 |

5 | 6 | ### Notes 7 | - This module comes in two flavors. ECMAScript & Commonjs. 8 | - The default install will be an ECMAScript module which requires use of an import statement. 9 | - __Optionally, install the commonjs module to make use of the more popular require statement.__ 10 | - This module uses simple-logger (https://github.com/chegele/Logger). 11 | - To update from private repositories a personal access token needs to be provided. 12 | - During updates a backup of the old version is taken and stored in the configured tempLocation. 13 | - The remote package.json is compared to the local package.json to determine if a different version is available. 14 |

15 | 16 | ### Config Options 17 | - **repository** *String* - The url to the root of a git repository to update from. 18 | - **tempLocation** *String* - The local dir to save temporary information for Auto Git Update. 19 | - **fromReleases** *Boolean* - [optional] Updated based off of latest published GitHub release instead of branch package.json. 20 | - **branch** *String* - [optional] The branch to update from. Defaults to master. 21 | - **token** *String* - [optional] A personal access token used for accessions private repositories. 22 | - **ignoreFiles** *Array[String]* - [optional] An array of files to not install when updating. Useful for config files. 23 | - **executeOnComplete** *String* - [optional] A command to execute after an update completes. Good for restarting the app. 24 | - **exitOnComplete** *Boolean* - [optional] Use process exit to stop the app after a successful update. 25 | - **logConfig** *Object* - [optional] An object with the logging configuration, see https://github.com/chegele/Logger 26 |

27 | 28 | ### Functions 29 | - **autoUpdate()** - Updates if local package.json version is different than remote. 30 | - **compareVersions()** - Compares package.json versions without updating. 31 | - Returns an object with the properties *upToDate*, *currentVersion*, & *remoteVersion*. 32 | - **forceUpdate()** - Updates without comparing package versions. 33 | - **setLogConfig(logConfig)** - Updates logging configuration. https://github.com/chegele/Logger 34 |

35 | 36 | ### ECMAScript Example (default) 37 | ``` 38 | npm i auto-git-update 39 | ``` 40 | ``` 41 | import AutoGitUpdate from 'auto-git-update'; 42 | 43 | const config = { 44 | repository: 'https://github.com/chegele/BackupPurger', 45 | fromReleases: true, 46 | tempLocation: 'C:/Users/scheg/Desktop/tmp/', 47 | ignoreFiles: ['util/config.js'], 48 | executeOnComplete: 'C:/Users/scheg/Desktop/worksapce/AutoGitUpdate/startTest.bat', 49 | exitOnComplete: true 50 | } 51 | 52 | const updater = new AutoGitUpdate(config); 53 | 54 | updater.autoUpdate(); 55 | ``` 56 |

57 | 58 | ### CommonJS Example 59 | ``` 60 | npm i auto-git-update@commonjs 61 | ``` 62 | ``` 63 | const AutoGitUpdate = require('auto-git-update'); 64 | 65 | const config = { 66 | repository: 'https://github.com/chegele/BackupPurger', 67 | fromReleases: true, 68 | tempLocation: 'C:/Users/scheg/Desktop/tmp/', 69 | ignoreFiles: ['util/config.js'], 70 | executeOnComplete: 'C:/Users/scheg/Desktop/worksapce/AutoGitUpdate/startTest.bat', 71 | exitOnComplete: true 72 | } 73 | 74 | const updater = new AutoGitUpdate(config); 75 | 76 | updater.autoUpdate(); 77 | ``` 78 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | import path from 'path'; 3 | import fs from 'fs-extra'; 4 | import {spawn, exec} from 'child_process'; 5 | import https from 'https'; 6 | import appRootPath from 'app-root-path'; 7 | import git from 'simple-git'; 8 | import Logger from 'chegs-simple-logger'; 9 | 10 | /** 11 | * @typedef {Object} Config - Configuration for Auto Git Update 12 | * @property {String} repository - The url to the root of a git repository to update from, or /latest GitHub release. 13 | * @property {String} branch - The branch to update from. Defaults to master. 14 | * @property {Boolean} fromReleases - Updated based off of latest published GitHub release instead of branch package.json. 15 | * @property {String} token - A personal access token used for accessions private repositories. 16 | * @property {Logger.Options} logConfig - An object with the logging configuration, see https://github.com/chegele/Logger 17 | * @property {String} tempLocation - The local dir to save temporary information for Auto Git Update. 18 | * @property {Array[String]} ignoreFiles - An array of files to not install when updating. Useful for config files. 19 | * @property {String} executeOnComplete - A command to execute after an update completes. Good for restarting the app. 20 | * @property {Boolean} exitOnComplete - Use process exit to stop the app after a successful update. 21 | */ 22 | 23 | /** @type {Config} */ 24 | let config = {} 25 | 26 | // Subdirectories to use within the configured tempLocation from above. 27 | const cloneSubdirectory = '/AutoGitUpdate/repo/'; 28 | const backupSubdirectory = '/AutoGitUpdate/backup/'; 29 | 30 | // Enable during testing to prevent overwrite of Auto Git Update 31 | const testing = false; 32 | 33 | // Create a new simple logger. This can be updated to use a new configuration by calling setLogConfig() 34 | // https://github.com/chegele/Logger 35 | let log = new Logger({}); 36 | log.logGeneral = true; 37 | log.logWarning = true; 38 | log.logError = true; 39 | log.logDetail = false; 40 | log.logDebug = false; 41 | 42 | // Toggles if performing async setup task 43 | let ready = true; 44 | 45 | export default class AutoGitUpdate { 46 | /** 47 | * Creates an object which can be used to automatically update an application from a remote git repository. 48 | * @param {Config} updateConfig 49 | */ 50 | constructor(updateConfig) { 51 | // validate config has required properties 52 | if (updateConfig == undefined) throw new Error('You must pass a config object to AutoGitUpdate.'); 53 | if (updateConfig.repository == undefined) throw new Error('You must include a repository link.'); 54 | if (updateConfig.branch == undefined) updateConfig.branch = 'master'; 55 | if (updateConfig.tempLocation == undefined) throw new Error('You must define a temp location for cloning the repository'); 56 | 57 | // Update the logger configuration if provided. 58 | if (updateConfig.logConfig) this.setLogConfig(updateConfig.logConfig); 59 | 60 | // Update config and retrieve current tag if configured to use releases 61 | config = updateConfig; 62 | if (config.fromReleases) { 63 | ready = false; 64 | setBranchToReleaseTag(config.repository); 65 | } 66 | 67 | // Validate that Auto Git Update is being used as a dependency or testing is enabled 68 | // This is to prevent the Auto Git Update module from being overwritten on accident during development 69 | if (!testing) { 70 | let file = path.join(appRootPath.path, 'package.json'); 71 | let appPackage = fs.readFileSync(file); 72 | appPackage = JSON.parse(appPackage); 73 | if (appPackage.name == 'auto-git-update') throw new Error('Auto Git Update is not being ran as a dependency & testing is not enabled.'); 74 | } 75 | 76 | } 77 | 78 | /** 79 | * Checks local version against the remote version & then updates if different. 80 | */ 81 | async autoUpdate() { 82 | while (!ready) { await sleep(1000); log.general('Auto Git Update - Not ready to update...')}; 83 | let versionCheck = await this.compareVersions(); 84 | if (versionCheck.upToDate) return true; 85 | return await this.forceUpdate(); 86 | } 87 | 88 | /** 89 | * @typedef VersionResults 90 | * @param {Boolean} UpToDate - If the local version is the same as the remote version. 91 | * @param {String} currentVersion - The version of the local application. 92 | * @param {String} remoteVersion - The version of the application in the git repository. 93 | * 94 | * Checks the local version of the application against the remote repository. 95 | * @returns {VersionResults} - An object with the results of the version comparison. 96 | */ 97 | async compareVersions() { 98 | try { 99 | log.general('Auto Git Update - Comparing versions...'); 100 | let currentVersion = readAppVersion(); 101 | let remoteVersion = await readRemoteVersion(); 102 | log.general('Auto Git Update - Current version: ' + currentVersion); 103 | log.general('Auto Git Update - Remote Version: ' + remoteVersion); 104 | if (currentVersion == remoteVersion) return {upToDate: true, currentVersion}; 105 | return {upToDate: false, currentVersion, remoteVersion}; 106 | }catch(err) { 107 | log.error('Auto Git Update - Error comparing local and remote versions.'); 108 | log.error(err); 109 | return {upToDate: false, currentVersion: 'Error', remoteVersion: 'Error'} 110 | } 111 | } 112 | 113 | /** 114 | * Clones the git repository, purges ignored files, and installs the update over the local application. 115 | * A backup of the application is created before the update is installed. 116 | * If configured, a completion command will be executed and the process for the app will be stopped. 117 | * @returns {Boolean} The result of the update. 118 | */ 119 | async forceUpdate() { 120 | try { 121 | log.general('Auto Git Update - Updating application from ' + config.repository); 122 | await downloadUpdate(); 123 | await backupApp(); 124 | await installUpdate(); 125 | await installDependencies(); 126 | log.general('Auto Git Update - Finished installing updated version.'); 127 | if (config.executeOnComplete) await promiseBlindExecute(config.executeOnComplete); 128 | if (config.exitOnComplete) process.exit(1); 129 | return true; 130 | }catch(err) { 131 | log.error('Auto Git Update - Error updating application'); 132 | log.error(err); 133 | return false; 134 | } 135 | } 136 | 137 | /** 138 | * Updates the simple logger to use the provided configuration. 139 | * Reference the readme for configuration options. 140 | * https://github.com/chegele/Logger 141 | * @param {Logger.Options} logConfig - An object with the logging configuration 142 | */ 143 | setLogConfig(logConfig) { 144 | log = new Logger(logConfig); 145 | } 146 | 147 | } 148 | 149 | //////////////////////////// 150 | // AUTO GIT UPDATE FUNCTIONS 151 | 152 | /** 153 | * Creates a backup of the application, including node modules. 154 | * The backup is stored in the configured tempLocation. Only one backup is kept at a time. 155 | */ 156 | async function backupApp() { 157 | let destination = path.join(config.tempLocation, backupSubdirectory); 158 | log.detail('Auto Git Update - Backing up app to ' + destination); 159 | await fs.ensureDir(destination); 160 | await fs.copy(appRootPath.path, destination, {dereference: true}); 161 | return true; 162 | } 163 | 164 | /** 165 | * Downloads the update from the configured git repository. 166 | * The repo is cloned to the configured tempLocation. 167 | */ 168 | async function downloadUpdate() { 169 | // Inject token for private repositories 170 | let repo = config.repository; 171 | if (config.token) { 172 | repo = repo.replace('http://', '').replace('https://', ''); 173 | repo = `https://${config.token}@${repo}`; 174 | } 175 | 176 | // Empty destination directory & clone repo 177 | let destination = path.join(config.tempLocation, cloneSubdirectory); 178 | log.detail('Auto Git Update - Cloning ' + repo); 179 | log.detail('Auto Git Update - Destination: ' + destination); 180 | await fs.ensureDir(destination); 181 | await fs.emptyDir(destination); 182 | await promiseClone(repo, destination, config.branch); 183 | return true; 184 | } 185 | 186 | /** 187 | * Runs npm install to update/install application dependencies. 188 | */ 189 | function installDependencies() { 190 | return new Promise(function(resolve, reject) { 191 | //If testing is enabled, use alternative path to prevent overwrite of app. 192 | let destination = testing ? path.join(appRootPath.path, '/testing/'): appRootPath.path; 193 | log.detail('Auto Git Update - Installing application dependencies in ' + destination); 194 | // Generate and execute command 195 | let command = `cd ${destination} && npm install`; 196 | let child = exec(command); 197 | 198 | // Wait for results 199 | child.stdout.on('end', resolve); 200 | child.stdout.on('data', data => log.general('Auto Git Update - npm install: ' + data.replace(/\r?\n|\r/g, ''))); 201 | child.stderr.on('data', data => { 202 | if (data.toLowerCase().includes('error')) { 203 | // npm passes warnings as errors, only reject if "error" is included 204 | data = data.replace(/\r?\n|\r/g, ''); 205 | log.error('Auto Git Update - Error installing dependencies'); 206 | log.error('Auto Git Update - ' + data); 207 | reject(); 208 | }else{ 209 | log.warning('Auto Git Update - ' + data); 210 | } 211 | }); 212 | }); 213 | } 214 | 215 | /** 216 | * Purge ignored files from the update, copy the files to the app directory, and install new modules 217 | * The update is installed from the configured tempLocation. 218 | */ 219 | async function installUpdate() { 220 | // Remove ignored files from the new version 221 | if (config.ignoreFiles) { 222 | log.detail('Auto Git Update - Purging ignored files from the update'); 223 | config.ignoreFiles.forEach(file => { 224 | file = path.join(config.tempLocation, cloneSubdirectory, file); 225 | log.detail('Auto Git Update - Removing ' + file); 226 | fs.unlinkSync(file); 227 | }); 228 | } 229 | 230 | // Install updated files 231 | let source = path.join(config.tempLocation, cloneSubdirectory); 232 | //If testing is enabled, use alternative path to prevent overwrite of app. 233 | let destination = testing ? path.join(appRootPath.path, '/testing/'): appRootPath.path; 234 | log.detail('Auto Git Update - Installing update...'); 235 | log.detail('Auto Git Update - Source: ' + source); 236 | log.detail('Auto Git Update - Destination: ' + destination); 237 | await fs.ensureDir(destination); 238 | await fs.copy(source, destination); 239 | return true; 240 | } 241 | 242 | /** 243 | * Reads the applications version from the package.json file. 244 | */ 245 | function readAppVersion() { 246 | let file = path.join(appRootPath.path, 'package.json'); 247 | log.detail('Auto Git Update - Reading app version from ' + file); 248 | let appPackage = fs.readFileSync(file); 249 | return JSON.parse(appPackage).version; 250 | } 251 | 252 | /** 253 | * Reads the applications version from the git repository. 254 | */ 255 | async function readRemoteVersion() { 256 | // Generate request details 257 | let options = {} 258 | let url = config.repository + `/${config.branch}/package.json`; 259 | if (url.includes('github')) url = url.replace('github.com', 'raw.githubusercontent.com'); 260 | if (config.token) options.headers = {Authorization: `token ${config.token}`} 261 | log.detail('Auto Git Update - Reading remote version from ' + url); 262 | // Send request for repositories raw package.json file 263 | try { 264 | let body = await promiseHttpsRequest(url, options); 265 | let remotePackage = JSON.parse(body); 266 | let version = remotePackage.version; 267 | return version; 268 | }catch(err) { 269 | if (err = 404) throw new Error('This repository requires a token or does not exist. \n ' + url); 270 | throw err; 271 | } 272 | } 273 | 274 | 275 | /** 276 | * Updates the configuration for this updater to use the latest release as the repo branch 277 | * @param {String} repository - The link to the repo 278 | */ 279 | async function setBranchToReleaseTag(repository) { 280 | // Validate the configuration & generate request details 281 | let options = {headers: {"User-Agent": "Auto-Git-Update - " + repository}} 282 | if (config.token) options.headers.Authorization = `token ${config.token}`; 283 | repository = repository.toLocaleLowerCase().replace('github.com/', 'api.github.com/repos/'); 284 | if (!repository.includes('github')) throw new Error('fromReleases is enabled but this does not seem to be a GitHub repo.'); 285 | if (repository.endsWith('/')) repository = repository.slice(0, -1); 286 | const url = (repository + '/releases/latest') 287 | log.general('Auto Git Update - Checking release tag from ' + url); 288 | 289 | // Attempt to identify the tag/version of the latest release 290 | try { 291 | let body = await promiseHttpsRequest(url, options); 292 | let response = JSON.parse(body); 293 | let tag = response.tag_name; 294 | config.branch = tag; 295 | ready = true; 296 | }catch(err) { 297 | if (err = 404) throw new Error('This repository requires a token or does not exist. \n ' + url); 298 | throw err; 299 | } 300 | } 301 | 302 | 303 | //////////////////////////// 304 | // HELPER & MISC FUNCTIONS 305 | 306 | /** 307 | * A promise wrapper for the simple-git clone function 308 | * @param {String} repo - The url of the repository to clone. 309 | * @param {String} destination - The local path to clone into. 310 | * @param {String} branch - The repo branch to clone. 311 | */ 312 | function promiseClone(repo, destination, branch) { 313 | return new Promise(function(resolve, reject) { 314 | git().clone(repo, destination, [`--branch=${branch}`], result => { 315 | if (result != null) reject(`Unable to clone repo \n ${repo} \n ${result}`); 316 | resolve(); 317 | }); 318 | }); 319 | } 320 | 321 | /** 322 | * A promise wrapper for the child-process spawn function. Does not listen for results. 323 | * @param {String} command - The command to execute. 324 | */ 325 | function promiseBlindExecute(command) { 326 | return new Promise(function(resolve, reject) { 327 | spawn(command, [], {shell: true, detached: true}); 328 | setTimeout(resolve, 1000); 329 | }); 330 | } 331 | 332 | /** 333 | * A promise wrapper for sending a get https requests. 334 | * @param {String} url - The Https address to request. 335 | * @param {String} options - The request options. 336 | */ 337 | function promiseHttpsRequest(url, options) { 338 | return new Promise(function(resolve, reject) { 339 | let req = https.request(url, options, res => { 340 | //Construct response 341 | let body = ''; 342 | res.on('data', data => {body += data}); 343 | res.on('end', function() { 344 | if (res.statusCode == '200') return resolve(body); 345 | log.detail('Auto Git Update - Bad Response ' + res.statusCode); 346 | reject(res.statusCode); 347 | }); 348 | }); 349 | log.detail('Auto Git Update - Sending request to ' + url); 350 | log.detail('Auto Git Update - Options: ' + JSON.stringify(options)); 351 | req.on('error', reject); 352 | req.end(); 353 | }); 354 | } 355 | 356 | async function sleep(time) { 357 | return new Promise(function(resolve, reject) { 358 | setTimeout(resolve, time); 359 | }); 360 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auto-git-update", 3 | "version": "1.1.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "auto-git-update", 9 | "version": "1.1.1", 10 | "license": "ISC", 11 | "dependencies": { 12 | "app-root-path": "^3.0.0", 13 | "chegs-simple-logger": "^1.1.0", 14 | "fs-extra": "^8.1.0", 15 | "simple-git": "^3.3.0" 16 | } 17 | }, 18 | "node_modules/@kwsites/file-exists": { 19 | "version": "1.1.1", 20 | "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", 21 | "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", 22 | "dependencies": { 23 | "debug": "^4.1.1" 24 | } 25 | }, 26 | "node_modules/@kwsites/promise-deferred": { 27 | "version": "1.1.1", 28 | "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", 29 | "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" 30 | }, 31 | "node_modules/app-root-path": { 32 | "version": "3.0.0", 33 | "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", 34 | "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==", 35 | "engines": { 36 | "node": ">= 6.0.0" 37 | } 38 | }, 39 | "node_modules/chegs-simple-logger": { 40 | "version": "1.1.0", 41 | "resolved": "https://registry.npmjs.org/chegs-simple-logger/-/chegs-simple-logger-1.1.0.tgz", 42 | "integrity": "sha512-GR7VaKpWw3oAQV9vmjQdNlIVjxCmx15dQpj9b4m9IrGDg4unKykx74pGp8taOxnFEIU0/uqi9XGy5CHNuYwfcA==", 43 | "dependencies": { 44 | "rotating-file-stream": "^1.4.2" 45 | } 46 | }, 47 | "node_modules/debug": { 48 | "version": "4.3.4", 49 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 50 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 51 | "dependencies": { 52 | "ms": "2.1.2" 53 | }, 54 | "engines": { 55 | "node": ">=6.0" 56 | }, 57 | "peerDependenciesMeta": { 58 | "supports-color": { 59 | "optional": true 60 | } 61 | } 62 | }, 63 | "node_modules/fs-extra": { 64 | "version": "8.1.0", 65 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", 66 | "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", 67 | "dependencies": { 68 | "graceful-fs": "^4.2.0", 69 | "jsonfile": "^4.0.0", 70 | "universalify": "^0.1.0" 71 | }, 72 | "engines": { 73 | "node": ">=6 <7 || >=8" 74 | } 75 | }, 76 | "node_modules/graceful-fs": { 77 | "version": "4.2.3", 78 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", 79 | "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" 80 | }, 81 | "node_modules/jsonfile": { 82 | "version": "4.0.0", 83 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 84 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", 85 | "optionalDependencies": { 86 | "graceful-fs": "^4.1.6" 87 | } 88 | }, 89 | "node_modules/ms": { 90 | "version": "2.1.2", 91 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 92 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 93 | }, 94 | "node_modules/rotating-file-stream": { 95 | "version": "1.4.6", 96 | "resolved": "https://registry.npmjs.org/rotating-file-stream/-/rotating-file-stream-1.4.6.tgz", 97 | "integrity": "sha512-QS7vGxBK6sGc1mCqlmAuwV4J0fmmVCKaUgMvKbkTueZr4jdkXN3bSpTEOQxtdtAVEzi1aUqdHzwIQ0ejNn+CQg==", 98 | "deprecated": "please use version 2.x", 99 | "engines": { 100 | "node": ">=6.0" 101 | } 102 | }, 103 | "node_modules/simple-git": { 104 | "version": "3.3.0", 105 | "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.3.0.tgz", 106 | "integrity": "sha512-K9qcbbZwPHhk7MLi0k0ekvSFXJIrRoXgHhqMXAFM75qS68vdHTcuzmul1ilKI02F/4lXshVgBoDll2t++JK0PQ==", 107 | "dependencies": { 108 | "@kwsites/file-exists": "^1.1.1", 109 | "@kwsites/promise-deferred": "^1.1.1", 110 | "debug": "^4.3.3" 111 | }, 112 | "funding": { 113 | "type": "github", 114 | "url": "https://github.com/sponsors/steveukx/" 115 | } 116 | }, 117 | "node_modules/universalify": { 118 | "version": "0.1.2", 119 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 120 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", 121 | "engines": { 122 | "node": ">= 4.0.0" 123 | } 124 | } 125 | }, 126 | "dependencies": { 127 | "@kwsites/file-exists": { 128 | "version": "1.1.1", 129 | "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", 130 | "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", 131 | "requires": { 132 | "debug": "^4.1.1" 133 | } 134 | }, 135 | "@kwsites/promise-deferred": { 136 | "version": "1.1.1", 137 | "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", 138 | "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" 139 | }, 140 | "app-root-path": { 141 | "version": "3.0.0", 142 | "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", 143 | "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==" 144 | }, 145 | "chegs-simple-logger": { 146 | "version": "1.1.0", 147 | "resolved": "https://registry.npmjs.org/chegs-simple-logger/-/chegs-simple-logger-1.1.0.tgz", 148 | "integrity": "sha512-GR7VaKpWw3oAQV9vmjQdNlIVjxCmx15dQpj9b4m9IrGDg4unKykx74pGp8taOxnFEIU0/uqi9XGy5CHNuYwfcA==", 149 | "requires": { 150 | "rotating-file-stream": "^1.4.2" 151 | } 152 | }, 153 | "debug": { 154 | "version": "4.3.4", 155 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 156 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 157 | "requires": { 158 | "ms": "2.1.2" 159 | } 160 | }, 161 | "fs-extra": { 162 | "version": "8.1.0", 163 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", 164 | "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", 165 | "requires": { 166 | "graceful-fs": "^4.2.0", 167 | "jsonfile": "^4.0.0", 168 | "universalify": "^0.1.0" 169 | } 170 | }, 171 | "graceful-fs": { 172 | "version": "4.2.3", 173 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", 174 | "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" 175 | }, 176 | "jsonfile": { 177 | "version": "4.0.0", 178 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 179 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", 180 | "requires": { 181 | "graceful-fs": "^4.1.6" 182 | } 183 | }, 184 | "ms": { 185 | "version": "2.1.2", 186 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 187 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 188 | }, 189 | "rotating-file-stream": { 190 | "version": "1.4.6", 191 | "resolved": "https://registry.npmjs.org/rotating-file-stream/-/rotating-file-stream-1.4.6.tgz", 192 | "integrity": "sha512-QS7vGxBK6sGc1mCqlmAuwV4J0fmmVCKaUgMvKbkTueZr4jdkXN3bSpTEOQxtdtAVEzi1aUqdHzwIQ0ejNn+CQg==" 193 | }, 194 | "simple-git": { 195 | "version": "3.3.0", 196 | "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.3.0.tgz", 197 | "integrity": "sha512-K9qcbbZwPHhk7MLi0k0ekvSFXJIrRoXgHhqMXAFM75qS68vdHTcuzmul1ilKI02F/4lXshVgBoDll2t++JK0PQ==", 198 | "requires": { 199 | "@kwsites/file-exists": "^1.1.1", 200 | "@kwsites/promise-deferred": "^1.1.1", 201 | "debug": "^4.3.3" 202 | } 203 | }, 204 | "universalify": { 205 | "version": "0.1.2", 206 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 207 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auto-git-update", 3 | "version": "1.1.1", 4 | "description": "Update node app from git repo.", 5 | "keywords": [ 6 | "auto", 7 | "automatic", 8 | "git", 9 | "github", 10 | "update", 11 | "updater" 12 | ], 13 | "main": "index.js", 14 | "type": "module", 15 | "scripts": { 16 | "test": "echo \"Error: no test specified\" && exit 1" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/chegele/AutoGitUpdate.git" 21 | }, 22 | "author": "", 23 | "license": "ISC", 24 | "bugs": { 25 | "url": "https://github.com/chegele/AutoGitUpdate/issues" 26 | }, 27 | "homepage": "https://github.com/chegele/AutoGitUpdate#readme", 28 | "dependencies": { 29 | "app-root-path": "^3.0.0", 30 | "chegs-simple-logger": "^1.1.0", 31 | "fs-extra": "^8.1.0", 32 | "simple-git": "^3.3.0" 33 | } 34 | } 35 | --------------------------------------------------------------------------------