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
320
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
660
Privacy Changes in Android Q
hadonghyun
1
420
지금까지 이런 간단한 Logic 처리는 없었다 이것은 Rx 인가, UI 이벤트인가? 네, RxBinding입니다.
hadonghyun
1
220
Other Decks in Technology
See All in Technology
データとAIで未来を創るDatabricks - 君の可能性を加速させるプラットフォーム
taka_aki
0
100
AI時代に必要なデータプラットフォームの要件とは by @Kazaneya_PR / 20251107
kazaneya
PRO
4
970
エンタープライズ企業における開発効率化のためのコンテキスト設計とその活用
sergicalsix
1
380
旧から新へ: 大規模ウェブクローラの Perl から Go への移行 / YAPC::Fukuoka 2025
motemen
3
850
手を動かしながら学ぶデータモデリング - 論理設計から物理設計まで / Data modeling
soudai
PRO
22
4.9k
仕様は“書く”より“語る” - 分断を超えたチーム開発の実践 / 20251115 Naoki Takahashi
shift_evolve
PRO
1
570
ググるより、AIに聞こう - Don’t Google it, ask AI
oikon48
0
860
エンジニア採用と 技術広報の取り組みと注力点/techpr1112
nishiuma
0
130
これからアウトプットする人たちへ - アウトプットを支える技術 / that support output
soudai
PRO
18
5.4k
Redux → Recoil → Zustand → useSyncExternalStore: 状態管理の10年とReact本来の姿
zozotech
PRO
12
6.3k
はじめての OSS コントリビューション 〜小さな PR が世界を変える〜
chiroito
4
260
Amazon ECS デプロイツール ecspresso の開発を支える「正しい抽象化」の探求 / YAPC::Fukuoka 2025
fujiwara3
11
2.1k
Featured
See All Featured
GitHub's CSS Performance
jonrohan
1032
470k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
The World Runs on Bad Software
bkeepers
PRO
72
12k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
118
20k
Build The Right Thing And Hit Your Dates
maggiecrowley
38
2.9k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
285
14k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.2k
How STYLIGHT went responsive
nonsquared
100
5.9k
Why Our Code Smells
bkeepers
PRO
340
57k
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
GraphQLの誤解/rethinking-graphql
sonatard
73
11k
Gamification - CAS2011
davidbonilla
81
5.5k
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