안녕하세요. 원스토어 iOS Platform팀 강석원입니다.
디자인 시스템 개발환경에 통합하기를 시작으로 어느덧 마지막 포스팅에 다다랐습니다. 이번 포스팅에서는 Figma Variables 추출, Style Dictionary를 사용한 코드 자동 생성의 과정을 CI/CD 파이프라인으로 통합하여 업무 자동화를 적용한 사례를 공유하려고 합니다.
CI/CD란?
CI/CD는 소프트웨어 개발과 배포 과정을 효율적이고 자동화된 방식으로 관리하기 위한 방법입니다.
CI (Continuous Integration)
CI는 개발자가 작성한 코드를 지속적으로 통합하는 과정입니다. 코드가 변경될 때마다 자동으로 빌드(Build)와 테스트(Test)를 수행하여 문제가 발생하지 않는지 확인합니다.
CD (Continuous Deployment/Delivery)
CD는 CI에서 통합된 코드가 실제 제품으로 배포될 준비가 되었는지 확인하는 단계입니다. 이때 코드를 자동으로 배포하는 과정이 이뤄집니다.
정리하면, CI/CD는 반복적이고 시간이 많이 드는 작업들을 자동화하여 업무 프로세스를 개선시키는데 도움을 주는 도구 입니다.
Jenkins란?
Jenkins는 오픈 소스 기반의 자동화 서버로, 다양한 개발 환경과 통합하여 CI/CD를 손쉽게 구축할 수 있도록 도와줍니다. Jenkins의 핵심은 Jenkins Pipeline으로, 스크립트 방식으로 워크플로우를 정의하고 실행할 수 있습니다.
Jenkins의 장점
- 무료로 사용 가능
- 다양한 플러그인
- 사용자 정의가 가능
사용자 정의와 다양한 확장이 가능하기 때문에 저희는 Jenkins Pipeline을 선택했습니다.
이를 기반으로 디자인 시스템을 개발 환경과 통합하여 CI/CD를 구축하는 과정을 이어서 소개하겠습니다.
디자인 시스템 CI/CD 구축
구축한 CI/CD의 흐름도는 위와 같습니다. 이제 하나씩 설명해보겠습니다.
첫 번째 단계입니다. 흐름도를 보고 눈치채신 분들도 있을 것 같습니다. 이 단계는 Figma Variables을 추출하는 커스텀 플러그인 제작기에서 이미 구현한 과정입니다.
디자인 토큰을 Figma Variables에 정의한 뒤, 이를 추출하여 데이터를 동기화하는 과정입니다.
이제부터 이번 포스팅의 핵심인 Jenkins Pipeline에 대해 설명하겠습니다.
Pipeline은 총 5개의 단계(Stage)로 구성되어 있습니다.
1. Clone
stage('Clone') {
steps {
echo "Starting repository clone"
git branch: 'develop', credentialsId: 'developer', url: REPO_URL
echo "Repository cloned successfully"
}
}
가장 먼저, 디자인 토큰 파일이 동기화된 저장소(repository)를 clone합니다.
2. Get Commit Message
stage('Get Commit Message for tokens.zip') {
steps {
script {
def commitMessage = sh(script: "git log -1 --pretty=%B -- ${TOKENS_ZIP_PATH}", returnStdout: true).trim()
echo "Latest Commit Message for tokens.zip: ${commitMessage}"
env.LATEST_COMMIT_MESSAGE = commitMessage
}
}
}
Variables Exporter 플러그인에서 추출한 파일을 동기화할 때, 변경된 내용을 Commit 메시지와 함께 저장했습니다. 이 단계에서는 해당 Commit 메시지를 추출합니다.
3. Unzip tokens
stage('Unzip tokens') {
steps {
echo "Starting tokens unzip process"
sh """
rm -rf ${TOKENS_EXTRACT_PATH}/*
unzip -o ${TOKENS_ZIP_PATH} -d ${TOKENS_EXTRACT_PATH}
"""
echo "Tokens unzipped successfully"
}
}
동기화된 파일은 여러 개의 디자인 토큰이 압축된 zip 파일 형태입니다. 따라서 이 단계에서는 해당 파일의 압축을 해제합니다.
4. Style Dictionary build
stage('Build - SD build') {
steps {
echo "Starting Style Dictionary build"
nodejs('__version__') {
sh """
cd ${SD_BUILD_PATH}
npm run build
cd ..
"""
}
echo "Style Dictionary build completed"
echo "Generating attachment zip files"
sh """
cd ${SD_BUILD_PATH}/build
for dir in ios; do
zip_file="\${dir}.zip"
rm -rf "./\${zip_file}*"
zip -r "\${zip_file}" "\${dir}"
done
"""
echo "Attachment zip files generation completed"
}
}
이 단계에서는 Style Dictionary로 디자인 토큰 자동화 첫 걸음 떼기에서 소개한 Style Dictionary를 빌드해서 코드를 자동으로 생성합니다.
5. Git push
stage('Deploy - add & push') {
steps {
echo "cloning project repository"
script {
def repoDir = './__project_repository__'
// 디렉토리 존재 여부 확인
if (fileExists(repoDir)) {
echo "Directory ${repoDir} already exists. Updating instead of cloning."
dir(repoDir) {
sh "git pull origin __branchName__"
echo "Project update successful"
}
} else {
echo "Cloning repository into ${repoDir}"
sh "git clone -b __branchName__ ${IOS_REPO_URL}"
}
}
echo "Starting git add & push"
script {
def colorsSourcePath = "__colorSourcePath__"
def colorsDestinationPath = "__colorDestinationPath__"
sh "cp -r ${colorsSourcePath} ${colorsDestinationPath}"
dir(colorAssetsDestinationPath) {
// Git 상태 확인
def status = sh(script: 'git status --porcelain', returnStdout: true).trim()
def hasChanges = status.split('\n').any { line ->
!line.trim().startsWith('??') && !line.isEmpty()
}
if (hasChanges) {
sh """
cd ..
ls -l
pwd
git add ./Sources
git commit -m "[ODS] ${env.LATEST_COMMIT_MESSAGE}"
git push origin __branchName__
"""
echo "변경사항이 커밋되고 푸시되었습니다."
} else {
echo "변경사항이 없습니다. 커밋과 푸시를 건너뜁니다."
}
}
}
}
}
Style Dictionary 빌드가 성공하면, 결과물로 생성된 소스 코드를 적용할 대상 프로젝트의 저장소에 add&push합니다. 이때 Git 상태를 체크하여 파일에 변경 사항이 있을 경우에만 동작하도록 구성했습니다.
6. Upload to Wiki
stage('Upload to wiki') {
steps {
script {
echo "Uploading ios.zip..."
def iosDownloadUrl = sh(script: """
curl \\
-X POST \\
-H "Authorization: ${AUTHORIZATION}" -H 'X-Atlassian-Token: nocheck' \\
-F "file=@${SD_BUILD_PATH}/build/${IOS_FILE_NAME}" \\
-F 'minorEdit="true"' \\
-F 'comment="${env.LATEST_COMMIT_MESSAGE}"; type=text/plain; charset=utf-8' \\
${CONFLUENCE_BASE_URL}/rest/api/content/${WIKI_PAGE_ID}/child/attachment/${IOS_FILE_ID}/data 2>/dev/null \\
| /opt/homebrew/bin/jq -r '._links.download'
""", returnStdout: true).trim()
env.IOS_FILE_DOWNLOAD_URL = "${CONFLUENCE_BASE_URL}${iosDownloadUrl}"
echo "ios.zip upload success \n ${iosDownloadUrl}"
}
}
}
결과물이 프로젝트에 바로 반영되기 때문에 이 단계는 생략할 수도 있습니다. 하지만, 빌드된 파일을 사내에서 사용 중인 wiki에 업로드하여 모든 사용자가 확인할 수 있도록 설정했습니다.
여기까지 모든 단계가 마무리되면, Style Dictionary를 통해 자동으로 생성된 소스 코드가 프로젝트에 바로 반영되므로, 디자인 시스템을 개발 환경에 성공적으로 통합하고 업무 프로세스를 자동화할 수 있었습니다.
마치며
이번 프로젝트는 MVP로 개발된 초기 버전으로, 앞으로 수정하고 업데이트해야 할 내용이 많습니다. 예를 들어, 플러그인의 기능을 더욱 확장하거나, Style Dictionary로 자동 생성된 소스 코드를 프로젝트에 직접 반영하는 대신 Maven이나 SPM 같은 의존성 관리 도구를 활용해 모듈로 패키징하여 배포하는 방식으로 개선할 계획입니다.
이번 프로젝트를 통해 업무 효율성을 높이고, 일관성 있는 디자인을 제공함으로써 사용자들이 더욱 편리하게 원스토어 서비스를 이용할 수 있도록 지속적으로 연구하고 개발해 나가겠습니다.
지금까지 긴 글을 읽어주셔서 감사합니다. 😊