Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Github Actions 로 Android 팀의 효율성 극대화
Search
Harada Ha
July 21, 2024
Technology
380
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Github Actions 로 Android 팀의 효율성 극대화
Google I/O extended Android 2024 때 발표한 자료 입니다.
Harada Ha
July 21, 2024
More Decks by Harada Ha
See All by Harada Ha
AI를 잘 쓰고 있다는 착각, 그리고 그걸 확인하는 법
hadonghyun
0
490
Privacy Changes in Android Q
hadonghyun
1
450
지금까지 이런 간단한 Logic 처리는 없었다 이것은 Rx 인가, UI 이벤트인가? 네, RxBinding입니다.
hadonghyun
1
230
Other Decks in Technology
See All in Technology
React Nativeでの OTA Updateって、 どう説明する?
ichiki1023
0
120
AIに会社の文脈を理解させる技術~上流工程・非エンジニアにも広げるハーネスエンジニアリング実践~
ochtum
0
190
高負荷プロダクション環境におけるAWS Lambdaのリアル 〜スケールとコストを左右する実行ライフサイクルの技術仕様〜
maimyyym
2
830
IR Today: Theory, Practice, and Agents
dtunkelang
0
260
いちAWSエンジニアのAI活用を振り返る #devio2026 / devio osaka 2026 kawahara
masahirokawahara
1
290
AIエージェント時代のPlatform as a Product —— テックリードがPdMとして回す発見・導入・計測 / Platform as a Product in the AI Agent Era
toshi0607
1
530
大阪オフィスに Unitree Go2 がやってきたので Physical AI やってみた
dafujii
0
140
spanner-autoscalerに学ぶ CRD設計パターン 〜自動化と緊急時対応を両立する Kubernetesコントローラーの作り方〜
tkuchiki
0
210
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
16
120k
AIエージェントを安全で速い現場監督にする:Jev・Obsidian・メタハーネス
x5gtrn
PRO
0
140
ScotSecure West 2026 - Glasgow
raybugg
0
210
Claude起点の仕様駆動開発
tanakaseiya
0
220
Featured
See All Featured
Discover your Explorer Soul
emna__ayadi
2
1.3k
Optimising Largest Contentful Paint
csswizardry
37
4k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
440
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
490
Utilizing Notion as your number one productivity tool
mfonobong
4
600
A Modern Web Designer's Workflow
chriscoyier
699
190k
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
3
4.3k
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
380
The Curse of the Amulet
leimatthew05
3
15k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
620
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