1 | const { execSync } = require('child_process');
|
2 | const fs = require('fs-extra');
|
3 | const path = require('path');
|
4 |
|
5 | const CLiError = require('@src/exceptions/cli-error');
|
6 | const Messenger = require('@src/view/messenger');
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | module.exports = class GitClient {
|
12 | |
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | constructor(projectPath, verbosityOptions) {
|
19 | this.projectPath = projectPath;
|
20 | this.verbosityOptions = verbosityOptions;
|
21 | }
|
22 |
|
23 | |
24 |
|
25 |
|
26 | init() {
|
27 | const commands = [`git init "${this.projectPath}"${this.verbosityOptions.showOutput === false ? ' --quiet' : ''}`];
|
28 | const options = {
|
29 | showStdOut: this.verbosityOptions.showOutput,
|
30 | showStdErr: true,
|
31 | showCmd: this.verbosityOptions.showCommand
|
32 | };
|
33 | this._execCommands(commands, options);
|
34 | }
|
35 |
|
36 | |
37 |
|
38 |
|
39 |
|
40 | configureCredentialHelper(credentialHelperPath) {
|
41 | const commands = [
|
42 | 'git config --local credential.helper ""',
|
43 | `git config --local --add credential.helper "!${credentialHelperPath}"`,
|
44 | 'git config --local credential.UseHttpPath true'];
|
45 | const options = {
|
46 | showStdOut: this.verbosityOptions.showOutput,
|
47 | showStdErr: true,
|
48 | showCmd: this.verbosityOptions.showCommand,
|
49 | workingDir: this.projectPath
|
50 | };
|
51 | this._execCommands(commands, options);
|
52 | }
|
53 |
|
54 | |
55 |
|
56 |
|
57 |
|
58 | updateCredentialHelper(credentialHelperPath) {
|
59 | const commands = [
|
60 | `git config --local --replace-all credential.helper "!${credentialHelperPath}"`,
|
61 | 'git config --local credential.UseHttpPath true'];
|
62 | const options = {
|
63 | showStdOut: this.verbosityOptions.showOutput,
|
64 | showStdErr: true,
|
65 | showCmd: this.verbosityOptions.showCommand,
|
66 | workingDir: this.projectPath
|
67 | };
|
68 | this._execCommands(commands, options);
|
69 | }
|
70 |
|
71 | |
72 |
|
73 |
|
74 |
|
75 | addOrigin(repoUrl) {
|
76 | const commands = [`git remote add origin ${repoUrl}`];
|
77 | const options = {
|
78 | showStdOut: this.verbosityOptions.showOutput,
|
79 | showStdErr: true,
|
80 | showCmd: this.verbosityOptions.showCommand,
|
81 | workingDir: this.projectPath
|
82 | };
|
83 | this._execCommands(commands, options);
|
84 | }
|
85 |
|
86 | |
87 |
|
88 |
|
89 | fetchAll() {
|
90 | const commands = [`git fetch --all${this.verbosityOptions.showOutput === false ? ' --quiet' : ''}`];
|
91 | const options = {
|
92 | showStdOut: this.verbosityOptions.showOutput,
|
93 | showStdErr: false,
|
94 | showCmd: this.verbosityOptions.showCommand,
|
95 | workingDir: this.projectPath
|
96 | };
|
97 | this._execCommands(commands, options);
|
98 | }
|
99 |
|
100 | |
101 |
|
102 |
|
103 |
|
104 | checkoutBranch(branch) {
|
105 | const commands = [`git checkout ${branch}${this.verbosityOptions.showOutput === false ? ' --quiet' : ''}`];
|
106 | const options = {
|
107 | showStdOut: this.verbosityOptions.showOutput,
|
108 | showStdErr: true,
|
109 | showCmd: this.verbosityOptions.showCommand,
|
110 | workingDir: this.projectPath
|
111 | };
|
112 | this._execCommands(commands, options);
|
113 | }
|
114 |
|
115 | |
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 | clone(cloneUrl, branch, folderName) {
|
122 | const commands = [`git clone --branch ${branch} ${cloneUrl} ${folderName} ${this.verbosityOptions.showOutput === false ? ' --quiet' : ''}`];
|
123 | const options = {
|
124 | showStdOut: this.verbosityOptions.showOutput,
|
125 | showStdErr: true,
|
126 | showCmd: this.verbosityOptions.showCommand
|
127 | };
|
128 | this._execCommands(commands, options);
|
129 | }
|
130 |
|
131 | |
132 |
|
133 |
|
134 |
|
135 | setupGitIgnore(filesToIgnore) {
|
136 | const gitignorePath = path.join(this.projectPath, '.gitignore');
|
137 | if (fs.existsSync(gitignorePath) === false) {
|
138 | fs.writeFileSync(gitignorePath, `${filesToIgnore.join('\n')}`);
|
139 | } else {
|
140 | const gitignoreFile = fs.readFileSync(gitignorePath).toString();
|
141 | filesToIgnore.forEach((file) => {
|
142 | if (gitignoreFile.indexOf(file) === -1) {
|
143 | fs.appendFileSync(gitignorePath, `\n${file}`);
|
144 | }
|
145 | });
|
146 | }
|
147 | this.add('.gitignore');
|
148 | }
|
149 |
|
150 | |
151 |
|
152 |
|
153 |
|
154 | add(file) {
|
155 | const commands = [`git add "${file}"`];
|
156 | const options = {
|
157 | showStdOut: this.verbosityOptions.showOutput,
|
158 | showStdErr: true,
|
159 | showCmd: this.verbosityOptions.showCommand,
|
160 | workingDir: this.projectPath
|
161 | };
|
162 | this._execCommands(commands, options);
|
163 | }
|
164 |
|
165 | |
166 |
|
167 |
|
168 |
|
169 | deleteBranch(branch) {
|
170 | const commands = [`git branch -d ${branch}`];
|
171 | const options = {
|
172 | showStdOut: this.verbosityOptions.showOutput,
|
173 | showStdErr: true,
|
174 | showCmd: this.verbosityOptions.showCommand
|
175 | };
|
176 | this._execCommands(commands, options);
|
177 | }
|
178 |
|
179 | |
180 |
|
181 |
|
182 |
|
183 | merge(branch) {
|
184 | const commands = [`git merge ${branch}`];
|
185 | const options = {
|
186 | showStdOut: this.verbosityOptions.showOutput,
|
187 | showStdErr: true,
|
188 | showCmd: this.verbosityOptions.showCommand
|
189 | };
|
190 | this._execCommands(commands, options);
|
191 | }
|
192 |
|
193 | |
194 |
|
195 |
|
196 |
|
197 | shortStatus() {
|
198 | const command = 'git status -s';
|
199 | const options = {
|
200 | showStdOut: this.verbosityOptions.showOutput,
|
201 | showStdErr: true,
|
202 | showCmd: this.verbosityOptions.showCommand
|
203 | };
|
204 | try {
|
205 | return this._execChildProcessSync(command, options);
|
206 | } catch (ex) {
|
207 | throw new CLiError(`${ex}`);
|
208 | }
|
209 | }
|
210 |
|
211 | |
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 | countCommitDifference(commit1, commit2) {
|
218 | const command = `git rev-list --count ${commit1}...${commit2}`;
|
219 | const options = {
|
220 | showStdOut: this.verbosityOptions.showOutput,
|
221 | showStdErr: true,
|
222 | showCmd: this.verbosityOptions.showCommand,
|
223 | workingDir: this.projectPath
|
224 | };
|
225 | try {
|
226 | return this._execChildProcessSync(command, options);
|
227 | } catch (ex) {
|
228 | throw new CLiError(`${ex}`);
|
229 | }
|
230 | }
|
231 |
|
232 | _execCommands(commands, options) {
|
233 | for (const command of commands) {
|
234 | try {
|
235 | this._execChildProcessSync(command, options);
|
236 | } catch (ex) {
|
237 | throw new CLiError(`${ex}`);
|
238 | }
|
239 | }
|
240 | }
|
241 |
|
242 | _execChildProcessSync(command, options) {
|
243 | const { showOutput, showStdErr, showCommand, workingDir } = options;
|
244 | const execOptions = {
|
245 | stdio: [null, showOutput ? 1 : null, showStdErr ? 2 : null],
|
246 | shell: true,
|
247 | windowsHide: true
|
248 | };
|
249 | if (workingDir) {
|
250 | execOptions.cwd = options.workingDir;
|
251 | }
|
252 | if (showCommand) {
|
253 | Messenger.getInstance().info(command);
|
254 | }
|
255 | return execSync(command, execOptions);
|
256 | }
|
257 | };
|