Bumps [gts](https://github.com/google/gts) from 5.3.1 to 6.0.0. - [Release notes](https://github.com/google/gts/releases) - [Changelog](https://github.com/google/gts/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/gts/compare/v5.3.1...v6.0.0) --- updated-dependencies: - dependency-name: gts dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
301 lines
9.3 KiB
TypeScript
301 lines
9.3 KiB
TypeScript
import * as core from '@actions/core';
|
|
import * as path from 'path';
|
|
import simpleGit, {Response} from 'simple-git';
|
|
import {checkInputs, getInput, logOutputs, setOutput} from './io';
|
|
import {log, matchGitArgs, parseInputArray} from './util';
|
|
|
|
const baseDir = path.join(process.cwd(), getInput('cwd') || '');
|
|
const git = simpleGit({baseDir});
|
|
|
|
const exitErrors: Error[] = [];
|
|
|
|
core.info(`Running in ${baseDir}`);
|
|
(async () => {
|
|
await checkInputs();
|
|
|
|
core.startGroup('Internal logs');
|
|
core.info('> Staging files...');
|
|
|
|
const ignoreErrors =
|
|
getInput('pathspec_error_handling') === 'ignore' ? 'pathspec' : 'none';
|
|
|
|
if (getInput('add')) {
|
|
core.info('> Adding files...');
|
|
await add(ignoreErrors);
|
|
} else core.info('> No files to add.');
|
|
|
|
if (getInput('remove')) {
|
|
core.info('> Removing files...');
|
|
await remove(ignoreErrors);
|
|
} else core.info('> No files to remove.');
|
|
|
|
core.info('> Checking for uncommitted changes in the git working tree...');
|
|
const changedFiles = (await git.diffSummary(['--cached'])).files.length;
|
|
// continue if there are any changes or if the allow-empty commit argument is included
|
|
if (
|
|
changedFiles > 0 ||
|
|
matchGitArgs(getInput('commit') || '').includes('--allow-empty')
|
|
) {
|
|
core.info(`> Found ${changedFiles} changed files.`);
|
|
core.debug(
|
|
`--allow-empty argument detected: ${matchGitArgs(
|
|
getInput('commit') || '',
|
|
).includes('--allow-empty')}`,
|
|
);
|
|
|
|
await git
|
|
.addConfig('user.email', getInput('author_email'), undefined, log)
|
|
.addConfig('user.name', getInput('author_name'), undefined, log)
|
|
.addConfig('author.email', getInput('author_email'), undefined, log)
|
|
.addConfig('author.name', getInput('author_name'), undefined, log)
|
|
.addConfig('committer.email', getInput('committer_email'), undefined, log)
|
|
.addConfig('committer.name', getInput('committer_name'), undefined, log);
|
|
core.debug(
|
|
'> Current git config\n' +
|
|
JSON.stringify((await git.listConfig()).all, null, 2),
|
|
);
|
|
|
|
let fetchOption: string | boolean;
|
|
try {
|
|
fetchOption = getInput('fetch', true);
|
|
} catch {
|
|
fetchOption = getInput('fetch');
|
|
}
|
|
if (fetchOption) {
|
|
core.info('> Fetching repo...');
|
|
await git.fetch(
|
|
matchGitArgs(fetchOption === true ? '' : fetchOption),
|
|
log,
|
|
);
|
|
} else core.info('> Not fetching repo.');
|
|
|
|
const targetBranch = getInput('new_branch');
|
|
if (targetBranch) {
|
|
core.info('> Checking-out branch...');
|
|
|
|
if (!fetchOption)
|
|
core.warning(
|
|
'Creating a new branch without fetching the repo first could result in an error when pushing to GitHub. Refer to the action README for more info about this topic.',
|
|
);
|
|
|
|
await git
|
|
.checkout(targetBranch)
|
|
.then(() => {
|
|
log(undefined, `'${targetBranch}' branch already existed.`);
|
|
})
|
|
.catch(() => {
|
|
log(undefined, `Creating '${targetBranch}' branch.`);
|
|
return git.checkoutLocalBranch(targetBranch, log);
|
|
});
|
|
}
|
|
|
|
const pullOption = getInput('pull');
|
|
if (pullOption) {
|
|
core.info('> Pulling from remote...');
|
|
core.debug(`Current git pull arguments: ${pullOption}`);
|
|
await git
|
|
.fetch(undefined, log)
|
|
.pull(undefined, undefined, matchGitArgs(pullOption), log);
|
|
|
|
core.info('> Checking for conflicts...');
|
|
const status = await git.status(undefined, log);
|
|
|
|
if (!status.conflicted.length) {
|
|
core.info('> No conflicts found.');
|
|
core.info('> Re-staging files...');
|
|
if (getInput('add')) await add(ignoreErrors);
|
|
if (getInput('remove')) await remove(ignoreErrors);
|
|
} else
|
|
throw new Error(
|
|
`There are ${
|
|
status.conflicted.length
|
|
} conflicting files: ${status.conflicted.join(', ')}`,
|
|
);
|
|
} else core.info('> Not pulling from repo.');
|
|
|
|
core.info('> Creating commit...');
|
|
await git
|
|
.commit(getInput('message'), matchGitArgs(getInput('commit') || ''))
|
|
.then(async data => {
|
|
log(undefined, data);
|
|
setOutput('committed', 'true');
|
|
setOutput('commit_long_sha', data.commit);
|
|
setOutput('commit_sha', data.commit.substring(0, 7));
|
|
})
|
|
.catch(err => core.setFailed(err));
|
|
|
|
if (getInput('tag')) {
|
|
core.info('> Tagging commit...');
|
|
|
|
if (!fetchOption)
|
|
core.warning(
|
|
'Creating a tag without fetching the repo first could result in an error when pushing to GitHub. Refer to the action README for more info about this topic.',
|
|
);
|
|
|
|
await git
|
|
.tag(matchGitArgs(getInput('tag') || ''), (err, data?) => {
|
|
if (data) setOutput('tagged', 'true');
|
|
return log(err, data);
|
|
})
|
|
.then(data => {
|
|
setOutput('tagged', 'true');
|
|
return log(null, data);
|
|
})
|
|
.catch(err => core.setFailed(err));
|
|
} else core.info('> No tag info provided.');
|
|
|
|
let pushOption: string | boolean;
|
|
try {
|
|
pushOption = getInput('push', true);
|
|
} catch {
|
|
pushOption = getInput('push');
|
|
}
|
|
if (pushOption) {
|
|
// If the options is `true | string`...
|
|
core.info('> Pushing commit to repo...');
|
|
|
|
if (pushOption === true) {
|
|
core.debug(
|
|
`Running: git push origin ${
|
|
getInput('new_branch') || ''
|
|
} --set-upstream`,
|
|
);
|
|
await git.push(
|
|
'origin',
|
|
getInput('new_branch'),
|
|
{'--set-upstream': null},
|
|
(err, data?) => {
|
|
if (data) setOutput('pushed', 'true');
|
|
return log(err, data);
|
|
},
|
|
);
|
|
} else {
|
|
core.debug(`Running: git push ${pushOption}`);
|
|
await git.push(
|
|
undefined,
|
|
undefined,
|
|
matchGitArgs(pushOption),
|
|
(err, data?) => {
|
|
if (data) setOutput('pushed', 'true');
|
|
return log(err, data);
|
|
},
|
|
);
|
|
}
|
|
|
|
if (getInput('tag')) {
|
|
core.info('> Pushing tags to repo...');
|
|
|
|
await git
|
|
.pushTags('origin', matchGitArgs(getInput('tag_push') || ''))
|
|
.then(data => {
|
|
setOutput('tag_pushed', 'true');
|
|
return log(null, data);
|
|
})
|
|
.catch(err => core.setFailed(err));
|
|
} else core.info('> No tags to push.');
|
|
} else core.info('> Not pushing anything.');
|
|
|
|
core.endGroup();
|
|
core.info('> Task completed.');
|
|
} else {
|
|
core.endGroup();
|
|
core.info('> Working tree clean. Nothing to commit.');
|
|
}
|
|
})()
|
|
.then(() => {
|
|
// Check for exit errors
|
|
if (exitErrors.length === 1) throw exitErrors[0];
|
|
else if (exitErrors.length > 1) {
|
|
exitErrors.forEach(e => core.error(e));
|
|
throw 'There have been multiple runtime errors.';
|
|
}
|
|
})
|
|
.then(logOutputs)
|
|
.catch(e => {
|
|
core.endGroup();
|
|
logOutputs();
|
|
core.setFailed(e);
|
|
});
|
|
|
|
async function add(ignoreErrors: 'all' | 'pathspec' | 'none' = 'none') {
|
|
const input = getInput('add');
|
|
if (!input) return [];
|
|
|
|
const parsed = parseInputArray(input);
|
|
const res: (string | void)[] = [];
|
|
|
|
for (const args of parsed) {
|
|
res.push(
|
|
// Push the result of every git command (which are executed in order) to the array
|
|
// If any of them fails, the whole function will return a Promise rejection
|
|
await git
|
|
.add(matchGitArgs(args), (err, data) =>
|
|
log(ignoreErrors === 'all' ? null : err, data),
|
|
)
|
|
.catch((e: Error) => {
|
|
// if I should ignore every error, return
|
|
if (ignoreErrors === 'all') return;
|
|
|
|
// if it's a pathspec error...
|
|
if (
|
|
e.message.includes('fatal: pathspec') &&
|
|
e.message.includes('did not match any files')
|
|
) {
|
|
if (ignoreErrors === 'pathspec') return;
|
|
|
|
const peh = getInput('pathspec_error_handling'),
|
|
err = new Error(
|
|
`Add command did not match any file: git add ${args}`,
|
|
);
|
|
if (peh === 'exitImmediately') throw err;
|
|
if (peh === 'exitAtEnd') exitErrors.push(err);
|
|
} else throw e;
|
|
}),
|
|
);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
async function remove(
|
|
ignoreErrors: 'all' | 'pathspec' | 'none' = 'none',
|
|
): Promise<(void | Response<void>)[]> {
|
|
const input = getInput('remove');
|
|
if (!input) return [];
|
|
|
|
const parsed = parseInputArray(input);
|
|
const res: (void | Response<void>)[] = [];
|
|
|
|
for (const args of parsed) {
|
|
res.push(
|
|
// Push the result of every git command (which are executed in order) to the array
|
|
// If any of them fails, the whole function will return a Promise rejection
|
|
await git
|
|
.rm(matchGitArgs(args), (e, d) =>
|
|
log(ignoreErrors === 'all' ? null : e, d),
|
|
)
|
|
.catch((e: Error) => {
|
|
// if I should ignore every error, return
|
|
if (ignoreErrors === 'all') return;
|
|
|
|
// if it's a pathspec error...
|
|
if (
|
|
e.message.includes('fatal: pathspec') &&
|
|
e.message.includes('did not match any files')
|
|
) {
|
|
if (ignoreErrors === 'pathspec') return;
|
|
|
|
const peh = getInput('pathspec_error_handling'),
|
|
err = new Error(
|
|
`Remove command did not match any file:\n git rm ${args}`,
|
|
);
|
|
if (peh === 'exitImmediately') throw err;
|
|
if (peh === 'exitAtEnd') exitErrors.push(err);
|
|
} else throw e;
|
|
}),
|
|
);
|
|
}
|
|
|
|
return res;
|
|
}
|