GitLab ๋ฌด๋ฃ ๋ฒ์ ์๋ ์๋ ๊ฐ์ฅ ํ์ํ ๊ธฐ๋ฅ ์ค ํ๋๋ ํ์ ์ฝ๋ ๊ฒํ ๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ฅ์ ๋ฌดํจํ์ ๋ฐ๋ํ๊ณ ๋ณํฉ ์์ฒญ(MR)์ ์ ์ดํ๋ โโ๊ธฐ๋ฅ์
๋๋ค.
์ต์ํ์ ๊ธฐ๋ฅ์ ์ค์ค๋ก ํด๋ณด์. ์ฌ๋ฌ ๊ฐ๋ฐ์๊ฐ MR์ ์์ง์๊ฐ๋ฝ์ ์น์ผ์ธ์ธ ๋๊น์ง Merge๋ฅผ ๊ธ์งํ ๊ฒ์ด๋ค.
์ด๊ฒ์ด ์ ํ์ํ๊ฐ์?
์ฐ๋ฆฌ ์กฐ์ง์ GitLab ๋ผ์ด์ผ์ค๋ฅผ ์ฝ๊ฒ ๊ตฌ์ ํ ์ฌ์ ๊ฐ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ฐ๋ฐ์ ์ธํฐ๋ท ์ ์ ์์ด ํ์ ๋ฃจํ๋ก ์งํ๋๊ณ ์๊ฒฉํ ์์ฐ ๊ณํ์ด ์๊ธฐ ๋๋ฌธ์ ํ์ํ ๊ธฐ๋ฅ์ ๊ฐ์ถ ์์ฒด ๊ด๋ฆฌํ ๋ผ์ด์ ์ค๋ฅผ ๊ตฌ๋งคํ๋ ๋ฐ ์๊ฐ์์ด ๊ฑธ๋ฆด ์ ์์ง๋ง ์ง๊ธ ์์ ์ ์๋ฃํด์ผ ํฉ๋๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก ๋ค์์ ์ํํด์ผ ํฉ๋๋ค.
- ๋๋ ์ผ๋ถ ๊ฐ๋ฐ์์ ๊ฒฝ์ฐ ๋ณดํธ๋ ๋ธ๋์น์์ ๋ณํฉ์ ์์ ํ ๊ธ์งํ์ง๋ง ๋ณํฉ ๊ถํ์ด ์๋ ๊ฐ๋ฐ์๋ ๋ณด๋์ค๋ก ๋ค๋ฅธ ์ฌ๋์ MR์ ๋ณํฉํ ๋ ์ถฉ๋์ ๋ฐ์ต๋๋ค.
- ๋๋ ์ด์ ๊ณ ์ฉ๋ ์ฃผ๋์ด๋ผ๋ ์ฝ๋ ๊ฒํ ์์ด ๋ง์คํฐ ๋ธ๋์น์ ํต์ ๋์ง ์์ ๋ณํฉ์ ์ํํ ์ ์๋ ๊ธฐํ๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
๋ด๊ฐ ํ ์ฒซ ๋ฒ์งธ ์ผ์ ๋๊ตฐ๊ฐ๊ฐ ์ด๋ฏธ ๋น์ทํ ์ผ์ (์ฝ๋ ์์ ์์ด) ํ์คํ ์ํํ๋ค๊ณ ๋ฏฟ์์ง๋ง ์ปค๋ฎค๋ํฐ ๋ฒ์ ์๋ ์์ง ๊ทธ๋ฌํ ๊ตฌํ์ด ์๋ค๋ ๊ฒ์ด ๋ฐํ์ง Google์ด์์ต๋๋ค.
์ผ๋ฐ์ ์ธ ์์ ๊ณํ
์๋ฅผ ๋ค์ด ํ
์คํธ ์ ์ฅ์์์ ๋ณํฉ ์์ฒญ ์น์ธ์ ๊ตฌ์ฑํด ๋ณด๊ฒ ์ต๋๋ค.
- GitLab API์ ์ก์ธ์คํ๊ธฐ ์ํ ํ ํฐ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฅผ ํตํด "์ฐฌ์ฑ" ๋ฐ "๋ฐ๋" ํฌํ ์์ ๋ํ ์ ๋ณด๋ฅผ ๋ฐ๊ฒ ๋ฉ๋๋ค.
- GitLab ๋ณ์์ ํ ํฐ์ ์ถ๊ฐํด ๋ณด๊ฒ ์ต๋๋ค.
- ํ์ดํ๋ผ์ธ์ ์ค๋ฅ๊ฐ ์๋ ๊ฒฝ์ฐ ๋ณํฉ์ ๋นํ์ฑํํ๊ฒ ์ต๋๋ค(์ฐฌ์ฑ ํฌํ๊ฐ ์ถฉ๋ถํ์ง ์์ ๊ฒฝ์ฐ).
- CI/CD ํ์ดํ๋ผ์ธ์ ์ผ๋ถ๋ก ํฌํ ํ์ธ์ ์ค์ ํด ๋ณด๊ฒ ์ต๋๋ค.
- ๋ณดํธ๋ ๋ธ๋์น์ ๋ํ ์ปค๋ฐ์ ๊ธ์งํฉ๋๋ค. ๋ชจ๋ ๋ณ๊ฒฝ์ MR์ ํตํด์๋ง ์ด๋ฃจ์ด์ง๋๋ค.
- ๊ฒฐ๊ตญ ๋ฌด์จ ์ผ์ด ์ผ์ด๋ฌ๋์ง ํ์ธํด ๋ณด์
1. API์ ์ ๊ทผํ๊ธฐ ์ํ ํ ํฐ ์์ฑ
์ฌ์ฉ์ ์ค์ โ ์ก์ธ์ค ํ ํฐ์ผ๋ก ์ด๋ํ์ฌ ํ ํฐ์ ์ ์ด ๋์ธ์.
ํ ํฐ์ ๋ฐ์ ๊ณ์
API ์ก์ธ์ค๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฆฌํฌ์งํ ๋ฆฌ๋ก ๊ฑฐ์ ๋ชจ๋ ์์
์ ์ํํ ์ ์์ผ๋ฏ๋ก ๋ณ๋์ Gitlab ๊ณ์ ์ ๋ง๋ค์ด ๋ฆฌํฌ์งํ ๋ฆฌ(์: Reporter)์ ๋ํ ์ต์ํ์ ๊ถํ์ ๋ถ์ฌํ๊ณ ํด๋น ๊ณ์ ์ ๋ํ ํ ํฐ์ ์ป๋ ๊ฒ์ด ์ข์ต๋๋ค.
2. Gitlab ๋ณ์์ ํ ํฐ์ ์ถ๊ฐํ์ธ์.
์๋ฅผ ๋ค์ด ์ด์ ๋จ๊ณ์์ ํ ํฐ์ ๋ฐ์์ต๋๋ค. QmN2Y0NOUFlfeXhvd21ZS01aQzgK
์ค์ ์ด๊ธฐ โ CI/CD โ ๋ณ์ โ ๋ณ์ ์ถ๊ฐ โ GITLAB_TOKEN_FOR_CI
๊ฒฐ๊ณผ์ ์ผ๋ก ์ฐ๋ฆฌ๋ ๋ค์์ ์ป์ต๋๋ค:
์ด๋ ํ๋์ ์ ์ฅ์ ๋๋ ์ ์ฅ์ ๊ทธ๋ฃน์์ ์ํํ ์ ์์ต๋๋ค.
3. ์ฝ๋ ๊ฒํ ํ ๋๋ฃ์ ์น์ธ์ ๋ฐ์ง ๋ชปํ ๊ฒฝ์ฐ Merge๋ฅผ ๊ธ์งํฉ๋๋ค.
์ฐ๋ฆฌ์ ๊ฒฝ์ฐ ๋ณํฉ์ ๋ํ ๊ธ์ง ์ฌํญ์ ํฌํ๊ฐ ์ถฉ๋ถํ์ง ์์ผ๋ฉด ์ด์ ๋ธ๋ฆฌ ํ์ดํ๋ผ์ธ์ด ์ค๋ฅ๋ฅผ ๋ฐํํ๋ค๋ ๊ฒ์ ๋๋ค.
์ค์ โ ์ผ๋ฐ โ ๋ณํฉ ์์ฒญ โ ๋ณํฉ ํ์ธ์ผ๋ก ์ด๋ํ์ฌ ์กฐ๋ฆฝ ๋ผ์ธ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋์ด์ผ ํจ ์ต์ ์ ํ์ฑํํฉ๋๋ค.
4. ํ์ดํ๋ผ์ธ ์ค์
์ ํ๋ฆฌ์ผ์ด์
์ ๋ํ CI/CD ํ์ดํ๋ผ์ธ์ ์์ง ์์ฑํ์ง ์์ ๊ฒฝ์ฐ
์ ์ฅ์ ๋ฃจํธ์ ํ์ผ ์์ฑ .gitlab-ci.yml ๊ฐ์ฅ ๊ฐ๋จํ ๋ด์ฉ์ผ๋ก:
stages:
- build
- test
variables:
NEED_VOTES: 1
include:
- remote: "https://gitlab.com/gitlab-ce-mr-approvals/ci/-/raw/master/check-approve.gitlab-ci.yml"
run-myapp:
stage: build
script: echo "Hello world"
CI/CD ๊ตฌ์ฑ์ ์ํ ๋ณ๋์ ์ ์ฅ์
ํ์ดํ๋ผ์ธ์ ๊ตฌ์ฑํ๊ธฐ ์ํด myapp.gitlab-ci.yml ํ์ผ์ ์์ฑํด์ผ ํ๋ ๋ณ๋์ ์ ์ฅ์๋ฅผ ๋ง๋๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋น๋ ํ์ดํ๋ผ์ธ์ ๋ณ๊ฒฝํ๊ณ ์ก์ธ์ค ํ ํฐ์ ๋ฐ์ ์ ์๋ ์ฐธ๊ฐ์์ ์ก์ธ์ค๋ฅผ ๋ ์ ์ ์ดํ ์ ์์ต๋๋ค.
์ ํ์ดํ๋ผ์ธ ํ์ผ์ ์์น๋ myapp ์ ์ฅ์ - ์ค์ - CI/CD - ์กฐ๋ฆฝ ๋ผ์ธ - ์ฌ์ฉ์ ์ ์ CI ๊ตฌ์ฑ ๊ฒฝ๋ก - ์ ํ์ผ ์ง์ ์ผ๋ก ์ด๋ํ์ฌ ์ง์ ํด์ผ ํฉ๋๋ค. myapp.gitlab-ci.yml@gitlab-ce-mr-approvals/Ci
ํ: ๋ฆฐํฐ๋ฅผ ์ฌ์ฉํ์ฌ GitLab CI ํ์ผ ๋ณ๊ฒฝ
ํผ์ ์์
ํ๋๋ผ๋ MR์ ํตํด ์์
ํ๋ ๊ฒ์ ํ์ดํ๋ผ์ธ ํ์ผ์ ๋ํ ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฆฐํฐ๋ฅผ ํตํด ์คํํ๋ ๋ฐ ํฐ ๋์์ด ๋ ๊ฒ์
๋๋ค. YAML ํ์ผ์ ๊ตฌ๋ฌธ์ ์ค์๊ฐ ์์ด๋ ํ๋ก๋์
ํ์ดํ๋ผ์ธ์ด ์ค๋จ๋์ง๋ ์์ง๋ง ๋จ์ํ ๋ณํฉ์ด ์ฐจ๋จ๋ฉ๋๋ค.
ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํ ์ ์๋ Linter๊ฐ ํฌํจ๋ ์ปจํ ์ด๋์ ์:
๊ฒ์ฆ ๋จ๊ณ์ ์:
stages:
- lint
lint:
stage: lint
image: sebiwi/gitlab-ci-validate:1.3.0
variables:
GITLAB_HOST: https://gitlab.com
script:
- CI_FILES=(./*.yml)
- for f in "${CI_FILES[@]}"; do
gitlab-ci-validate $f;
done;
์๋ํ๋ ค๋ฉด ํ์ดํ๋ผ์ธ์ ๋ช ๊ฐ์ง ๋งค๊ฐ๋ณ์๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
stages:
- test
variables:
NEED_VOTES: 1
include:
- remote: "https://gitlab.com/gitlab-ce-mr-approvals/ci/-/raw/master/check-approve.gitlab-ci.yml"
NEED_VOTES ๋ณ์๋ ๋ณํฉ์ ์ฌ์ฉํ ์ ์์ผ๋ ค๋ฉด MR์ด ์ผ๋ง๋ ๋ง์ "์ข์์"๋ฅผ ๊ฐ์ ธ์ผ ํ๋์ง ๊ฒฐ์ ํฉ๋๋ค. XNUMX๊ณผ ๊ฐ์ ๊ฐ์ ์์ ์ด MR์ "์ข์์"๋ฅผ ํ์ํ์ฌ ์น์ธํ ์ ์์์ ์๋ฏธํฉ๋๋ค.
include์๋ '์ข์์' ์๋ฅผ ํ์ธํ๋ ํ ์คํธ ๋จ๊ณ๊ฐ ํฌํจ๋ฉ๋๋ค.
myapp.gitlab-ci.yml์ ์๋ฅผ ์ฌ์ฉํ ๊ฐ์ฅ ๊ฐ๋จํ ํ์ดํ๋ผ์ธ
stages:
- build
- test
variables:
NEED_VOTES: 0
include:
- remote: "https://gitlab.com/gitlab-ce-mr-approvals/ci/-/raw/master/check-approve.gitlab-ci.yml"
run-myapp:
stage: build
image: openjdk
script:
- echo CI_MERGE_REQUEST_TARGET_BRANCH_NAME $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- java HelloWorld.java
๋ด์ฉ check-approve.gitlab-ci.yml
ci-mr:
stage: test
script:
- echo ${CI_API_V4_URL}
- echo "CI_PROJECT_ID ${CI_PROJECT_ID}"
- echo "CI_COMMIT_SHA ${CI_COMMIT_SHA}"
- "export MR_ID=$(curl --silent --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN_FOR_CI" ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests | jq ".[] | if .sha == \"${CI_COMMIT_SHA}\" then .id else {} end" | grep --invert-match {})"
- "export MR_TITLE=$(curl --silent --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN_FOR_CI" ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests | jq ".[] | if .sha == \"${CI_COMMIT_SHA}\" then .title else {} end" | grep --invert-match {})"
- "export MR_WIP=$(curl --silent --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN_FOR_CI" ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests | jq ".[] | if .sha == \"${CI_COMMIT_SHA}\" then .work_in_progress else {} end" | grep --invert-match {})"
- "export MR_UPVOTES=$(curl --silent --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN_FOR_CI" ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests | jq ".[] | if .sha == \"${CI_COMMIT_SHA}\" then .upvotes else {} end" | grep --invert-match {})"
- "export MR_DOWNVOTES=$(curl --silent --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN_FOR_CI" ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests | jq ".[] | if .sha == \"${CI_COMMIT_SHA}\" then .downvotes else {} end" | grep --invert-match {})"
- MR_VOTES=$(expr ${MR_UPVOTES} - ${MR_DOWNVOTES})
- NEED_VOTES_REAL=${NEED_VOTES:-1}
- echo "MR_ID ${MR_ID} MR_TITLE ${MR_TITLE} MR_WIP ${MR_WIP} MR_UPVOTES ${MR_UPVOTES} MR_DOWNVOTES ${MR_DOWNVOTES}"
- echo "MR_VOTES ${MR_VOTES} Up vote = 1, down vote = -1, MR OK if votes >=${NEED_VOTES_REAL}"
- if [ "${MR_VOTES}" -ge "$(expr ${NEED_VOTES_REAL})" ];
then
echo "MR OK";
else
echo "MR ERROR Need more votes";
exit 1;
fi
image: laptevss/gitlab-api-util
rules:
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^release/.*$/'
์ธ์ฆ ์ค์ ๋ฐ์ํ๋ ์ํฉ์ ๋ํ ์ถ๊ฐ ์ ๋ณด:
- master ๋๋ release/* ๋ธ๋์น์์ MR์ ์์ฑํ ๋๋ง ๊ฒ์ฌ๊ฐ ์ํ๋๋ค๋ ์ ํ์ด ์์ต๋๋ค.
- GitLab API๋ฅผ ์ฌ์ฉํ์ฌ "์ข์์"์ "์ซ์ด์" ์๋ฅผ ์ป์ต๋๋ค.
- ๊ธ์ ์ ์ธ ์๋ต๊ณผ ๋ถ์ ์ ์ธ ์๋ต์ ์ฐจ์ด๋ฅผ ๊ณ์ฐํฉ๋๋ค.
- ์ฐจ์ด๊ฐ NEED_VOTES์ ์ค์ ํ ๊ฐ๋ณด๋ค ์์ผ๋ฉด ๋ณํฉ ๊ธฐ๋ฅ์ด ์ฐจ๋จ๋ฉ๋๋ค.
5. ๋ณดํธ๋ ๋ธ๋์น์ ๋ํ ์ปค๋ฐ์ ๊ธ์งํฉ๋๋ค.
์ฐ๋ฆฌ๋ ์ฝ๋ ๊ฒํ ๋ฅผ ์ํํด์ผ ํ๋ ๋ถ๊ธฐ๋ฅผ ์ ์ํ๊ณ MR์ ํตํด์๋ง ์์ ํ ์ ์์์ ๋ํ๋ ๋๋ค.
์ด๋ ๊ฒ ํ๋ ค๋ฉด ์ค์ โ ๋ฆฌํฌ์งํ ๋ฆฌ โ ๋ณดํธ๋ ๋ถ๊ธฐ๋ก ์ด๋ํ์ธ์.
6. ํ์ธ
NEED_VOTES ์ค์ : 0
MR์ ๋ง๋ค๊ณ '์ซ์ด์'๋ฅผ ๋ฃ์ต๋๋ค.
๋น๋ ๋ก๊ทธ์์:
์ด์ "์ข์์"๋ฅผ ์
๋ ฅํ๊ณ ๋ค์ ํ์ธ์ ์์ํ์ธ์.
์ถ์ฒ : habr.com