mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-11 03:46:49 -07:00
chore(scripts): improve linter portability and fix validation issues
This commit is contained in:
+91
-22
@@ -7,12 +7,12 @@
|
||||
*/
|
||||
|
||||
import { execSync } from 'node:child_process';
|
||||
|
||||
const isWindows = process.platform === 'win32';
|
||||
import { existsSync, lstatSync, readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
const LINTERS = {
|
||||
actionlint: {
|
||||
check: isWindows ? 'where npx node-actionlint 2>nul' : 'command -v npx node-actionlint',
|
||||
check: 'npm list @tktco/node-actionlint --depth=0',
|
||||
installer: 'npm install --save-dev @tktco/node-actionlint',
|
||||
run: `
|
||||
npx node-actionlint \
|
||||
@@ -24,29 +24,56 @@ const LINTERS = {
|
||||
`,
|
||||
},
|
||||
shellcheck: {
|
||||
check: isWindows ? 'where npx shellcheck 2>nul' : 'command -v npx shellcheck',
|
||||
check: 'npm list shellcheck --depth=0',
|
||||
installer: 'npm install --save-dev shellcheck',
|
||||
run: `
|
||||
git ls-files | grep -E '^([^.]+|.*\\.(sh|zsh|bash))' | xargs file --mime-type \
|
||||
| grep "text/x-shellscript" | awk '{ print substr($1, 1, length($1)-1) }' \
|
||||
| xargs npx shellcheck \
|
||||
--check-sourced \
|
||||
--enable=all \
|
||||
--exclude=SC2002,SC2129,SC2310 \
|
||||
--severity=style \
|
||||
--format=gcc \
|
||||
--color=never | sed -e 's/note:/warning:/g' -e 's/style:/warning:/g'
|
||||
`,
|
||||
},
|
||||
yamllint: {
|
||||
check: isWindows ? 'where npx yaml-lint 2>nul' : 'command -v npx yaml-lint',
|
||||
check: 'npm list yaml-lint --depth=0',
|
||||
installer: 'npm install --save-dev yaml-lint',
|
||||
run: isWindows
|
||||
? `powershell -Command "Get-ChildItem -Recurse -Include *.yaml,*.yml | ForEach-Object { npx yaml-lint $_.FullName }"`
|
||||
: "git ls-files | grep -E '\\.(yaml|yml)' | xargs npx yaml-lint",
|
||||
},
|
||||
};
|
||||
|
||||
function getShellScripts() {
|
||||
const allFiles = execSync('git ls-files', { encoding: 'utf-8' })
|
||||
.split('\n')
|
||||
.filter(Boolean);
|
||||
|
||||
return allFiles.filter((file) => {
|
||||
if (
|
||||
file.endsWith('.sh') ||
|
||||
file.endsWith('.zsh') ||
|
||||
file.endsWith('.bash')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
!file.includes('.') &&
|
||||
existsSync(file) &&
|
||||
!lstatSync(file).isDirectory()
|
||||
) {
|
||||
try {
|
||||
const content = readFileSync(file, 'utf-8');
|
||||
const firstLine = content.split('\n')[0];
|
||||
return (
|
||||
firstLine.startsWith('#!') &&
|
||||
(firstLine.includes('sh') ||
|
||||
firstLine.includes('bash') ||
|
||||
firstLine.includes('zsh'))
|
||||
);
|
||||
} catch (_e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function getYamlFiles() {
|
||||
return execSync('git ls-files', { encoding: 'utf-8' })
|
||||
.split('\n')
|
||||
.filter((file) => file.endsWith('.yaml') || file.endsWith('.yml'));
|
||||
}
|
||||
|
||||
function runCommand(command, stdio = 'inherit') {
|
||||
try {
|
||||
execSync(command, { stdio, env: process.env, shell: true });
|
||||
@@ -58,7 +85,7 @@ function runCommand(command, stdio = 'inherit') {
|
||||
|
||||
export function setupLinters() {
|
||||
console.log('Setting up linters...');
|
||||
|
||||
|
||||
for (const linter in LINTERS) {
|
||||
const { check, installer } = LINTERS[linter];
|
||||
if (!runCommand(check, 'ignore')) {
|
||||
@@ -90,14 +117,56 @@ export function runActionlint() {
|
||||
|
||||
export function runShellcheck() {
|
||||
console.log('\nRunning shellcheck...');
|
||||
if (!runCommand(LINTERS.shellcheck.run)) {
|
||||
const files = getShellScripts();
|
||||
if (files.length === 0) {
|
||||
console.log('No shell scripts found.');
|
||||
return;
|
||||
}
|
||||
|
||||
const command = `npx shellcheck \
|
||||
--check-sourced \
|
||||
--enable=all \
|
||||
--exclude=SC2002,SC2129,SC2310 \
|
||||
--severity=style \
|
||||
--format=gcc \
|
||||
--color=never ${files.join(' ')}`;
|
||||
|
||||
try {
|
||||
const output = execSync(command, {
|
||||
env: process.env,
|
||||
encoding: 'utf-8',
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
console.log(
|
||||
output.replace(/note:/g, 'warning:').replace(/style:/g, 'warning:'),
|
||||
);
|
||||
} catch (e) {
|
||||
if (e.stdout) {
|
||||
console.log(
|
||||
e.stdout
|
||||
.toString()
|
||||
.replace(/note:/g, 'warning:')
|
||||
.replace(/style:/g, 'warning:'),
|
||||
);
|
||||
}
|
||||
if (e.stderr) {
|
||||
console.error(e.stderr.toString());
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
export function runYamllint() {
|
||||
console.log('\nRunning yamllint...');
|
||||
if (!runCommand(LINTERS.yamllint.run)) {
|
||||
const files = getYamlFiles();
|
||||
if (files.length === 0) {
|
||||
console.log('No YAML files found.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Use xargs-like behavior but via Node to avoid shell limits and ensure portability
|
||||
// Passing all files at once is generally supported by yaml-lint
|
||||
if (!runCommand(`npx yaml-lint ${files.join(' ')}`)) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
+46
-44
@@ -5,17 +5,17 @@
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <pr#> [model]"
|
||||
if [[ -z "${1}" ]]; then
|
||||
echo "Usage: ${0} <pr#> [model]"
|
||||
exit 1
|
||||
fi
|
||||
pr="$1"
|
||||
pr="${1}"
|
||||
model="${2:-gemini-3.1-pro-preview}"
|
||||
REPO="google-gemini/gemini-cli"
|
||||
REVIEW_DIR="$HOME/git/review/gemini-cli"
|
||||
REVIEW_DIR="${HOME}/git/review/gemini-cli"
|
||||
|
||||
if [ ! -d "$REVIEW_DIR" ]; then
|
||||
echo "ERROR: Directory $REVIEW_DIR does not exist."
|
||||
if [[ ! -d "${REVIEW_DIR}" ]]; then
|
||||
echo "ERROR: Directory ${REVIEW_DIR} does not exist."
|
||||
echo ""
|
||||
echo "Please create a new gemini-cli clone at that directory to use for reviews."
|
||||
echo "Instructions:"
|
||||
@@ -26,54 +26,56 @@ if [ ! -d "$REVIEW_DIR" ]; then
|
||||
fi
|
||||
|
||||
# 1. Check if the PR exists before doing anything else
|
||||
echo "review: Validating PR $pr on $REPO..."
|
||||
if ! gh pr view "$pr" -R "$REPO" > /dev/null 2>&1; then
|
||||
echo "ERROR: Could not find PR #$pr in $REPO."
|
||||
echo "Are you sure $pr is a Pull Request number and not an Issue number?"
|
||||
echo "review: Validating PR ${pr} on ${REPO}..."
|
||||
if ! gh pr view "${pr}" -R "${REPO}" > /dev/null 2>&1; then
|
||||
echo "ERROR: Could not find PR #${pr} in ${REPO}."
|
||||
echo "Are you sure ${pr} is a Pull Request number and not an Issue number?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "review: Opening PR $pr in browser..."
|
||||
if [[ "$(uname)" == "Darwin" ]]; then
|
||||
open "https://github.com/$REPO/pull/$pr" || true
|
||||
echo "review: Opening PR ${pr} in browser..."
|
||||
OS_TYPE=$(uname)
|
||||
if [[ "${OS_TYPE}" == "Darwin" ]]; then
|
||||
open "https://github.com/${REPO}/pull/${pr}" || true
|
||||
else
|
||||
xdg-open "https://github.com/$REPO/pull/$pr" || true
|
||||
xdg-open "https://github.com/${REPO}/pull/${pr}" || true
|
||||
fi
|
||||
|
||||
echo "review: Changing directory to $REVIEW_DIR"
|
||||
cd "$REVIEW_DIR" || exit 1
|
||||
echo "review: Changing directory to ${REVIEW_DIR}"
|
||||
cd "${REVIEW_DIR}" || exit 1
|
||||
|
||||
# 2. Fetch latest main to ensure we have a clean starting point
|
||||
echo "review: Fetching latest from origin..."
|
||||
git fetch origin main
|
||||
|
||||
# 3. Handle worktree creation
|
||||
WORKTREE_PATH="pr_$pr"
|
||||
if [ -d "$WORKTREE_PATH" ]; then
|
||||
echo "review: Worktree directory $WORKTREE_PATH already exists."
|
||||
WORKTREE_PATH="pr_${pr}"
|
||||
if [[ -d "${WORKTREE_PATH}" ]]; then
|
||||
echo "review: Worktree directory ${WORKTREE_PATH} already exists."
|
||||
# Check if it's actually a registered worktree
|
||||
if git worktree list | grep -q "$WORKTREE_PATH"; then
|
||||
WORKTREE_LIST=$(git worktree list)
|
||||
if echo "${WORKTREE_LIST}" | grep -q "${WORKTREE_PATH}"; then
|
||||
echo "review: Reusing existing worktree..."
|
||||
else
|
||||
echo "review: Directory exists but is not a worktree. Cleaning up..."
|
||||
rm -rf "$WORKTREE_PATH"
|
||||
rm -rf "${WORKTREE_PATH}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -d "$WORKTREE_PATH" ]; then
|
||||
echo "review: Adding new worktree at $WORKTREE_PATH..."
|
||||
if [[ ! -d "${WORKTREE_PATH}" ]]; then
|
||||
echo "review: Adding new worktree at ${WORKTREE_PATH}..."
|
||||
# Create a detached worktree from origin/main
|
||||
git worktree add --detach "$WORKTREE_PATH" origin/main
|
||||
git worktree add --detach "${WORKTREE_PATH}" origin/main
|
||||
fi
|
||||
|
||||
echo "review: Changing directory to $WORKTREE_PATH"
|
||||
cd "$WORKTREE_PATH" || exit 1
|
||||
echo "review: Changing directory to ${WORKTREE_PATH}"
|
||||
cd "${WORKTREE_PATH}" || exit 1
|
||||
|
||||
# 4. Checkout the PR
|
||||
echo "review: Cleaning worktree and checking out PR $pr..."
|
||||
echo "review: Cleaning worktree and checking out PR ${pr}..."
|
||||
git reset --hard
|
||||
git clean -fd
|
||||
gh pr checkout "$pr" --branch "review-$pr" -f -R "$REPO"
|
||||
gh pr checkout "${pr}" --branch "review-${pr}" -f -R "${REPO}"
|
||||
|
||||
# 5. Clean and Build
|
||||
echo "review: Clearing possibly stale node_modules..."
|
||||
@@ -87,48 +89,48 @@ npm install
|
||||
|
||||
echo "--- build ---"
|
||||
temp_dir_base="${TMPDIR:-/tmp}"
|
||||
build_log_file=$(mktemp "${temp_dir_base}/npm_build_log.XXXXXX") || {
|
||||
if ! build_log_file=$(mktemp "${temp_dir_base}/npm_build_log.XXXXXX"); then
|
||||
echo "Attempting to create temporary file in current directory as a fallback." >&2
|
||||
build_log_file=$(mktemp "./npm_build_log_fallback.XXXXXX")
|
||||
if [ $? -ne 0 ] || [ -z "$build_log_file" ]; then
|
||||
if ! build_log_file=$(mktemp "./npm_build_log_fallback.XXXXXX"); then
|
||||
echo "ERROR: Critical - Failed to create any temporary build log file. Aborting." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
fi
|
||||
|
||||
build_status=0
|
||||
build_command_to_run="FORCE_COLOR=1 CLICOLOR_FORCE=1 npm run build"
|
||||
|
||||
echo "Running build. Output (with colors) will be shown below and saved to: $build_log_file"
|
||||
echo "Build command: $build_command_to_run"
|
||||
echo "Running build. Output (with colors) will be shown below and saved to: ${build_log_file}"
|
||||
echo "Build command: ${build_command_to_run}"
|
||||
|
||||
if [[ "$(uname)" == "Darwin" ]]; then
|
||||
script -q "$build_log_file" /bin/sh -c "$build_command_to_run"
|
||||
OS_TYPE=$(uname)
|
||||
if [[ "${OS_TYPE}" == "Darwin" ]]; then
|
||||
script -q "${build_log_file}" /bin/sh -c "${build_command_to_run}"
|
||||
build_status=$?
|
||||
else
|
||||
if script -q -e -c "$build_command_to_run" "$build_log_file"; then
|
||||
if script -q -e -c "${build_command_to_run}" "${build_log_file}"; then
|
||||
build_status=0
|
||||
else
|
||||
build_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $build_status -ne 0 ]; then
|
||||
echo "ERROR: npm build failed with exit status $build_status." >&2
|
||||
echo "Review output above. Full log (with color codes) was in $build_log_file." >&2
|
||||
if [[ "${build_status}" -ne 0 ]]; then
|
||||
echo "ERROR: npm build failed with exit status ${build_status}." >&2
|
||||
echo "Review output above. Full log (with color codes) was in ${build_log_file}." >&2
|
||||
exit 1
|
||||
else
|
||||
if grep -q -i -E "\berror\b|\bfailed\b|ERR!|FATAL|critical" "$build_log_file"; then
|
||||
if grep -q -i -E "\berror\b|\bfailed\b|ERR!|FATAL|critical" "${build_log_file}"; then
|
||||
echo "ERROR: npm build completed with exit status 0, but suspicious error patterns were found in the build output." >&2
|
||||
echo "Review output above. Full log (with color codes) was in $build_log_file." >&2
|
||||
echo "Review output above. Full log (with color codes) was in ${build_log_file}." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "npm build completed successfully (exit status 0, no critical error patterns found in log)."
|
||||
rm -f "$build_log_file"
|
||||
rm -f "${build_log_file}"
|
||||
fi
|
||||
|
||||
echo "-- running ---"
|
||||
if ! npm start -- -m "$model" -i="/review-frontend $pr"; then
|
||||
if ! npm start -- -m "${model}" -i="/review-frontend ${pr}"; then
|
||||
echo "ERROR: npm start failed. Please check its output for details." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user