저장, CLI, Tasks, CI를 하나로 연결하기
언어별 검사 명령을 Bash 진입점과 VS Code Tasks, CI에 연결하고 버전·경로·설정 충돌을 진단합니다.
자료 확인일: 2026-09-06. 예제는 별도 format-lab 프로젝트에서 순서대로 적용합니다. 명령은 macOS·Linux·WSL의 프로젝트 루트 기준이며, 기존 설정에는 필요한 키를 병합합니다.
실습의 마지막 결과물은 하나의 검사 진입점입니다
선행 포맷 실습을 마치면 저장은 현재 파일을 빠르게 다듬고, CLI는 저장소의 합의한 범위를 검사합니다. 저장 훅 자체를 CI에서 재현하려 하지 않고 같은 설정을 읽는 검사 명령을 공유합니다.
| 경로 | 실행 책임 | 성공 판정 |
|---|---|---|
| VS Code 저장 | 언어별 formatter와 선택한 fix | 해당 파일이 CLI 검사 통과 |
| CLI check | 저장소 전체 합의 범위 | 모든 명령 종료 코드 0 |
| VS Code Task | CLI check 호출 | 터미널 결과와 종료 코드 |
| CI | 고정한 환경 설치 후 같은 check | 깨끗한 checkout에서 통과 |
읽기 전용 검사 script를 만듭니다
이 예제는 모든 이전 실습의 파일과 설정이 있어야 실행됩니다. scripts/check.sh에 저장합니다. 스크립트 위치를 기준으로 루트에 이동하므로 다른 폴더에서 호출해도 같은 설정을 읽습니다.
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/.."
npm run fmt:check
npm run lint
npm run typecheck
uv run --locked yamllint -c .yamllint.yaml -s config
shfmt -ln bash -i 2 -d scripts
shellcheck scripts/*.sh
for script in scripts/*.sh; do
bash -n "$script"
done
bash scripts/check-go-format.sh
(cd go-example && go vet ./... && go test ./...)
uv run --locked ruff format --check python-example
uv run --locked ruff check python-exampleset -e로 첫 실패에서 멈추고 실패한 도구를 먼저 고칩니다. Go 모듈 이동은 subshell 안에서 끝나므로 뒤의 Python 명령은 계속 루트에서 실행됩니다. Go 포맷 실습의 check-go-format.sh도 함께 필요합니다.
여기에는 -w, --fix 같은 수정 옵션을 넣지 않습니다. yamllint·Ruff는 예제 디렉터리, ShellCheck는 바로 아래 .sh 파일, Oxfmt·Oxlint는 각 설정의 제외 규칙을 적용한 범위입니다. 새로운 폴더를 추가할 때 검사 범위도 함께 갱신합니다.
이 검사는 YAML의 애플리케이션 스키마 검증이나 Python의 전체 타입 검사를 포함하지 않습니다. 필요한 보장은 별도 명령으로 추가합니다. 테스트 파일이 없는 Go 예제에서 go test 통과 역시 기능 테스트를 대신하지 않습니다.
수정은 별도 단계에서 실행합니다
먼저 예제의 수동 수정 사항을 모두 반영한 뒤 다음을 한 줄씩 실행합니다. 린터가 자동으로 고치지 못한 오류에서 멈추면 원인을 해결하고 이어갑니다.
npm run lint:fix
npm run fmt
shfmt -ln bash -i 2 -w scripts
gofmt -w go-example
uv run --locked ruff check --fix python-example
uv run --locked ruff format python-example
bash scripts/check.sh
git diff --check
git diff첫 포맷에서는 설정 파일과 script도 정리되어 diff가 생길 수 있습니다. 검토한 뒤 같은 수정 명령을 다시 실행하고 추가 변화가 없는지 확인합니다. git diff --check는 공백 오류 검사이며 다른 formatter와 linter의 대체가 아닙니다.
VS Code Task는 CLI 진입점을 호출합니다
YAML 실습의 .vscode/tasks.json에서 tasks 배열에 다음 객체를 추가합니다.
{
"label": "check",
"type": "process",
"command": "bash",
"args": ["scripts/check.sh"],
"options": { "cwd": "${workspaceFolder}" },
"group": { "kind": "test", "isDefault": true },
"problemMatcher": []
}Tasks: Run Task → check로 실행합니다. 이 task는 여러 도구의 출력을 한 정규식에 억지로 맞추지 않고 터미널로 보여줍니다. YAML 진단이 필요하면 YAML 실습의 lint:yaml task를 사용합니다. type: process와 인수 배열은 경로를 shell 문자열로 조립할 필요를 줄여줍니다. VS Code Tasks
CI도 동일 명령으로 시작합니다
CI runner에는 Node.js·npm, uv·Python, Go SDK, shfmt, ShellCheck를 먼저 설치합니다. 아래는 그 설치 단계 이후의 명령입니다. 완전한 runner provisioning 예제가 아니며 프로젝트가 선택한 CI의 실행 단계에 넣습니다.
npm ci
uv sync --locked
bash scripts/check.shpackage-lock.json과 uv.lock은 반드시 커밋합니다. JS·Python 도구 외에 Go SDK, shfmt, ShellCheck, uv, Node 버전도 runner 이미지나 도구 버전 파일에 고정합니다. 설치 때마다 latest를 고르면 lockfile만으로 전체 환경이 재현되지 않습니다.
다음 출력을 CI 로그와 로컬에서 비교할 수 있습니다.
node --version
npm --version
npm exec -- oxfmt --version
npm exec -- oxlint --version
uv --version
uv run --locked ruff --version
uv run --locked yamllint --version
go version
shfmt --version
shellcheck --version다를 때는 네 가지를 순서대로 확인합니다
| 증상 | 확인할 것 | 조치 |
|---|---|---|
| 저장과 CLI가 번갈아 파일을 바꿈 | formatter·import 액션 중복 | 언어별 default formatter와 저장 액션 정리 |
| 터미널만 도구를 찾음 | 확장 호스트 PATH | Output 경로 확인, 명시적 실행 파일 또는 창 재시작 |
| 특정 하위 폴더만 다름 | cwd·중첩 설정·ignore | 실제 config 탐색과 대상 파일 목록 비교 |
| 로컬 통과, CI 실패 | 버전·lockfile·미추적 파일 | 깨끗한 checkout에서 같은 명령 실행 |
| SSH 창에서만 실패 | 로컬/원격 실행 위치 | 원격에 확장·SDK·의존성 설치 |
VS Code 설정을 공유할 때 개인 절대 경로와 운영체제 전용 경로는 분리합니다. workspace 추천 확장은 설치 안내이며 CLI 도구를 설치하거나 설정을 강제하지 않습니다.
마지막 실습
TS의 any, YAML의 중복 키, Shell의 인용 누락, Go의 잘못된 Printf, Python의 미사용 import를 하나씩 다시 넣습니다. 매번 어떤 명령이 실패하고 어떤 명령은 통과하는지 기록합니다. 전부 고친 뒤 저장 → check Task → CLI check → 깨끗한 checkout의 CI check가 같은 결론인지 확인합니다.
자료 확인은 공식 문서와 설정 계약을 기준으로 했습니다. 실제 VS Code 저장·Problems 이동·원격 확장 동작은 독자의 환경에서 위 절차로 확인해야 합니다. CLI 검사가 통과했다고 해당 GUI 동작까지 검증되었다고 간주하지 않습니다.
이 글의 CLI 검증 기록
2026-09-06에 본문의 코드 블록을 임시 프로젝트로 추출해 Oxfmt 0.66.0, Oxlint 1.81.0, shfmt 3.12.0, ShellCheck 0.9.0, Go 1.27.1, Ruff 0.16.6, yamllint 1.38.0으로 실행했습니다. Oxc와 TypeScript는 작업 환경의 설치본을 사용했고 Python 도구는 uv로 별도 설치했습니다.
잘못된 예제의 예상 실패, 수정 후 통과, 공백을 포함한 Shell 출력, yamllint Problems 정규식, 통합 check.sh, 두 번째 포맷의 추가 변경 없음을 확인했습니다. VS Code GUI와 실제 CI runner 실행은 이 검증에 포함하지 않았습니다.