작은 npm 헤드 스크래처

6477 단어 zshnpmbashcli
요전날 나는 재미있는 퍼즐을 만났는데, 그것은 분류하는 것이 재미있었고, 그 과정에서 나는 그것을 적어야 한다고 생각했을 정도로 충분히 배웠다.

설정



AJavaScript project I maintain는 다음과 같은 파일 구조를 가지고 있습니다.

src/
  util/
     slurp.js
  cli-opts.js
test/
  cli-opts.test.js
index.js


JavaScript 프로젝트에 일반적으로 사용하는 두 가지 도구는 테스트용tape과 Linting용eslint이며 궁극적으로 다음과 같이 실행했습니다.

tape test/**/*.test.js
eslint {src,test}/**/*.js *.js


...하지만 실제로는 내 package.json 파일에 npm 스크립트로 저장됩니다.

{
    "scripts": {
      "test": "tape test/**/*.test.js",
      "lint": "eslint {src,test}/**/*.js *.js"
    }
}


...그리고 각각 npm run testnpm run lint로 호출됩니다.

이 명령은 훌륭하게 작동했습니다. 너무 좋아서 사전 커밋 후크에 추가하고 GitHub Actions에서 실행하여 코드가 최상급 품질인지 확인했습니다.

그런 다음 사전 커밋 후크를 통과한 한 코드 변경으로 인해 GitHub 작업이 갑자기 중단되었습니다.

뭐. 지난 몇 년 동안 zsh 셸을 실행한 터미널을 실행하고 npm run lint 를 실행합니다.

오류가 없습니다. 무슨 일이야?

우연한 기회에 스스로 알아내고 싶은 경우(실제 설정 없이는 재미가 없다고 생각합니다) 아래 설명을 읽기 전에 여기에서 멈추십시오.

설명



무슨 일이 일어나고 있는지 껍질입니다.

내가 zsh를 실행한다고 우연히 언급한 것을 기억하십니까? 이것이 중요하다는 것이 밝혀졌습니다. manual for src/cli-opts.js 을 불러오면서 지금까지 알려지지 않은 정보가 다음과 같이 밝혀졌습니다.

The actual shell your script is run within is platform dependent. By default, on Unix-like systems it is the /bin/sh command, on Windows it is the cmd.exe. The actual shell referred to by /bin/sh also depends on the system.



잠시만요, 제가 npm run lint 와 함께 npm 스크립트를 계속 실행하고 있다는 말씀이신가요?!

쉘 선택이 중요한 한 가지 측면은 쉘마다 확장 규칙이 다르다는 것입니다glob.

zsh는 npm run 패턴의 recursive expansion을 지원하므로 GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin19)**/src/**/*.js 모두와 일치하지만 bash 3.2는 전자만 일치합니다. 재귀 확장을 허용하는 버전 4bash gets a src/util/slurp.js option에만 있으며 기본적으로 활성화되지 않을 수도 있습니다.

또한 glob 패턴에 일치하는 파일이 없으면 zsh에서 오류가 발생합니다. 기본적으로 bash는 변경되지 않은 glob 패턴을 출력합니다.

이 두 쌍의 발산 동작에 문제가 있는지 확인하기 위해 zsh 및 bash에서의 확장과 함께 파일 구조와 glob 패턴을 다시 확인하세요.

src/
  util/
     slurp.js
  cli-opts.js
test/
  cli-opts.test.js
index.js

echo test/**/*.test.js
# zsh:
test/cli-opts.test.js
# bash 3.2:
test/**/*.test.js

echo {src,test}/**/*.test.js *.js
# zsh:
src/util/slurp.js 
src/cli-opts.js 
index.js 
test/cli-opts.test.js

# bash 3.2:
src/util/slurp.js 
index.js 
test/**/*.test.js


이제 src/cli-opts.jsglobstar 의 각각의 tape 파일을 보면 둘 다 glob 패키지를 사용하여 glob 패턴을 피연산자로 받아들이고 eslint globstar를 지원하는 것을 볼 수 있습니다. 그들의 확장 패턴.

일치하지 않는 glob에 대한 Bash의 동작, 즉 package.json** 명령에 피연산자로 변경하지 않고 전달하는 것은 (반직관적으로!) 전체 뻔뻔함을 함께 유지하여 bash가 거의 zsh처럼 작동하도록 만드는 핵심입니다. .

그러나 완전히는 아닙니다. 위의 확장을 자세히 살펴보면 bash에서 tape 폴더 바로 아래에 있는 파일 집합을 린트하지 않는다는 것을 알 수 있습니다. linting 명령은 eslint 하위 폴더를 도입한 순간 조용히 깨졌습니다. 이유는 독자에게 연습으로 남겨두겠습니다 :-).

이 미묘한 세부 사항 때문에 대부분의 경우 내 설정에 문제가 있다는 것을 깨닫지 못했습니다. 모든 테스트가 실행되었고 대부분의 파일이 린트되었습니다. src/의 최근 실수가 GitHub Actions에 의해 포착되었지만 로컬이 아닌 경우에만 지그가 올라갔습니다.
src/util 명령이 GitHub 작업에서 작동한 이유는 무엇입니까? 나는 그것을 조사할 에너지가 없었지만 내 생각에 내가 사용하는 특정 Ubuntu 이미지는 src/cli-opts.js 옵션이 활성화된 bash 버전 4 이상을 lint 로 사용할 수 있습니다.

해결책



솔루션은 항상 그렇듯이 셸에서 확장을 방지하기 위해 glob 패턴을 인용하고 /bin/shglobstar 명령에 그대로 전달되도록 하는 것입니다. 그러면 특정 셸에 관계없이 일관되게 확장됩니다. 실행 중.

패키지.json

{
    "scripts": {
      "test": "tape 'test/**/*.test.js'",
      "lint": "eslint '{src,test}/**/*.js' '*.js'"
    }
}


이 글이 도움이 되었기를 바랍니다!

좋은 웹페이지 즐겨찾기