@sonar-autofix/git-client 0.0.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +110 -29
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -13,6 +13,7 @@ class GitClient {
|
|
|
13
13
|
* @param {object} [config]
|
|
14
14
|
* @param {object} [config.git]
|
|
15
15
|
* @param {string} [config.git.branch]
|
|
16
|
+
* @param {string} [config.git.baseBranch]
|
|
16
17
|
* @param {string} [config.git.token]
|
|
17
18
|
* @param {string} [config.git.username]
|
|
18
19
|
* @param {string} [config.git.remote='origin']
|
|
@@ -51,6 +52,18 @@ class GitClient {
|
|
|
51
52
|
);
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Get the base branch for pull requests.
|
|
57
|
+
*
|
|
58
|
+
* Returns the configured base branch (config.git.baseBranch),
|
|
59
|
+
* or undefined when it is not set in the configuration.
|
|
60
|
+
*
|
|
61
|
+
* @returns {string|undefined}
|
|
62
|
+
*/
|
|
63
|
+
_getBaseBranch() {
|
|
64
|
+
return this.config.git.baseBranch;
|
|
65
|
+
}
|
|
66
|
+
|
|
54
67
|
/**
|
|
55
68
|
* Get Git username.
|
|
56
69
|
*
|
|
@@ -74,29 +87,15 @@ class GitClient {
|
|
|
74
87
|
* @returns {Promise<string>}
|
|
75
88
|
*/
|
|
76
89
|
async _execGit(args) {
|
|
77
|
-
|
|
78
|
-
var env = Object.assign({}, process.env);
|
|
79
|
-
|
|
80
|
-
var token = this._getToken();
|
|
81
|
-
|
|
82
|
-
if (token) {
|
|
83
|
-
env.GIT_TERMINAL_PROMPT = '0';
|
|
84
|
-
|
|
85
|
-
/*
|
|
86
|
-
* GIT_ASKPASS prevents Git from prompting for credentials.
|
|
87
|
-
* The actual token is supplied through environment variables.
|
|
88
|
-
*/
|
|
89
|
-
env.GIT_USERNAME = this._getUsername();
|
|
90
|
-
env.GIT_PASSWORD = token;
|
|
90
|
+
var env = Object.assign({}, process.env);
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
*/
|
|
98
|
-
}
|
|
92
|
+
/*
|
|
93
|
+
* Never hang on an interactive credential prompt.
|
|
94
|
+
* Authentication is supplied per-command (see push()).
|
|
95
|
+
*/
|
|
96
|
+
env.GIT_TERMINAL_PROMPT = '0';
|
|
99
97
|
|
|
98
|
+
try {
|
|
100
99
|
var result = await execFile('git', args, {
|
|
101
100
|
cwd: this.cwd,
|
|
102
101
|
env: env
|
|
@@ -104,8 +103,8 @@ class GitClient {
|
|
|
104
103
|
|
|
105
104
|
return (result.stdout || '').trim();
|
|
106
105
|
} catch (err) {
|
|
107
|
-
var command = 'git ' + args.join(' ');
|
|
108
|
-
var stderr = (err.stderr || '').trim();
|
|
106
|
+
var command = this._redactSecrets('git ' + args.join(' '));
|
|
107
|
+
var stderr = this._redactSecrets((err.stderr || '').trim());
|
|
109
108
|
|
|
110
109
|
throw new Error(
|
|
111
110
|
'Git command failed: ' +
|
|
@@ -115,6 +114,64 @@ class GitClient {
|
|
|
115
114
|
}
|
|
116
115
|
}
|
|
117
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Remove any configured secrets from a string so they never leak
|
|
119
|
+
* into logs or error messages.
|
|
120
|
+
*
|
|
121
|
+
* @param {string} value
|
|
122
|
+
* @returns {string}
|
|
123
|
+
*/
|
|
124
|
+
_redactSecrets(value) {
|
|
125
|
+
if (!value) {
|
|
126
|
+
return value;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
var token = this._getToken();
|
|
130
|
+
|
|
131
|
+
if (token && value.indexOf(token) !== -1) {
|
|
132
|
+
value = value.split(token).join('[REDACTED]');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return value;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Build an authenticated push URL by embedding the GitHub token.
|
|
140
|
+
*
|
|
141
|
+
* This lets Git authenticate with the token directly instead of
|
|
142
|
+
* prompting for a username and password. Only HTTP(S) remotes are
|
|
143
|
+
* eligible; other remotes (e.g. SSH) return null and fall back to a
|
|
144
|
+
* normal push.
|
|
145
|
+
*
|
|
146
|
+
* @returns {Promise<string|null>}
|
|
147
|
+
*/
|
|
148
|
+
async _getAuthenticatedUrl() {
|
|
149
|
+
var token = this._getToken();
|
|
150
|
+
|
|
151
|
+
if (!token) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
var url;
|
|
156
|
+
try {
|
|
157
|
+
url = await this._execGit(['remote', 'get-url', this.config.git.remote]);
|
|
158
|
+
} catch (err) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
var match = url.match(/^https?:\/\/(?:[^@\/]+@)?([^\/]+?)\/(.+)$/);
|
|
163
|
+
|
|
164
|
+
if (!match) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
var host = match[1];
|
|
169
|
+
var path = match[2];
|
|
170
|
+
var user = this._getUsername();
|
|
171
|
+
|
|
172
|
+
return 'https://' + user + ':' + token + '@' + host + '/' + path;
|
|
173
|
+
}
|
|
174
|
+
|
|
118
175
|
/**
|
|
119
176
|
* Execute GitHub CLI command.
|
|
120
177
|
*
|
|
@@ -140,7 +197,9 @@ class GitClient {
|
|
|
140
197
|
|
|
141
198
|
var result = await execFile('gh', args, {
|
|
142
199
|
cwd: this.cwd,
|
|
143
|
-
env: env
|
|
200
|
+
env: env,
|
|
201
|
+
encoding: 'utf8',
|
|
202
|
+
stdio: 'pipe',
|
|
144
203
|
});
|
|
145
204
|
|
|
146
205
|
return (result.stdout || '').trim();
|
|
@@ -150,7 +209,8 @@ class GitClient {
|
|
|
150
209
|
throw new Error(
|
|
151
210
|
'GitHub CLI command failed: ' +
|
|
152
211
|
['gh'].concat(args).join(' ') +
|
|
153
|
-
(stderr ? '\n' + stderr : '')
|
|
212
|
+
(stderr ? '\n' + stderr : '') + '-' +
|
|
213
|
+
err.message
|
|
154
214
|
);
|
|
155
215
|
}
|
|
156
216
|
}
|
|
@@ -215,6 +275,11 @@ class GitClient {
|
|
|
215
275
|
/**
|
|
216
276
|
* Push branch to remote.
|
|
217
277
|
*
|
|
278
|
+
* When a GitHub token is available and the remote is HTTP(S), the
|
|
279
|
+
* branch is pushed to a token-authenticated URL so Git authenticates
|
|
280
|
+
* with the token directly instead of a username/password. For other
|
|
281
|
+
* remotes (e.g. SSH) it falls back to a normal `git push <remote>`.
|
|
282
|
+
*
|
|
218
283
|
* @param {string} [branchName]
|
|
219
284
|
* @param {boolean} [force=false]
|
|
220
285
|
* @returns {Promise<string>}
|
|
@@ -223,10 +288,18 @@ class GitClient {
|
|
|
223
288
|
var branch = branchName || this.config.git.branch;
|
|
224
289
|
var remote = this.config.git.remote;
|
|
225
290
|
|
|
226
|
-
var args = ['push'
|
|
291
|
+
var args = ['push'];
|
|
227
292
|
|
|
228
293
|
if (force) {
|
|
229
|
-
args.
|
|
294
|
+
args.push('--force');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
var authUrl = await this._getAuthenticatedUrl();
|
|
298
|
+
|
|
299
|
+
if (authUrl) {
|
|
300
|
+
args.push(authUrl, branch);
|
|
301
|
+
} else {
|
|
302
|
+
args.push(remote, branch);
|
|
230
303
|
}
|
|
231
304
|
|
|
232
305
|
return this._execGit(args);
|
|
@@ -279,9 +352,14 @@ class GitClient {
|
|
|
279
352
|
* The token is passed through the environment and never
|
|
280
353
|
* appears in the command line.
|
|
281
354
|
*
|
|
355
|
+
* The base branch is resolved in the following order:
|
|
356
|
+
* 1. The baseBranch argument (when provided by the caller).
|
|
357
|
+
* 2. config.git.baseBranch from the configuration file.
|
|
358
|
+
* 3. The current git branch (the branch the CLI is running in).
|
|
359
|
+
*
|
|
282
360
|
* @param {string} title
|
|
283
361
|
* @param {string} body
|
|
284
|
-
* @param {string} [baseBranch
|
|
362
|
+
* @param {string} [baseBranch]
|
|
285
363
|
* @returns {Promise<string>}
|
|
286
364
|
*/
|
|
287
365
|
async createPullRequest(title, body, baseBranch) {
|
|
@@ -301,7 +379,10 @@ class GitClient {
|
|
|
301
379
|
);
|
|
302
380
|
}
|
|
303
381
|
|
|
304
|
-
var base =
|
|
382
|
+
var base =
|
|
383
|
+
baseBranch ||
|
|
384
|
+
this._getBaseBranch() ||
|
|
385
|
+
(await this.getCurrentBranch());
|
|
305
386
|
|
|
306
387
|
return this._execGh([
|
|
307
388
|
'pr',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sonar-autofix/git-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Git client for the Sonar Autofix tool",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -14,4 +14,4 @@
|
|
|
14
14
|
],
|
|
15
15
|
"author": "Sonar Autofix Team",
|
|
16
16
|
"license": "MIT"
|
|
17
|
-
}
|
|
17
|
+
}
|