Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Github Actions 로 Android 팀의 효율성 극대화
Search
Harada Ha
July 21, 2024
Technology
0
310
Github Actions 로 Android 팀의 효율성 극대화
Google I/O extended Android 2024 때 발표한 자료 입니다.
Harada Ha
July 21, 2024
Tweet
Share
More Decks by Harada Ha
See All by Harada Ha
빠른 안드로이드 개발에 대한 프로세스 알아보기
hadonghyun
0
650
Privacy Changes in Android Q
hadonghyun
1
420
지금까지 이런 간단한 Logic 처리는 없었다 이것은 Rx 인가, UI 이벤트인가? 네, RxBinding입니다.
hadonghyun
1
220
Other Decks in Technology
See All in Technology
Terraformで構築する セルフサービス型データプラットフォーム / terraform-self-service-data-platform
pei0804
1
170
下手な強制、ダメ!絶対! 「ガードレール」を「檻」にさせない"ガバナンス"の取り方とは?
tsukaman
2
430
研究開発と製品開発、両利きのロボティクス
youtalk
1
520
5年目から始める Vue3 サイト改善 #frontendo
tacck
PRO
3
220
なぜテストマネージャの視点が 必要なのか? 〜 一歩先へ進むために 〜
moritamasami
0
220
Agile PBL at New Grads Trainings
kawaguti
PRO
1
410
20250910_障害注入から効率的復旧へ_カオスエンジニアリング_生成AIで考えるAWS障害対応.pdf
sh_fk2
3
240
ZOZOマッチのアーキテクチャと技術構成
zozotech
PRO
3
1.5k
AIのグローバルトレンド2025 #scrummikawa / global ai trend
kyonmm
PRO
1
270
サラリーマンの小遣いで作るtoCサービス - Cloudflare Workersでスケールする開発戦略
shinaps
2
420
「全員プロダクトマネージャー」を実現する、Cursorによる仕様検討の自動運転
applism118
21
10k
EncryptedSharedPreferences が deprecated になっちゃった!どうしよう! / Oh no! EncryptedSharedPreferences has been deprecated! What should I do?
yanzm
0
230
Featured
See All Featured
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
The Pragmatic Product Professional
lauravandoore
36
6.9k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
The World Runs on Bad Software
bkeepers
PRO
70
11k
We Have a Design System, Now What?
morganepeng
53
7.8k
Build your cross-platform service in a week with App Engine
jlugia
231
18k
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.7k
The Straight Up "How To Draw Better" Workshop
denniskardys
236
140k
How to train your dragon (web standard)
notwaldorf
96
6.2k
GraphQLの誤解/rethinking-graphql
sonatard
72
11k
Stop Working from a Prison Cell
hatefulcrawdad
271
21k
Fireside Chat
paigeccino
39
3.6k
Transcript
하동현 / @harada.ha Github Actions 로 Android 팀의 효율성 극대화
성장하는 팀, 늘어나는 업무: Github Actions 도입 배경 Section 1
H사 2 ~ 3명 Section 1 # 소통의 용이함 #
자원 부족 # 단순한 관리
B사 5 ~ 8명 Section 1 # 소통의 복잡성 증가
# 복잡한 워크플로우 # 안정된 운영
K사 10명 Section 1 # 향상된 안정성 # 관리 오버헤드
K사 bitrise B사 Github Actions Section 1
Github Actions Section 1
Github Actions 개요
Github Actions Section 1 # CI / CD
Event Runner 1 Runner 2 Job 1 Job 2 Runner
1 Runner 2 Step 1 : Run action Step 2 : Run script Step 1 : Run action Section 1
pull_request, issue_comment, workflow_dispatch, … Events on : pull_request : types
: [opened, synchronize] Section 1
Event Runner 1 Runner 2 Job 1 Job 2 Runner
1 Runner 2 Step 1 : Run action Step 2 : Run script Step 1 : Run action Section 1
Event Runner 1 Runner 2 Job 1 Job 2 Runner
1 Runner 2 Step 1 : Run action Step 2 : Run script Step 1 : Run action Section 1
Job 을 구성하는 작은 단계 Actions steps : # 체크아웃
액션: 저장소의 코드를 체크아웃 - - name : Check out Code uses : actions/checkout@v3 # 액션: 코드 컴파일 - name : Build the project run : ./gradlew assembleDebug Section 1
Event Runner 1 Runner 2 Job 1 Job 2 Runner
1 Runner 2 Step 1 : Run action Step 2 : Run script Step 1 : Run action Section 1
None
효율적인 워크플로우 구축: Github Action 적용 사례 Section 2
Android PR Board Section 2
Android PR Board Section 2
- Ts : 수동으로 카드 하나를 생성하는 데 걸리는 시간
= 20초 - R : PR 당 리뷰어의 수 = 2명 - P : PR의 수 = 3개 - C : 총 생성해야 하는 카드의 수 = R×P = 6개 Total_s = C×Ts = 6×20 = 2분 PR 카드 생성 시간 Section 2 Section 2
PR 카드 생성 시간 Section 2 1일 기준 = 2분
× 5명 = 10분 근무 21일 기준 = 210분 = 3.5시간
GitHub Docs Section # Section 2
PR 카드 생성 자동화로 시간 절약 3.5H Save Section #
Section 2
PR Review Workflow
PR Review Workflow Section 2 /review @notifier, @notifier
PR Review Workflow Section 2 set-reviewers
PR Review Workflow Section # Section 2 create-card
PR Review Workflow Section # PR Card Section 2 move-card
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data review-pr-card
pr-review column_id find-card set-reviewers create-card move-card outputs
PR Comment
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data review-pr-card
pr-review column_id find-card set-reviewers create-card move-card outputs
PR Comment Section 2 /review @notifier, @notifier
https://docs.github.com/ko/actions/using-workflows/events-that-trigger-workflows Events on : issue_comment : types : [created] Section
2 - created - edited - deleted
Jobs Section 2 jobs : pr_comment : if : github.event.issue.pull_request
&& startsWith(github.event.comment.body, '/review' ) steps : - name : Dispatch . . .
https://github.com/actions/github-script Actions steps : # PR comment 분석하여 리뷰어 추출
후, review-pr-card 워크 플로우 트리거 - - name : Dispatch uses : actions/github-script@v7 with : github-token : ${{ secrets.GITHUB_TOKEN }} script : | Section 1 Section 2
- name : dispatch uses : actions/github-script@v7 with : github-token
: ${{ secrets.GITHUB_TOKEN }} script : | const[ , …reviewParameters] = '${{ github.event.comment.body }}'.trim().split(' ') . . . await github.rest.actions.createWorkflowDispatch({ . . .context.repo, workflow_id : 'action-pipelines-review-pr-card.yml', ref : context.ref, inputs : { pr_number: `${ context.issue.number }`, . . . } });
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data review-pr-card
pr-automation column_id find-card set-reviewers create-card move-card outputs
PR Board Section # Section 2 Assignee Reviewer PR Data
- name : dispatch . . . with : script
: | . . . await github.rest.actions.createWorkflowDispatch({ . . .context.repo, workflow_id : 'action-pipelines-review-pr-card.yml', ref : context.ref, inputs : { pr_number: `${ context.issue.number }`, pr_assignee: `${ commentUser }`, pr_reviewers = `${ notifiers.join() }` } });
Review PR Card
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data review-pr-card
pr-review column_id find-card set-reviewers create-card move-card outputs
on : workflow_dispatch : inputs : pr_number : description :
'PR number' required : true default : ' ' pr_assignee : . . . pr_reviewers : . . . jobs : prepare : runs-on : [self-hosted, amd64, small, spot] steps : . . .
None
prepare pr_data review-pr-card pr-review column_id find-card set-reviewers create-card move-card pr_html_url
pr_title outputs
PR Card Section # pr_title pr_html_url Section 2
prepare : steps : - name : get-pr-data uses :
actions/github-script@v7 id : pr_data with : script : | . . . return pr_data - name : get-pr-url . . . script : | const prData = ${{ steps.pr_data.outputs.result }} return prData.html_url result-encoding : string
prepare : steps : - name : get-pr-data uses :
actions/github-script@v7 id : pr_data with : script : | . . . return pr_data - name : get-pr-url . . . script : | const prData = ${{ steps.pr_data.outputs.result }} return prData.html_url result-encoding : string
prepare pr_data review-pr-card pr-review column_id find-card set-reviewers create-card move-card pr_assignee_column_id
pr_reviewers_column_id outputs Section 2
PR Board Section # Section 2 pr_assignee_column_id pr_reviewers_column_id
prepare : steps : . . . - name :
checkout uses : actions/checkout@v3 - name : pr-assignee-to-project-column-id run : chmod +x ./column.sh result=$(./column.sh "${{ github.event.inputs.pr_assignee }}") echo "result=${result}" >> $GITHUB_OUTPUT . . .
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data review-pr-card
pr-review column_id find-card set-reviewers create-card move-card outputs
jobs : prepare : steps : - name : get-pr-data
- name : get-pr-url . . . outputs : pr_html_url : ${{ steps.pr_html_url.outputs.result }} pr_title : ${{ steps.pr_title_url.outputs.result }} pr_assignee_column_id : ${{ steps.pr-assignee-to-project-column-id.outputs.result }} . . . pr-automation : . . .
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data review-pr-card
pr-review column_id find-card set-reviewers create-card move-card outputs
jobs : prepare : steps : - name : get-pr-data
- name : get-pr-url . . . pr-review : needs : [ prepare ] steps : - name : find-card - name : set-reviewers - name : create-card - name : move-card
jobs .<job_id> .needs Section # Section 2
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data review-pr-card
pr-review column_id find-card set-reviewers create-card move-card outputs
Find Card Section # Section 2 기존에 카드가 존재 했을
경우
- name : find-card uses : actions/github-script@v7 id : find_card
with : github-token : ${{ secrets.GITHUB_TOKEN }} script : | const { data: listCards } = await github.rest.projects.listCards({ column_id : columnId, }); . . . if (card) { return card.id } else { return 0 }
- name : find-card uses : actions/github-script@v7 id : find_card
with : github-token : ${{ secrets.GITHUB_TOKEN }} script : | const { data: listCards } = await github.rest.projects.listCards({ column_id : colinmId, }); . . . if (card) { return card.id } else { return 0 }
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data review-pr-card
pr-review column_id find-card set-reviewers create-card move-card outputs
- name : set-reviewers if : steps.find_card.outputs.result == 0 uses
: actions/github-script@v7 with : github-token : ${{ secrets.GITHUB_TOKEN }} script : | const { data: requestedReviewers } = await github.rest.pulls.listRequestedReviewers({ column_id : colinmId, }); . . . if (requestedReviewers.users.length === 0) { await github.rest.pulls.requestReviewers({ . . . }} }
- name : set-reviewers if : steps.find_card.outputs.result == 0 uses
: actions/github-script@v7 with : github-token : ${{ secrets.GITHUB_TOKEN }} script : | const { data: requestedReviewers } = await github.rest.pulls.listRequestedReviewers({ column_id : colinmId, }); . . . if (requestedReviewers.users.length === 0) { await github.rest.pulls.requestReviewers({ . . . }} }
PR Reviewers State Section 2 approved requested-reviewer
- name : set-reviewers if : steps.find_card.outputs.result == 0 uses
: actions/github-script@v7 with : github-token : ${{ secrets.GITHUB_TOKEN }} script : | const { data: requestedReviewers } = await github.rest.pulls.listRequestedReviewers({ column_id : colinmId, }); . . . if (requestedReviewers.users.length === 0) { await github.rest.pulls.requestReviewers({ . . . }} }
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data review-pr-card
pr-review column_id find-card set-reviewers create-card move-card outputs
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data review-pr-card
pr-review column_id find-card set-reviewers create-card move-card outputs
PR Review Card Section # PR Card Section 2
찾아온 위기: Projects Sunset
Projects (classic) sunset Section 2
PR Review Section 2 팀원들이 PR을 잘 볼 수 있는
방법 없을까?
GitHub Integration Section # Section 2
Slack Github Action Section # Section 2
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data pr-review
github_username set-reviewers notify-reviewers send-dm-for- reviewer outputs notify-pr-reviewer pr_title pr_url pr_assignee pr_reviewer
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data pr-review
github_username set-reviewers notify-reviewers send-dm-for- reviewer outputs notify-pr-reviewer pr_title pr_url pr_assignee pr_reviewer
- name : notify-reviewers uses : actions/github-script@v7 with : github-token
: ${{ secrets.GITHUB_TOKEN }} script : | . . . for (const reviewer of selectedReviewers) { await github.rest.actions.createWorkflowDispatch({ . . . context.repo, workflow_id : 'action-pipelines-notify-pr-reviewer.yml', inputs: { . . . } } }
PR Reviewers Section 2 notify-pr-reviewer notify-pr-reviewer notify-pr-reviewer
pr_comment prepare /review @notifier, @notifier pr_number pr_assignee pr_reviewers pr_data pr-review
github_username set-reviewers notify-reviewers send-dm-for- reviewer outputs notify-pr-reviewer pr_title pr_url pr_assignee pr_reviewer
- name : send-dm-for-reviewer uses : slackapi/
[email protected]
env : SLACK_BOT_TOKEN
: ${{ secrets.SLACK_ANDROID_PR_BOT_TOKEN }} with : channel-id : ${{ steps.pr_reviewer_slack_mention_token.outputs.result }} payload : | { "blocks" : [ { "type" : "header", "text" : { "type" : "plain_text", "text" : "PR 리뷰 부탁드립니다 :pray:", "emoji" : true } . . .
Slack API Your Apps Section # Section 2
Slack Bot Token Section # https://api.slack.com/tutorials/tracks/getting-a-token Section 2
Slack Bot Token Scopes Section # Section 2
GitHub Repository Settings Section # Section 2
- name : send-dm-for-reviewer uses : slackapi/
[email protected]
env : SLACK_BOT_TOKEN
: ${{ secrets.SLACK_ANDROID_PR_BOT_TOKEN }} with : channel-id : ${{ steps.pr_reviewer_slack_mention_token.outputs.result }} payload : | { "blocks" : [ { "type" : "header", "text" : { "type" : "plain_text", "text" : "PR 리뷰 부탁드립니다 :pray:", "emoji" : true } . . .
- name : send-dm-for-reviewer uses : slackapi/
[email protected]
env : SLACK_BOT_TOKEN
: ${{ secrets.SLACK_ANDROID_PR_BOT_TOKEN }} with : channel-id : ${{ steps.pr_reviewer_slack_mention_token.outputs.result }} payload : | { "blocks" : [ { "type" : "header", "text" : { "type" : "plain_text", "text" : "PR 리뷰 부탁드립니다 :pray:", "emoji" : true } . . .
Slack Channel-Id Section # Section 2
Slack Channel-Id Section # Section 2 https://api.slack.com/types/channel channel-id example: C1H9RESGL
Slack Channel-Id Section # Section 2
Slack Mention Section # Section 2 channel-id : C1H9RESGL mention
: <@U0G9QF9C6>
- name : send-dm-for-reviewer uses : slackapi/
[email protected]
env : SLACK_BOT_TOKEN
: ${{ secrets.SLACK_ANDROID_PR_BOT_TOKEN }} with : channel-id : ${{ steps.pr_reviewer_slack_mention_token.outputs.result }} payload : | { "blocks" : [ { "type" : "header", "text" : { "type" : "plain_text", "text" : "PR 리뷰 부탁드립니다 :pray:", "emoji" : true } . . .
Slack Block Kit Builder Section # Section 2
Slack Block Kit Builder Section # Section 2
Slack Block Kit Builder Section # Section 2
- name : send-dm-for-reviewer uses : slackapi/
[email protected]
env : SLACK_BOT_TOKEN
: ${{ secrets.SLACK_ANDROID_PR_BOT_TOKEN }} with : channel-id : ${{ steps.pr_reviewer_slack_mention_token.outputs.result }} payload : | { "blocks" : [ { "type" : "header", "text" : { "type" : "plain_text", "text" : "PR 리뷰 부탁드립니다 :pray:", "emoji" : true } . . .
Android PR Bot Section # Section 2
PR Review Reminder
PR Review Reminder Section 2 Slack DM으로 PR 메시지가 오는데
자꾸 까먹네... PR을 잘 볼 수 있는 방법 없을까?
PR Review Reminder Section 2 매일 오후 1시에 슬랙 알람이
온다면.. D-day 라벨을 붙이면..
pr-remind find-open-pr get-slack-mention- token notify-pr-list-to-reviewer payload pr_reviewer prepare-slack-message send-dm-for- reviewer
on : schedule : # 평일 13시 실행 cron :
'0 4 * * 1-5' workflow_dispatch : jobs : pr-remind : . . . steps : - name : find-open-pr - name : prepare-slack-message . . .
Slack Block Kit Builder Section # Section 2
pr-remind find-open-pr get-slack-mention- token notify-pr-list-to-reviewer payload pr_reviewer prepare-slack-message send-dm-for- reviewer
- name : find-open-pr . . . script : |
const { data : pullRequests } = await github.rest.pulls.list({ . . . }); const filteredPullRequests = pullRequests.filter(pr => pr.requested_reviewers.length !=0 && !pr.draft ); return filteredPullRequests
- name : find-open-pr . . . script : |
const { data : pullRequests } = await github.rest.pulls.list({ . . . }); const filteredPullRequests = pullRequests.filter(pr => pr.requested_reviewers.length !=0 && !pr.draft ); return filteredPullRequests
Error Section # Section 2
pr-remind find-open-pr get-slack-mention- token notify-pr-list-to-reviewer payload pr_reviewer prepare-slack-message send-dm-for- reviewer
- name : prepare-slack-message . . . script : |
. . . const payload = { blocks : [ . . . ] } await github.rest.actions.createWorkflowDispatch({ . . . inputs : { payload : JSON.stringfy(payload), pr_reviewer : `${ reviewer }` } })
Slack Block Kit Builder Section # Section 2
- name : prepare-slack-message . . . script : |
. . . const payload = { blocks : [ . . . ] } await github.rest.actions.createWorkflowDispatch({ . . . inputs : { payload : JSON.stringfy(payload), pr_reviewer : `${ reviewer }` } })
pr-remind find-open-pr get-slack-mention- token notify-pr-list-to-reviewer payload pr_reviewer prepare-slack-message send-dm-for- reviewer
pr-remind find-open-pr get-slack-mention- token notify-pr-list-to-reviewer payload pr_reviewer prepare-slack-message send-dm-for- reviewer
PR Reminder Section # Section 2
PR Review Reminder Section 2 Section 3
Github Actions, 그 이후 Section 3
Android Build Bot Section 2 Section 3
Android Build Bot Section 2 Section 3
PR Review Label Section 2 Section 3
Thank You 하동현 / @harada.ha Remember | ex-KakaoStyle