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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
猫でもわかるKiro Web
kentapapa
1
160
企業の現実世界をグラフで写し取る
sansantech
PRO
0
210
Coil3を内部実装から読み解く~キャッシュ戦略とAVIF画像の描画〜/nikkei-tech-talk50
nikkei_engineer_recruiting
0
170
Harness Engineering on Rails
joelq
0
760
【データ横丁主催】AI Agentがコンテキストを使って仕事をした後、何が残るのか― 組織の経験を次の判断に引き継ぐ「Agent Memory」
shisyu_gaku
2
270
Incremental HTTP
kazuho
3
1.4k
AWS DevOps Agent スキルをつかいこなそう / Master AWS DevOps Agent Skills
kinunori
2
640
音声コミュニティを守るAI監視基盤_ 90%以上の入力削減を支えたServerless設計と運用判断
shuheioka123
0
120
人にやさしく、AIにやさしく、書き手を選ばないIaCのガードレール再考 / Rethinking IaC Guardrails for Humans and AI Alike
kohbis
5
1.8k
Account Factory for Terraformによる 標準化されたアカウント発行の自動化
pensuke628
0
120
LT:「このままでいいのかな?」から一歩踏み出した私のデータキャリア選択〜社会人3年目に上京を決意したリアル〜Snowflake女子会 vol.8
snowwmn0824
0
120
20260929_AmazonGuardDutyの検出通知メールにAWS DevOpsAgentの調査結果を追加する
yhana
1
380
Featured
See All Featured
Designing Dashboards & Data Visualisations in Web Apps
destraynor
232
55k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
690
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.7k
Deep Space Network (abreviated)
tonyrice
0
340
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
380
Testing 201, or: Great Expectations
jmmastey
46
8.3k
Done Done
chrislema
187
17k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
Balancing Empowerment & Direction
lara
6
1.3k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
510
Large-scale JavaScript Application Architecture
addyosmani
515
110k
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
330
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