GitHub 작업을 사용하여 지속적 통합 테스트 워크플로 생성

게시 됨: 2022-03-10
빠른 요약 ↬ 이 튜토리얼을 통해 GitHub Actions를 사용하여 Node JS REST API에 대한 지속적인 통합 워크플로를 만드는 방법과 Coveralls로 테스트 커버리지를 보고하는 방법을 배울 수 있습니다.

GitHub 및 Bitbucket과 같은 버전 제어 플랫폼에서 프로젝트에 기여할 때 관례는 기능 코드베이스를 포함하는 기본 분기가 있다는 것입니다. 그런 다음 몇 가지 개발자가 메인의 사본에서 새로운 기능을 추가하고 버그 수정 등을 수정하는 다른 지점이 있습니다. 들어오는 변경 사항이 기존 코드에 적용되는 영향의 종류를 더 쉽게 모니터링하는 것이 더 쉬워지기 때문에 많은 의미가 있습니다. 오류가 있으면 변경 사항을 메인 브랜치에 통합하기 전에 쉽게 추적하고 수정할 수 있습니다. 소규모 프로젝트를 위해서도 수동으로 오류 나 버그를 찾는 모든 코드 줄을 수동으로 찾는 데 시간이 많이 걸릴 수 있습니다. 바로 여기에서 지속적인 통합이 필요합니다.

지속적 통합(CI)이란 무엇입니까?

"지속적 통합(CI)은 여러 기여자의 코드 변경 사항을 단일 소프트웨어 프로젝트로 자동화하는 방식입니다."

— Atlassian.com

CI(지속적 통합)의 기본 개념은 프로젝트에 대한 변경 사항이 "빌드를 중단"하지 않도록, 즉 기존 코드 기반을 망치지 않도록 하는 것입니다. 워크플로를 설정하는 방법에 따라 프로젝트에서 지속적 통합을 구현하면 누구든지 리포지토리를 변경할 때마다 빌드가 생성됩니다.

그렇다면 빌드란 무엇인가?

이 컨텍스트에서 빌드는 소스 코드를 실행 가능한 형식으로 컴파일하는 것입니다. 성공한 경우 들어오는 변경 사항이 코드베이스에 부정적인 영향을 미치지 않으며,가는 것이 좋습니다. 그러나 빌드가 실패하면 변경 사항을 재평가해야 합니다. 그렇기 때문에 메인 코드베이스에 통합하기 전에 다른 브랜치에서 프로젝트 복사본을 작업하여 프로젝트를 변경하는 것이 좋습니다. 이렇게하면 빌드가 끊어지면 오류가 어디에서 오는 위치가 있는지 파악하는 것이 더 쉽고 기본 소스 코드에 영향을주지 않습니다.

"결함을 일찍 발견할수록 수리 비용이 저렴해집니다."

— David Farley, 지속적 전달: 빌드, 테스트 및 배포 자동화를 통한 안정적인 소프트웨어 릴리스

프로젝트에 대한 지속적인 통합을 만드는 데 도움이 되는 몇 가지 도구가 있습니다. 여기에는 Jenkins, Travisci, Circleci, Gitlab CI, Github Actions 등이 포함됩니다.이 자습서에는 GitHub 작업을 사용할 것입니다.

지속적 통합을 위한 GitHub 작업

CI 작업은 GitHub의 상당히 새로운 기능이며 프로젝트의 빌드 및 테스트를 자동으로 실행하는 워크 플로 생성을 가능하게합니다. 워크플로에는 이벤트가 발생할 때 활성화할 수 있는 하나 이상의 작업이 포함됩니다. 이 이벤트는 리포지토리의 모든 분기에 대한 푸시 또는 풀 요청 생성일 수 있습니다. 진행하면서 이 용어에 대해 자세히 설명하겠습니다.

시작하자!

전제 조건

이것은 초보자를 위한 자습서이므로 표면 수준에서 GitHub Actions CI에 대해 주로 이야기하겠습니다. 독자는 PostgreSQL 데이터베이스, Sequelize ORM을 사용하여 Node JS REST API를 만들고 Mocha 및 Chai로 테스트를 작성하는 데 이미 익숙해야 합니다.

또한 컴퓨터에 다음이 설치되어 있어야 합니다.

  • 노드 js,
  • PostgreSQL,
  • npm,
  • VSCode(또는 선택한 편집기 및 터미널).

내가 이미 만든 countries-info-api 라는 REST API를 사용할 것입니다. 역할 기반 인증이 없는 간단한 API입니다(이 튜토리얼을 작성할 당시). 즉, 누구나 국가 세부 정보를 추가, 삭제 및/또는 업데이트할 수 있습니다. 각 국가에는 ID(자동 생성 UUID), 이름, 자본 및 인구가 있습니다. 이를 달성하기 위해 Node js, express js 프레임워크 및 데이터베이스용 Postgresql을 사용했습니다.

테스트 커버리지를 위한 테스트와 지속적인 통합을 위한 워크플로 파일 작성을 시작하기 전에 서버, 데이터베이스를 설정하는 방법을 간략하게 설명하겠습니다.

countries-info-api repo를 복제하여 자체 API를 생성하거나 수행할 수 있습니다.

사용기술 : Node Js, NPM(Javascript용 패키지 관리자), Postgresql 데이터베이스, Sequelize ORM, Babel.

점프 후 더! 아래에서 계속 읽기 ↓

서버 설정

서버를 설정하기 전에 npm에서 몇 가지 종속성을 설치했습니다.

 npm install express dotenv cors npm install --save-dev @babel/core @babel/cli @babel/preset-env nodemon

익스프레스 프레임워크를 사용하고 ES6 형식으로 작성하고 있으므로 내 코드를 컴파일하려면 Babeljs가 필요합니다. 공식 문서를 읽고 작동 방식과 프로젝트에 맞게 구성하는 방법에 대해 자세히 알아볼 수 있습니다. Nodemon은 코드에 대한 변경 사항을 감지하고 자동으로 서버를 다시 시작합니다.

참고 : --save --save-dev 플래그를 사용하여 설치된 Npm 패키지는 개발 단계에서만 필요하며 package.json 파일의 devDependencies 아래에 표시됩니다.

index.js 파일에 다음을 추가했습니다.

 import express from "express"; import bodyParser from "body-parser"; import cors from "cors"; import "dotenv/config"; const app = express(); const port = process.env.PORT; app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(cors()); app.get("/", (req, res) => { res.send({message: "Welcome to the homepage!"}) }) app.listen(port, () => { console.log(`Server is running on ${port}...`) })

이것은 .env 파일의 PORT 변수에 할당된 모든 항목에서 실행되도록 API를 설정합니다. 여기에서 다른 사람들이 쉽게 액세스할 수 없도록 하는 변수를 선언할 것입니다. dotenv npm 패키지는 .env 에서 환경 변수를 로드합니다.

이제 터미널에서 npm run start 를 실행하면 다음과 같이 표시됩니다.

서버 실행
포트 3000에서 서버가 실행 중입니다. (큰 미리보기)

보시다시피 서버가 가동 중입니다. 야!

웹 브라우저의 https://127.0.0.1:your_port_number/ 링크는 환영 메시지를 반환해야 합니다. 즉, 서버가 실행되고 있는 동안입니다.

브라우저
홈페이지. (큰 미리보기)

다음으로 데이터베이스 및 모델입니다.

Sequelize를 사용하여 국가 모델을 만들고 Postgres 데이터베이스에 연결했습니다. Sequelize는 Nodejs용 ORM입니다. 주요 이점은 원시 SQL 쿼리를 작성하는 시간을 절약할 수 있다는 것입니다.

PostgreSQL을 사용하고 있기 때문에 데이터베이스 CREATE DATABASE database_name 명령을 사용하여 PSQL 명령 줄을 통해 데이터베이스를 만들 수 있습니다. 이것은 터미널에서도 수행할 수 있지만 PSQL Shell을 선호합니다.

env 파일에서 아래 형식에 따라 데이터베이스의 연결 문자열을 설정합니다.

 TEST_DATABASE_URL = postgres://<db_username>:<db_password>@127.0.0.1:5432/<database_name>

내 모델의 경우 이 후속 튜토리얼을 따랐습니다. 따라하기 쉽고 Sequelize 설정에 대한 모든 것을 설명합니다.

다음으로 방금 만든 모델에 대한 테스트를 작성하고 Coverall에서 적용 범위를 설정합니다.

테스트 작성 및 보고 범위

왜 테스트를 작성합니까? 개인적으로 테스트 작성은 개발자가 브레인스토밍 프로세스이기 때문에 소프트웨어가 사용자의 손에서 어떻게 수행될 것으로 예상되는지 더 잘 이해하는 데 도움이 된다고 생각합니다. 또한 적시에 버그를 발견하는 데 도움이 됩니다.

테스트 :

그러나이 튜토리얼에서는 다른 소프트웨어 테스트 방법이 있습니다. 단위 및 엔드 투 엔드 테스트를 사용했습니다.

Mocha 테스트 프레임워크와 Chai 어설션 라이브러리를 사용하여 테스트를 작성했습니다. 또한 sequelize.define 을 사용하여 생성한 모델을 테스트하는 데 도움이 되도록 sequelize-test-helpers 를 설치했습니다.

테스트 범위:

결과는 테스트 케이스가 실제로 코드를 커버하는지 여부와 테스트 케이스를 실행할 때 얼마나 많은 코드가 사용되는지를 보여주기 때문에 테스트 커버리지를 확인하는 것이 좋습니다.

나는 Istanbul(테스트 커버리지 도구), nyc(Instabul의 CLI 클라이언트) 및 Coveralls를 사용했습니다.

문서에 따르면, Istanbul은 라인 카운터를 사용하여 ES5 및 ES2015+ JavaScript 코드를 계측하므로 단위 테스트가 코드베이스를 얼마나 잘 활용하는지 추적할 수 있습니다.

package.json 파일에서 테스트 스크립트는 테스트를 실행하고 보고서를 생성합니다.

 { "scripts": { "test": "nyc --reporter=lcov --reporter=text mocha -r @babel/register ./src/test/index.js" } }

이 과정에서 원시 적용 정보가 포함된 .nyc_output 폴더와 적용 보고서 파일이 포함된 coverage 폴더를 생성합니다. 두 파일 모두 내 저장소에 필요하지 않으므로 .gitignore 파일에 배치했습니다.

이제 보고서를 생성했으므로 Coveralls로 보내야 합니다. Coveralls(및 기타 적용 범위 도구)의 멋진 점 중 하나는 테스트 적용 범위를 보고하는 방법입니다. 적용 범위는 파일별로 분류되어 관련 적용 범위, 적용 및 누락된 라인, 빌드 적용 범위에서 변경된 사항을 볼 수 있습니다.

시작하려면 작업복 npm 패키지를 설치하세요. 또한 작업복에 로그인하고 저장소를 추가해야 합니다.

작업복 저장소
작업복에 연결된 리포지토리. (큰 미리보기)

그런 다음 루트 디렉토리에 coveralls.yml 파일을 만들어 자바스크립트 프로젝트에 대한 작업복을 설정합니다. 이 파일은 작업복의 저장소에 대한 설정 섹션에서 가져온 repo-token 을 보관합니다.

package.json 파일에 필요한 또 다른 스크립트는 커버리지 스크립트입니다. 이 스크립트는 Actions를 통해 빌드를 생성할 때 유용합니다.

 { "scripts": { "coverage": "nyc npm run test && nyc report --reporter=text-lcov --reporter=lcov | node ./node_modules/coveralls/bin/coveralls.js --verbose" } }

기본적으로 테스트를 실행하고 보고서를 가져와 분석을 위해 작업복으로 보냅니다.

이제 이 튜토리얼의 요점으로.

노드 JS 워크플로 파일 생성

이 시점에서 GitHub 작업에서 실행할 필요한 작업을 설정했습니다. ("작업"이 무엇을 의미하는지 궁금하십니까? 계속 읽으십시오.)

GitHub에서는 스타터 템플릿을 제공하여 워크플로 파일을 쉽게 만들 수 있습니다. 작업 페이지에 표시된 것처럼 다양한 용도로 사용되는 여러 워크플로 템플릿이 있습니다. 이 자습서에서는 Node.js 워크플로(GitHub이 이미 친절하게 제안한)를 사용합니다.

작업 페이지
GitHub 작업 페이지. (큰 미리보기)

GitHub에서 직접 파일을 편집할 수 있지만 로컬 저장소에 수동으로 파일을 생성하겠습니다. node.js.yml 파일이 포함된 .github/workflows 폴더는 루트 디렉터리에 있습니다.

이 파일에는 이미 몇 가지 기본 명령이 포함되어 있으며 첫 번째 주석은 해당 명령이 수행하는 작업을 설명합니다.

 # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node

위의 설명 외에도 적용 범위를 실행하도록 일부 변경하겠습니다.

.node.js.yml 파일:

 name: NodeJS CI on: ["push"] jobs: build: name: Build runs-on: windows-latest strategy: matrix: node-version: [12.x, 14.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - run: npm install - run: npm run build --if-present - run: npm run coverage - name: Coveralls uses: coverallsapp/github-action@master env: COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} COVERALLS_GIT_BRANCH: ${{ github.ref }} with: github-token: ${{ secrets.GITHUB_TOKEN }}

이것은 무엇을 의미 하는가?

분해해 봅시다.

  • name
    이것은 워크 플로우 (NodeJS CI) 또는 작업 (빌드)의 이름이며 GitHub은 리포지토리의 작업 페이지에 표시됩니다.
  • on
    워크플로를 트리거하는 이벤트입니다. 내 파일의 해당 줄은 기본적으로 GitHub에 내 저장소에 푸시가 있을 때마다 워크플로를 트리거하도록 지시합니다.
  • jobs
    워크플로에는 하나 이상의 작업이 포함될 수 있으며 각 작업은 runs-on 지정된 환경에서 실행됩니다. 위의 파일 샘플에서는 빌드를 실행하고 커버리지를 실행하고 Windows 환경에서 실행됩니다. 다음과 같이 두 개의 다른 작업으로 분리할 수도 있습니다.

업데이트된 Node.yml 파일

 name: NodeJS CI on: [push] jobs: build: name: Build runs-on: windows-latest strategy: matrix: node-version: [12.x, 14.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - run: npm install - run: npm run build --if-present - run: npm run test coverage: name: Coveralls runs-on: windows-latest strategy: matrix: node-version: [12.x, 14.x] steps: - uses: coverallsapp/github-action@master env: COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} with: github-token: ${{ secrets.GITHUB_TOKEN }}
  • env
    여기에는 워크플로의 모든 또는 특정 작업 및 단계에 사용할 수 있는 환경 변수가 포함됩니다. Coverage 작업에서 환경 변수가 "숨겨진" 것을 볼 수 있습니다. 설정 아래 저장소의 비밀 페이지에서 찾을 수 있습니다.
  • steps
    이것은 기본적으로 해당 작업을 실행할 때 취해야 할 단계의 목록입니다.
  • build 작업은 다음과 같은 여러 작업을 수행합니다.
    • 워크 플로가 액세스 할 수 있도록 리포지토리를 문자 그대로 체크 아웃하는 체크 아웃 동작 (V2가 버전을 의미합니다)을 사용합니다.
    • 사용할 노드 환경을 설정하는 setup-node 작업을 사용합니다.
    • package.json 파일에 있는 설치, 빌드 및 테스트 스크립트를 실행합니다.
  • coverage
    이것은 분석을 위해 테스트 스위트의 LCOV 범위 데이터를 coveralls.io에 게시하는 coverallsapp 작업을 사용합니다.
성공적인 직업
모든 작업이 성공적으로 실행됩니다. (큰 미리보기)

나는 처음에 내 feat-add-controllers-and-route 브랜치를 푸시했고 Coveralls의 repo_token을 내 .coveralls.yml 파일에 추가하는 것을 잊었습니다. 그래서 132행에서 볼 수 있는 오류가 발생했습니다.

빌드 실패
작업복의 구성 파일 오류로 인해 작업이 실패했습니다. (큰 미리보기)
 Bad response: 422 {"message":"Couldn't find a repository matching this job.","error":true}

repo_token 을 추가하면 빌드가 성공적으로 실행될 수 있었습니다. 이 토큰이 없으면 작업복이 내 테스트 커버리지 분석을 제대로 보고할 수 없습니다. 다행인 것은 GitHub Actions CI가 오류가 메인 브랜치로 푸시되기 전에 지적했다는 점입니다.

성공적인 빌드
오류가 수정되었습니다. 작업이 성공했습니다. 야! (큰 미리보기)

주의: 작업을 두 작업으로 나누기 전에 찍은 것입니다. 또한 커버리지 스크립트 끝에 --verbose 플래그를 추가했기 때문에 터미널에서 커버리지 요약 및 오류 메시지를 볼 수 있었습니다.

결론

프로젝트에 대한 지속적인 통합을 설정하는 방법과 GitHub에서 제공하는 작업을 사용하여 테스트 커버리지를 통합하는 방법을 확인할 수 있습니다. 프로젝트의 요구 사항에 맞게 조정할 수 있는 다른 방법이 많이 있습니다. 이 튜토리얼에서 사용된 샘플 repo는 정말 사소한 프로젝트이지만 더 큰 프로젝트에서도 지속적인 통합이 얼마나 필수적인지 알 수 있습니다. 이제 작업이 성공적으로 실행되었으므로 분기를 주 분기와 병합할 수 있습니다. 나는 여전히 모든 실행 후에 단계의 결과를 읽고 완전히 성공적인지 확인하는 것이 좋습니다.