mirror of
https://github.com/actions/checkout.git
synced 2024-11-21 13:51:26 +01:00
Implement branch list using callbacks from exec function (#1045)
When trying to list local branches to figure out what needs cleaned up during runs on non-ephemeral Actions Runners, we use git rev-parse --symbolic-full-name to get a list of branches. This can lead to ambiguous ref name errors when there are branches and tags with similar names. Part of the reason we use rev-parse --symbolic-full-name vs git branch --list or git rev-parse --symbolic seems to related to a bug in Git 2.18. Until we can deprecate our usage of Git 2.18, I think we need to keep --symbolic-full-name. Since part of the problem is that these ambiguous ref name errors clog the Actions annotation limits, this is a mitigation to suppress those messages until we can get rid of the workaround.
This commit is contained in:
parent
755da8c3cf
commit
8856415920
5 changed files with 243 additions and 57 deletions
2
.licenses/npm/qs.dep.yml
generated
2
.licenses/npm/qs.dep.yml
generated
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
name: qs
|
name: qs
|
||||||
version: 6.10.1
|
version: 6.11.0
|
||||||
type: npm
|
type: npm
|
||||||
summary: A querystring parser that supports nesting and arrays, with a depth limit
|
summary: A querystring parser that supports nesting and arrays, with a depth limit
|
||||||
homepage: https://github.com/ljharb/qs
|
homepage: https://github.com/ljharb/qs
|
||||||
|
|
80
__test__/git-command-manager.test.ts
Normal file
80
__test__/git-command-manager.test.ts
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import * as exec from '@actions/exec'
|
||||||
|
import * as fshelper from '../lib/fs-helper'
|
||||||
|
import * as commandManager from '../lib/git-command-manager'
|
||||||
|
|
||||||
|
let git: commandManager.IGitCommandManager
|
||||||
|
let mockExec = jest.fn()
|
||||||
|
|
||||||
|
describe('git-auth-helper tests', () => {
|
||||||
|
beforeAll(async () => {})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
jest.spyOn(fshelper, 'fileExistsSync').mockImplementation(jest.fn())
|
||||||
|
jest.spyOn(fshelper, 'directoryExistsSync').mockImplementation(jest.fn())
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.restoreAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {})
|
||||||
|
|
||||||
|
it('branch list matches', async () => {
|
||||||
|
mockExec.mockImplementation((path, args, options) => {
|
||||||
|
console.log(args, options.listeners.stdout)
|
||||||
|
|
||||||
|
if (args.includes('version')) {
|
||||||
|
options.listeners.stdout(Buffer.from('2.18'))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.includes('rev-parse')) {
|
||||||
|
options.listeners.stdline(Buffer.from('refs/heads/foo'))
|
||||||
|
options.listeners.stdline(Buffer.from('refs/heads/bar'))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
})
|
||||||
|
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
|
||||||
|
const workingDirectory = 'test'
|
||||||
|
const lfs = false
|
||||||
|
git = await commandManager.createCommandManager(workingDirectory, lfs)
|
||||||
|
|
||||||
|
let branches = await git.branchList(false)
|
||||||
|
|
||||||
|
expect(branches).toHaveLength(2)
|
||||||
|
expect(branches.sort()).toEqual(['foo', 'bar'].sort())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('ambiguous ref name output is captured', async () => {
|
||||||
|
mockExec.mockImplementation((path, args, options) => {
|
||||||
|
console.log(args, options.listeners.stdout)
|
||||||
|
|
||||||
|
if (args.includes('version')) {
|
||||||
|
options.listeners.stdout(Buffer.from('2.18'))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.includes('rev-parse')) {
|
||||||
|
options.listeners.stdline(Buffer.from('refs/heads/foo'))
|
||||||
|
// If refs/tags/v1 and refs/heads/tags/v1 existed on this repository
|
||||||
|
options.listeners.errline(
|
||||||
|
Buffer.from("error: refname 'tags/v1' is ambiguous")
|
||||||
|
)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
})
|
||||||
|
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
|
||||||
|
const workingDirectory = 'test'
|
||||||
|
const lfs = false
|
||||||
|
git = await commandManager.createCommandManager(workingDirectory, lfs)
|
||||||
|
|
||||||
|
let branches = await git.branchList(false)
|
||||||
|
|
||||||
|
expect(branches).toHaveLength(1)
|
||||||
|
expect(branches.sort()).toEqual(['foo'].sort())
|
||||||
|
})
|
||||||
|
})
|
127
dist/index.js
vendored
127
dist/index.js
vendored
|
@ -7441,8 +7441,10 @@ class GitCommandManager {
|
||||||
const result = [];
|
const result = [];
|
||||||
// Note, this implementation uses "rev-parse --symbolic-full-name" because the output from
|
// Note, this implementation uses "rev-parse --symbolic-full-name" because the output from
|
||||||
// "branch --list" is more difficult when in a detached HEAD state.
|
// "branch --list" is more difficult when in a detached HEAD state.
|
||||||
// Note, this implementation uses "rev-parse --symbolic-full-name" because there is a bug
|
// TODO(https://github.com/actions/checkout/issues/786): this implementation uses
|
||||||
// in Git 2.18 that causes "rev-parse --symbolic" to output symbolic full names.
|
// "rev-parse --symbolic-full-name" because there is a bug
|
||||||
|
// in Git 2.18 that causes "rev-parse --symbolic" to output symbolic full names. When
|
||||||
|
// 2.18 is no longer supported, we can switch back to --symbolic.
|
||||||
const args = ['rev-parse', '--symbolic-full-name'];
|
const args = ['rev-parse', '--symbolic-full-name'];
|
||||||
if (remote) {
|
if (remote) {
|
||||||
args.push('--remotes=origin');
|
args.push('--remotes=origin');
|
||||||
|
@ -7450,18 +7452,42 @@ class GitCommandManager {
|
||||||
else {
|
else {
|
||||||
args.push('--branches');
|
args.push('--branches');
|
||||||
}
|
}
|
||||||
const output = yield this.execGit(args);
|
const stderr = [];
|
||||||
for (let branch of output.stdout.trim().split('\n')) {
|
const errline = [];
|
||||||
branch = branch.trim();
|
const stdout = [];
|
||||||
if (branch) {
|
const stdline = [];
|
||||||
if (branch.startsWith('refs/heads/')) {
|
const listeners = {
|
||||||
branch = branch.substr('refs/heads/'.length);
|
stderr: (data) => {
|
||||||
}
|
stderr.push(data.toString());
|
||||||
else if (branch.startsWith('refs/remotes/')) {
|
},
|
||||||
branch = branch.substr('refs/remotes/'.length);
|
errline: (data) => {
|
||||||
}
|
errline.push(data.toString());
|
||||||
result.push(branch);
|
},
|
||||||
|
stdout: (data) => {
|
||||||
|
stdout.push(data.toString());
|
||||||
|
},
|
||||||
|
stdline: (data) => {
|
||||||
|
stdline.push(data.toString());
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
// Suppress the output in order to avoid flooding annotations with innocuous errors.
|
||||||
|
yield this.execGit(args, false, true, listeners);
|
||||||
|
core.debug(`stderr callback is: ${stderr}`);
|
||||||
|
core.debug(`errline callback is: ${errline}`);
|
||||||
|
core.debug(`stdout callback is: ${stdout}`);
|
||||||
|
core.debug(`stdline callback is: ${stdline}`);
|
||||||
|
for (let branch of stdline) {
|
||||||
|
branch = branch.trim();
|
||||||
|
if (!branch) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (branch.startsWith('refs/heads/')) {
|
||||||
|
branch = branch.substring('refs/heads/'.length);
|
||||||
|
}
|
||||||
|
else if (branch.startsWith('refs/remotes/')) {
|
||||||
|
branch = branch.substring('refs/remotes/'.length);
|
||||||
|
}
|
||||||
|
result.push(branch);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
@ -7712,7 +7738,7 @@ class GitCommandManager {
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
execGit(args, allowAllExitCodes = false, silent = false) {
|
execGit(args, allowAllExitCodes = false, silent = false, customListeners = {}) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
fshelper.directoryExistsSync(this.workingDirectory, true);
|
fshelper.directoryExistsSync(this.workingDirectory, true);
|
||||||
const result = new GitOutput();
|
const result = new GitOutput();
|
||||||
|
@ -7723,20 +7749,24 @@ class GitCommandManager {
|
||||||
for (const key of Object.keys(this.gitEnv)) {
|
for (const key of Object.keys(this.gitEnv)) {
|
||||||
env[key] = this.gitEnv[key];
|
env[key] = this.gitEnv[key];
|
||||||
}
|
}
|
||||||
|
const defaultListener = {
|
||||||
|
stdout: (data) => {
|
||||||
|
stdout.push(data.toString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const mergedListeners = Object.assign(Object.assign({}, defaultListener), customListeners);
|
||||||
const stdout = [];
|
const stdout = [];
|
||||||
const options = {
|
const options = {
|
||||||
cwd: this.workingDirectory,
|
cwd: this.workingDirectory,
|
||||||
env,
|
env,
|
||||||
silent,
|
silent,
|
||||||
ignoreReturnCode: allowAllExitCodes,
|
ignoreReturnCode: allowAllExitCodes,
|
||||||
listeners: {
|
listeners: mergedListeners
|
||||||
stdout: (data) => {
|
|
||||||
stdout.push(data.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
result.exitCode = yield exec.exec(`"${this.gitPath}"`, args, options);
|
result.exitCode = yield exec.exec(`"${this.gitPath}"`, args, options);
|
||||||
result.stdout = stdout.join('');
|
result.stdout = stdout.join('');
|
||||||
|
core.debug(result.exitCode.toString());
|
||||||
|
core.debug(result.stdout);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -13947,6 +13977,7 @@ var encode = function encode(str, defaultEncoder, charset, kind, format) {
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
||||||
|
/* eslint operator-linebreak: [2, "before"] */
|
||||||
out += hexTable[0xF0 | (c >> 18)]
|
out += hexTable[0xF0 | (c >> 18)]
|
||||||
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
|
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
|
||||||
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
|
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
|
||||||
|
@ -17572,7 +17603,7 @@ var parseObject = function (chain, val, options, valuesParsed) {
|
||||||
) {
|
) {
|
||||||
obj = [];
|
obj = [];
|
||||||
obj[index] = leaf;
|
obj[index] = leaf;
|
||||||
} else {
|
} else if (cleanRoot !== '__proto__') {
|
||||||
obj[cleanRoot] = leaf;
|
obj[cleanRoot] = leaf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34704,6 +34735,7 @@ var arrayPrefixGenerators = {
|
||||||
};
|
};
|
||||||
|
|
||||||
var isArray = Array.isArray;
|
var isArray = Array.isArray;
|
||||||
|
var split = String.prototype.split;
|
||||||
var push = Array.prototype.push;
|
var push = Array.prototype.push;
|
||||||
var pushToArray = function (arr, valueOrArray) {
|
var pushToArray = function (arr, valueOrArray) {
|
||||||
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
|
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
|
||||||
|
@ -34740,10 +34772,13 @@ var isNonNullishPrimitive = function isNonNullishPrimitive(v) {
|
||||||
|| typeof v === 'bigint';
|
|| typeof v === 'bigint';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var sentinel = {};
|
||||||
|
|
||||||
var stringify = function stringify(
|
var stringify = function stringify(
|
||||||
object,
|
object,
|
||||||
prefix,
|
prefix,
|
||||||
generateArrayPrefix,
|
generateArrayPrefix,
|
||||||
|
commaRoundTrip,
|
||||||
strictNullHandling,
|
strictNullHandling,
|
||||||
skipNulls,
|
skipNulls,
|
||||||
encoder,
|
encoder,
|
||||||
|
@ -34759,8 +34794,23 @@ var stringify = function stringify(
|
||||||
) {
|
) {
|
||||||
var obj = object;
|
var obj = object;
|
||||||
|
|
||||||
if (sideChannel.has(object)) {
|
var tmpSc = sideChannel;
|
||||||
throw new RangeError('Cyclic object value');
|
var step = 0;
|
||||||
|
var findFlag = false;
|
||||||
|
while ((tmpSc = tmpSc.get(sentinel)) !== void undefined && !findFlag) {
|
||||||
|
// Where object last appeared in the ref tree
|
||||||
|
var pos = tmpSc.get(object);
|
||||||
|
step += 1;
|
||||||
|
if (typeof pos !== 'undefined') {
|
||||||
|
if (pos === step) {
|
||||||
|
throw new RangeError('Cyclic object value');
|
||||||
|
} else {
|
||||||
|
findFlag = true; // Break while
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof tmpSc.get(sentinel) === 'undefined') {
|
||||||
|
step = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof filter === 'function') {
|
if (typeof filter === 'function') {
|
||||||
|
@ -34787,6 +34837,14 @@ var stringify = function stringify(
|
||||||
if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
|
if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
|
||||||
if (encoder) {
|
if (encoder) {
|
||||||
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format);
|
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format);
|
||||||
|
if (generateArrayPrefix === 'comma' && encodeValuesOnly) {
|
||||||
|
var valuesArray = split.call(String(obj), ',');
|
||||||
|
var valuesJoined = '';
|
||||||
|
for (var i = 0; i < valuesArray.length; ++i) {
|
||||||
|
valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset, 'value', format));
|
||||||
|
}
|
||||||
|
return [formatter(keyValue) + (commaRoundTrip && isArray(obj) && valuesArray.length === 1 ? '[]' : '') + '=' + valuesJoined];
|
||||||
|
}
|
||||||
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))];
|
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))];
|
||||||
}
|
}
|
||||||
return [formatter(prefix) + '=' + formatter(String(obj))];
|
return [formatter(prefix) + '=' + formatter(String(obj))];
|
||||||
|
@ -34801,7 +34859,7 @@ var stringify = function stringify(
|
||||||
var objKeys;
|
var objKeys;
|
||||||
if (generateArrayPrefix === 'comma' && isArray(obj)) {
|
if (generateArrayPrefix === 'comma' && isArray(obj)) {
|
||||||
// we need to join elements in
|
// we need to join elements in
|
||||||
objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : undefined }];
|
objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];
|
||||||
} else if (isArray(filter)) {
|
} else if (isArray(filter)) {
|
||||||
objKeys = filter;
|
objKeys = filter;
|
||||||
} else {
|
} else {
|
||||||
|
@ -34809,24 +34867,28 @@ var stringify = function stringify(
|
||||||
objKeys = sort ? keys.sort(sort) : keys;
|
objKeys = sort ? keys.sort(sort) : keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < objKeys.length; ++i) {
|
var adjustedPrefix = commaRoundTrip && isArray(obj) && obj.length === 1 ? prefix + '[]' : prefix;
|
||||||
var key = objKeys[i];
|
|
||||||
var value = typeof key === 'object' && key.value !== undefined ? key.value : obj[key];
|
for (var j = 0; j < objKeys.length; ++j) {
|
||||||
|
var key = objKeys[j];
|
||||||
|
var value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key];
|
||||||
|
|
||||||
if (skipNulls && value === null) {
|
if (skipNulls && value === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyPrefix = isArray(obj)
|
var keyPrefix = isArray(obj)
|
||||||
? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix
|
? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(adjustedPrefix, key) : adjustedPrefix
|
||||||
: prefix + (allowDots ? '.' + key : '[' + key + ']');
|
: adjustedPrefix + (allowDots ? '.' + key : '[' + key + ']');
|
||||||
|
|
||||||
sideChannel.set(object, true);
|
sideChannel.set(object, step);
|
||||||
var valueSideChannel = getSideChannel();
|
var valueSideChannel = getSideChannel();
|
||||||
|
valueSideChannel.set(sentinel, sideChannel);
|
||||||
pushToArray(values, stringify(
|
pushToArray(values, stringify(
|
||||||
value,
|
value,
|
||||||
keyPrefix,
|
keyPrefix,
|
||||||
generateArrayPrefix,
|
generateArrayPrefix,
|
||||||
|
commaRoundTrip,
|
||||||
strictNullHandling,
|
strictNullHandling,
|
||||||
skipNulls,
|
skipNulls,
|
||||||
encoder,
|
encoder,
|
||||||
|
@ -34850,7 +34912,7 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
|
||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.encoder !== null && opts.encoder !== undefined && typeof opts.encoder !== 'function') {
|
if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') {
|
||||||
throw new TypeError('Encoder has to be a function.');
|
throw new TypeError('Encoder has to be a function.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34923,6 +34985,10 @@ module.exports = function (object, opts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];
|
var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];
|
||||||
|
if (opts && 'commaRoundTrip' in opts && typeof opts.commaRoundTrip !== 'boolean') {
|
||||||
|
throw new TypeError('`commaRoundTrip` must be a boolean, or absent');
|
||||||
|
}
|
||||||
|
var commaRoundTrip = generateArrayPrefix === 'comma' && opts && opts.commaRoundTrip;
|
||||||
|
|
||||||
if (!objKeys) {
|
if (!objKeys) {
|
||||||
objKeys = Object.keys(obj);
|
objKeys = Object.keys(obj);
|
||||||
|
@ -34943,6 +35009,7 @@ module.exports = function (object, opts) {
|
||||||
obj[key],
|
obj[key],
|
||||||
key,
|
key,
|
||||||
generateArrayPrefix,
|
generateArrayPrefix,
|
||||||
|
commaRoundTrip,
|
||||||
options.strictNullHandling,
|
options.strictNullHandling,
|
||||||
options.skipNulls,
|
options.skipNulls,
|
||||||
options.encode ? options.encoder : null,
|
options.encode ? options.encoder : null,
|
||||||
|
|
12
package-lock.json
generated
12
package-lock.json
generated
|
@ -17110,9 +17110,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/qs": {
|
"node_modules/qs": {
|
||||||
"version": "6.10.1",
|
"version": "6.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||||
"integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
|
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.4"
|
||||||
},
|
},
|
||||||
|
@ -31553,9 +31553,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.10.1",
|
"version": "6.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||||
"integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
|
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.4"
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,8 +94,11 @@ class GitCommandManager {
|
||||||
|
|
||||||
// Note, this implementation uses "rev-parse --symbolic-full-name" because the output from
|
// Note, this implementation uses "rev-parse --symbolic-full-name" because the output from
|
||||||
// "branch --list" is more difficult when in a detached HEAD state.
|
// "branch --list" is more difficult when in a detached HEAD state.
|
||||||
// Note, this implementation uses "rev-parse --symbolic-full-name" because there is a bug
|
|
||||||
// in Git 2.18 that causes "rev-parse --symbolic" to output symbolic full names.
|
// TODO(https://github.com/actions/checkout/issues/786): this implementation uses
|
||||||
|
// "rev-parse --symbolic-full-name" because there is a bug
|
||||||
|
// in Git 2.18 that causes "rev-parse --symbolic" to output symbolic full names. When
|
||||||
|
// 2.18 is no longer supported, we can switch back to --symbolic.
|
||||||
|
|
||||||
const args = ['rev-parse', '--symbolic-full-name']
|
const args = ['rev-parse', '--symbolic-full-name']
|
||||||
if (remote) {
|
if (remote) {
|
||||||
|
@ -104,21 +107,49 @@ class GitCommandManager {
|
||||||
args.push('--branches')
|
args.push('--branches')
|
||||||
}
|
}
|
||||||
|
|
||||||
const output = await this.execGit(args)
|
const stderr: string[] = []
|
||||||
|
const errline: string[] = []
|
||||||
|
const stdout: string[] = []
|
||||||
|
const stdline: string[] = []
|
||||||
|
|
||||||
for (let branch of output.stdout.trim().split('\n')) {
|
const listeners = {
|
||||||
branch = branch.trim()
|
stderr: (data: Buffer) => {
|
||||||
if (branch) {
|
stderr.push(data.toString())
|
||||||
if (branch.startsWith('refs/heads/')) {
|
},
|
||||||
branch = branch.substr('refs/heads/'.length)
|
errline: (data: Buffer) => {
|
||||||
} else if (branch.startsWith('refs/remotes/')) {
|
errline.push(data.toString())
|
||||||
branch = branch.substr('refs/remotes/'.length)
|
},
|
||||||
}
|
stdout: (data: Buffer) => {
|
||||||
|
stdout.push(data.toString())
|
||||||
result.push(branch)
|
},
|
||||||
|
stdline: (data: Buffer) => {
|
||||||
|
stdline.push(data.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Suppress the output in order to avoid flooding annotations with innocuous errors.
|
||||||
|
await this.execGit(args, false, true, listeners)
|
||||||
|
|
||||||
|
core.debug(`stderr callback is: ${stderr}`)
|
||||||
|
core.debug(`errline callback is: ${errline}`)
|
||||||
|
core.debug(`stdout callback is: ${stdout}`)
|
||||||
|
core.debug(`stdline callback is: ${stdline}`)
|
||||||
|
|
||||||
|
for (let branch of stdline) {
|
||||||
|
branch = branch.trim()
|
||||||
|
if (!branch) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (branch.startsWith('refs/heads/')) {
|
||||||
|
branch = branch.substring('refs/heads/'.length)
|
||||||
|
} else if (branch.startsWith('refs/remotes/')) {
|
||||||
|
branch = branch.substring('refs/remotes/'.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(branch)
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +426,8 @@ class GitCommandManager {
|
||||||
private async execGit(
|
private async execGit(
|
||||||
args: string[],
|
args: string[],
|
||||||
allowAllExitCodes = false,
|
allowAllExitCodes = false,
|
||||||
silent = false
|
silent = false,
|
||||||
|
customListeners = {}
|
||||||
): Promise<GitOutput> {
|
): Promise<GitOutput> {
|
||||||
fshelper.directoryExistsSync(this.workingDirectory, true)
|
fshelper.directoryExistsSync(this.workingDirectory, true)
|
||||||
|
|
||||||
|
@ -409,22 +441,29 @@ class GitCommandManager {
|
||||||
env[key] = this.gitEnv[key]
|
env[key] = this.gitEnv[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
const stdout: string[] = []
|
const defaultListener = {
|
||||||
|
stdout: (data: Buffer) => {
|
||||||
|
stdout.push(data.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mergedListeners = {...defaultListener, ...customListeners}
|
||||||
|
|
||||||
|
const stdout: string[] = []
|
||||||
const options = {
|
const options = {
|
||||||
cwd: this.workingDirectory,
|
cwd: this.workingDirectory,
|
||||||
env,
|
env,
|
||||||
silent,
|
silent,
|
||||||
ignoreReturnCode: allowAllExitCodes,
|
ignoreReturnCode: allowAllExitCodes,
|
||||||
listeners: {
|
listeners: mergedListeners
|
||||||
stdout: (data: Buffer) => {
|
|
||||||
stdout.push(data.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.exitCode = await exec.exec(`"${this.gitPath}"`, args, options)
|
result.exitCode = await exec.exec(`"${this.gitPath}"`, args, options)
|
||||||
result.stdout = stdout.join('')
|
result.stdout = stdout.join('')
|
||||||
|
|
||||||
|
core.debug(result.exitCode.toString())
|
||||||
|
core.debug(result.stdout)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue