-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
492 additions
and
219 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,137 +1,176 @@ | ||
const { execSync } = require('child_process'); | ||
const fs = require('fs-extra'); | ||
const git = require('simple-git'); | ||
const path = require('path'); | ||
|
||
const CLiError = require('@src/exceptions/cli-error'); | ||
const Messenger = require('@src/view/messenger'); | ||
|
||
module.exports = { | ||
init, | ||
configureCredentialHelper, | ||
addOrigin, | ||
fetchAll, | ||
checkoutBranch, | ||
add, | ||
clone, | ||
setupGitIgnore | ||
}; | ||
|
||
const isWindows = process.platform === 'win32'; | ||
// eslint-disable-next-line quotes | ||
const QUOTES = isWindows ? `"` : `'`; | ||
|
||
function init(projectPath, verbosityOptions) { | ||
const commands = [`git init ${QUOTES}${projectPath}${QUOTES}${verbosityOptions.showOutput === false ? ' --quiet' : ''}`]; | ||
const options = { showStdOut: verbosityOptions.showOutput, showStdErr: true, showCmd: verbosityOptions.showCommand }; | ||
for (const command of commands) { | ||
try { | ||
_execChildProcessSync(command, options); | ||
} catch (ex) { | ||
throw new Error(`${command} Failed.`); | ||
} | ||
/** | ||
* Class for git commands management | ||
*/ | ||
module.exports = class GitClient { | ||
/** | ||
* Constructor for GitClient with projectPath and verbosity options | ||
* @param {string} projectPath the path of a project | ||
* @param {object} verbosityOptions | showOutput | ||
* | showCommand | ||
*/ | ||
constructor(projectPath, verbosityOptions) { | ||
this.projectPath = projectPath; | ||
this.verbosityOptions = verbosityOptions; | ||
} | ||
} | ||
|
||
function configureCredentialHelper(projectPath, credentialHelperPath, verbosityOptions) { | ||
const commands = [`git config --local credential.helper ${QUOTES}${QUOTES}`, | ||
`git config --local --add credential.helper ${QUOTES}!${credentialHelperPath}${QUOTES}`, | ||
'git config --local credential.UseHttpPath true']; | ||
const options = { showStdOut: verbosityOptions.showOutput, showStdErr: true, showCmd: verbosityOptions.showCommand, workingDir: projectPath }; | ||
for (const command of commands) { | ||
try { | ||
_execChildProcessSync(command, options); | ||
} catch (ex) { | ||
throw new Error(`${command} Failed.`); | ||
} | ||
/** | ||
* Execute git-init to create an empty Git repository or reinitialize an existing one | ||
*/ | ||
init() { | ||
const commands = [`git init ${QUOTES}${this.projectPath}${QUOTES}${this.verbosityOptions.showOutput === false ? ' --quiet' : ''}`]; | ||
const options = { | ||
showStdOut: this.verbosityOptions.showOutput, | ||
showStdErr: true, | ||
showCmd: this.verbosityOptions.showCommand | ||
}; | ||
this._execCommands(commands, options); | ||
} | ||
} | ||
|
||
function addOrigin(projectPath, repoUrl, verbosityOptions) { | ||
const commands = [`git remote add origin ${repoUrl}`]; | ||
const options = { showStdOut: verbosityOptions.showOutput, showStdErr: true, showCmd: verbosityOptions.showCommand, workingDir: projectPath }; | ||
for (const command of commands) { | ||
try { | ||
_execChildProcessSync(command, options); | ||
} catch (ex) { | ||
throw new Error(`${command} Failed.`); | ||
} | ||
/** | ||
* Config local git credential helper with credentialHelperPath | ||
* @param {string} credentialHelperPath the path of git credential helper | ||
*/ | ||
configureCredentialHelper(credentialHelperPath) { | ||
const commands = [`git config --local credential.helper ${QUOTES}${QUOTES}`, | ||
`git config --local --add credential.helper ${QUOTES}!${credentialHelperPath}${QUOTES}`, | ||
'git config --local credential.UseHttpPath true']; | ||
const options = { | ||
showStdOut: this.verbosityOptions.showOutput, | ||
showStdErr: true, | ||
showCmd: this.verbosityOptions.showCommand, | ||
workingDir: this.projectPath | ||
}; | ||
this._execCommands(commands, options); | ||
} | ||
} | ||
|
||
function fetchAll(projectPath, verbosityOptions) { | ||
const commands = [`git fetch --all${verbosityOptions.showOutput === false ? ' --quiet' : ''}`]; | ||
const options = { showStdOut: verbosityOptions.showOutput, showStdErr: false, showCmd: verbosityOptions.showCommand, workingDir: projectPath }; | ||
for (const command of commands) { | ||
try { | ||
_execChildProcessSync(command, options); | ||
} catch (ex) { | ||
throw new Error(`${command} Failed.`); | ||
} | ||
/** | ||
* Add a new remote in the directory your repository is stored at | ||
* @param {String} repoUrl a remote url | ||
*/ | ||
addOrigin(repoUrl) { | ||
const commands = [`git remote add origin ${repoUrl}`]; | ||
const options = { | ||
showStdOut: this.verbosityOptions.showOutput, | ||
showStdErr: true, | ||
showCmd: this.verbosityOptions.showCommand, | ||
workingDir: this.projectPath | ||
}; | ||
this._execCommands(commands, options); | ||
} | ||
} | ||
|
||
function checkoutBranch(projectPath, branch, verbosityOptions) { | ||
const commands = [`git checkout ${branch}${verbosityOptions.showOutput === false ? ' --quiet' : ''}`]; | ||
const options = { showStdOut: verbosityOptions.showOutput, showStdErr: true, showCmd: verbosityOptions.showCommand, workingDir: projectPath }; | ||
for (const command of commands) { | ||
try { | ||
_execChildProcessSync(command, options); | ||
} catch (ex) { | ||
throw new Error(`${command} Failed.`); | ||
} | ||
/** | ||
* Execute git fetch to fetch all remotes | ||
*/ | ||
fetchAll() { | ||
const commands = [`git fetch --all${this.verbosityOptions.showOutput === false ? ' --quiet' : ''}`]; | ||
const options = { | ||
showStdOut: this.verbosityOptions.showOutput, | ||
showStdErr: false, | ||
showCmd: this.verbosityOptions.showCommand, | ||
workingDir: this.projectPath | ||
}; | ||
this._execCommands(commands, options); | ||
} | ||
|
||
/** | ||
* Execute git checkout to switch branch or restore working tree files | ||
* @param {string} branch the branch name | ||
*/ | ||
checkoutBranch(branch) { | ||
const commands = [`git checkout ${branch}${this.verbosityOptions.showOutput === false ? ' --quiet' : ''}`]; | ||
const options = { | ||
showStdOut: this.verbosityOptions.showOutput, | ||
showStdErr: true, | ||
showCmd: this.verbosityOptions.showCommand, | ||
workingDir: this.projectPath | ||
}; | ||
this._execCommands(commands, options); | ||
} | ||
|
||
/** | ||
* Execute git clone to clone a repository into a new directory | ||
* @param {string} cloneUrl the clone url | ||
* @param {string} branch the branch name | ||
* @param {string} folderName the directory folder name | ||
*/ | ||
clone(cloneUrl, branch, folderName) { | ||
const commands = [`git clone --branch ${branch} ${cloneUrl} ${folderName} ${this.verbosityOptions.showOutput === false ? ' --quiet' : ''}`]; | ||
const options = { | ||
showStdOut: this.verbosityOptions.showOutput, | ||
showStdErr: true, | ||
showCmd: this.verbosityOptions.showCommand | ||
}; | ||
this._execCommands(commands, options); | ||
} | ||
} | ||
|
||
function add(repoDir, projectPath, verbosityOptions) { | ||
const commands = [`git add ${QUOTES}${projectPath}${QUOTES}`]; | ||
const options = { showStdOut: verbosityOptions.showOutput, showStdErr: true, showCmd: verbosityOptions.showCommand, workingDir: repoDir }; | ||
for (const command of commands) { | ||
try { | ||
_execChildProcessSync(command, options); | ||
} catch (ex) { | ||
throw new Error(`${command} Failed.`); | ||
/** | ||
* Set up or update a gitignore file | ||
* @param {Array} filesToIgnore the list of files to ignore for git | ||
*/ | ||
setupGitIgnore(filesToIgnore) { | ||
const gitignorePath = path.join(this.projectPath, '.gitignore'); | ||
if (fs.existsSync(gitignorePath) === false) { | ||
fs.writeFileSync(gitignorePath, `${filesToIgnore.join('\n')}`); | ||
} else { | ||
const gitignoreFile = fs.readFileSync(gitignorePath).toString(); | ||
filesToIgnore.forEach((file) => { | ||
if (gitignoreFile.indexOf(file) === -1) { | ||
fs.appendFileSync(gitignorePath, `\n${file}`); | ||
} | ||
}); | ||
} | ||
this.add('.gitignore'); | ||
} | ||
} | ||
|
||
function clone(cloneUrl, branch, cloneDir, callback) { | ||
const cloneOption = []; | ||
if (branch) { | ||
cloneOption.push('-b'); | ||
cloneOption.push(branch); | ||
/** | ||
* Execute git add to add file contents to the index | ||
* @param {string} file the file to add content from | ||
*/ | ||
add(file) { | ||
const commands = [`git add ${QUOTES}${file}${QUOTES}`]; | ||
const options = { | ||
showStdOut: this.verbosityOptions.showOutput, | ||
showStdErr: true, | ||
showCmd: this.verbosityOptions.showCommand, | ||
workingDir: this.projectPath | ||
}; | ||
this._execCommands(commands, options); | ||
} | ||
git().silent(true).clone(cloneUrl, cloneDir, cloneOption, (err) => { | ||
callback(err); | ||
}); | ||
} | ||
|
||
function setupGitIgnore(projectPath, filesToIgnore, verbosityOptions) { | ||
const gitignorePath = path.join(projectPath, '.gitignore'); | ||
if (fs.existsSync(gitignorePath) === false) { | ||
fs.writeFileSync(gitignorePath, `${filesToIgnore.join('\n')}`); | ||
} else { | ||
const gitignoreFile = fs.readFileSync(gitignorePath); | ||
filesToIgnore.forEach((file) => { | ||
if (gitignoreFile.toString().indexOf(file) === -1) { | ||
fs.appendFileSync(gitignorePath, `\n${file}`); | ||
_execCommands(commands, options) { | ||
for (const command of commands) { | ||
try { | ||
this._execChildProcessSync(command, options); | ||
} catch (ex) { | ||
throw new CLiError(`${ex}`); | ||
} | ||
}); | ||
} | ||
} | ||
add(projectPath, '.gitignore', verbosityOptions); | ||
} | ||
|
||
function _execChildProcessSync(command, options) { | ||
const { showStdOut, showStdErr, showCmd, workingDir } = options; | ||
const execOptions = { | ||
stdio: [null, showStdOut ? 1 : null, showStdErr ? 2 : null], | ||
shell: true, | ||
windowsHide: true | ||
}; | ||
if (workingDir) { | ||
execOptions.cwd = options.workingDir; | ||
} | ||
if (showCmd) { | ||
Messenger.getInstance().info(command); | ||
_execChildProcessSync(command, options) { | ||
const { showOutput, showStdErr, showCommand, workingDir } = options; | ||
const execOptions = { | ||
stdio: [null, showOutput ? 1 : null, showStdErr ? 2 : null], | ||
shell: true, | ||
windowsHide: true | ||
}; | ||
if (workingDir) { | ||
execOptions.cwd = options.workingDir; | ||
} | ||
if (showCommand) { | ||
Messenger.getInstance().info(command); | ||
} | ||
return execSync(command, execOptions); | ||
} | ||
return execSync(command, execOptions); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.