Upgrade to Pro — share decks privately, control downloads, hide ads and more …

iOS Dev Workflow Automation for note

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for laprasDrum laprasDrum
September 21, 2020

iOS Dev Workflow Automation for note

iOSDC Japan 2020 で登壇しました。

「それ、自動化できますよ」: note を支えるワークフロー大全
https://fortee.jp/iosdc-japan-2020/proposal/a6fcae29-405e-4923-aa45-8132a2444e60

補足版を技術書典で販売しています。
よければ見てくれるとうれしいです。

Zapier ではじめる iOS 開発ワークフロー自動化
https://techbookfest.org/product/5017415553384448

Avatar for laprasDrum

laprasDrum

September 21, 2020
Tweet

More Decks by laprasDrum

Other Decks in Technology

Transcript

  1. desc "[CI] add new device UDID. It requires options: name,

    udid" lane :add_new_device do |options| if (options[:name].nil? or options[:name].empty?) or (options[:udid].nil? or options[:udid].empty?) UI.user_error!("missing options! call with name:{device name} udid:{device udid}") end UI.important("registering #{options[:name]} (#{options[:udid]})") register_device( name: options[:name], udid: options[:udid] ) # ূ໌ॻߋ৽ match( app_identifier: ['com.myapp.viewer'], # ొ࿥͍ͨ͠ identifier ͢΂ͯೖΕΔ type: 'adhoc', # ඞཁͳΒ development ΋ force_for_new_devices: true ) # Ϗϧυ gym(...) # ഑৴ firebase_app_distribution(...) end fastlane add_new_device udid:xxx name:yyy
  2. import json # Zapier Ͱઃఆͨ͠؀ڥม਺͸ input_data ͰऔಘՄೳ headers = {

    'Accept': 'application/json', 'Content-Type': 'application/json' } auth = (input_data['circleci_token'], '') response = requests.post( "https://circleci.com/api/v2/project/gh/org/repo/pipeline", data=json.dumps({ "branch": "master", "parameters": { "run_device_registration_from_ci": True, "device_name": input_data['device_name'], "device_udid": input_data['device_udid'] }}), headers = headers, auth = auth) response.raise_for_status() output = response.json() parameters: run_device_registration_from_ci: type: boolean default: false workflows: version: 2.1 # --- API ܦ༝ͷΈ # fastlane register_device Λ࣮ߦ͢Δ add_new_device_from_ci: when: << pipeline.parameters.run_device_registration_from_ci >> steps: - checkout - run: *build - run: bundle exec fastlane add_new_device name:<< pipeline.parameters.device_name >> udid:<< pipeline.parameters.device_udid >> config.yml CI ্Ͱ fastlane ࣮ߦ
  3. release branch ࡞੒ import json import base64 headers = {

    "Content-type": "application/json", "Authorization": f"token {input_data['github_token']}" } # master branch HEAD ͷ SHA Λऔಘ master_ref_url = "https://api.github.com/repos/org/repo/git/ref/heads/master" master_ref_response = requests.get(master_ref_url, headers=headers) master_ref_response.raise_for_status() master_ref_json = master_ref_response.json() master_sha = master_ref_json['object']['sha'] # release/x.y.z branch Λ࡞੒ release_branch_url = "https://api.github.com/repos/org/repo/git/refs" payload = { "ref": f"refs/heads/{input_data['branch']}", # branch = 'x.y.z' "sha": master_sha } release_branch_response = requests.post( release_branch_url, data=json.dumps(payload), headers=headers ) release_branch_response.raise_for_status() output = release_branch_response.json()
  4. CircleCI ্Ͱ࣮ߦ workflows: version: 2.1 auto_update_commit: when: << pipeline.parameters.run_auto_update_commit >>

    jobs: - "Commit and Push version update": filters: branches: only: /^release\/.+$ jobs: "Commit and Push version update": steps: - run: *checkout_and_build - run: name: "commit & push version update to ${NEXT_VERSION}" command: | NEXT_VERSION=<< pipeline.parameters.next_version >> git reset --hard HEAD git config user.email "[email protected]" git config user.name "your auto committer" bundle exec fastlane update_version to:${NEXT_VERSION} git add . git commit -m "[ci skip] [auto commit] update to ${NEXT_VERSION}" git push origin release/${NEXT_VERSION} - when: condition: << pipeline.parameters.run_integration_tests >> steps: *upload_latest_note_to_magic_pod release branch ͷΈ࣮ߦ fastlane update_version Λ࣮ߦͯ͠ commit & push
  5. fastlane update_version desc "[CI] update version & deploy adhoc apps"

    lane :update_version do |options| increment_version_number(version_number: options[:to].to_s) generate_changelog match(...) gym(...) upload_to_firebase(...) end github-changelog-generator Ͱ 3.0.0 tag ~ HEAD ؒͷ diff Λऔͬͯ ReleaseNote Λ࡞੒
  6. release tag ࡞੒ # generator Ͱ࡞੒ͨ͠ ReleaseNote ͷຊจΛऔಘ branch =

    f"release/{input_data['version']}" release_note_url = f"https://api.github.com/repos/org/repo/contents/LatestReleaseCheckIssue.md?ref={branch}" body_response = requests.get(release_note_url, headers=headers) body_response.raise_for_status() body_json = body_response.json() decoded_body = base64.b64decode(body_json['content']).decode('utf-8') # version tag ࡞੒ release_tag_url = "https://api.github.com/repos/org/repo/releases" payload = { 'tag_name': input_data['version'], 'target_commitish': branch, 'name': input_data['version'], 'body': decoded_body, 'draft': False, 'prereleases': False } released_response = requests.post(release_tag_url, data=json.dumps(payload), headers=headers) released_response.raise_for_status() released_json = released_response.json()
  7. merge # master ʹ޲͚ͯ PR ࡞੒ pr_url = "https://api.github.com/repos/org/repo/pulls" payload

    = { 'title': f"[Auto Create & Merge] {input_data['version']}", 'head': branch, 'base': 'master', 'body': 'created by zapier' } pr_response = requests.post(pr_url, data=json.dumps(payload), headers=headers) pr_response.raise_for_status() pr_json = pr_response.json() pr_number = str(pr_json['number']) pr_link = f"https://github.com/org/repo/pull/{pr_number}" # merge merge_url = f"https://api.github.com/repos/org/repo/pulls/{pr_number}/merge" merge_response = requests.put(merge_url, headers=headers) result = merge_response.json() # Slack ʹ౤ߘ͢ΔϝοηʔδΛ࡞੒ʢauto merge ੒ޭ or ࣦഊʣ if 'merged' in result and result['merged'] == True: return { 'message': f"{input_data['version']} ϦϦʔεʂmaster merge ͨ͠Α {pr_link}" } else: return { 'message': f"{input_data['version']} ϦϦʔεʂ͚ͩͲ master merge Ͱ͖ͳ͔ͬͨΑ {pr_link}" }
  8. ϦϦʔεϝʔϧˠdSYM lane :upload_dsym do |options| version = options[:version] || get_info_plist_value(path:

    "path/to/info.plist", key: "CFBundleShortVersionString") app_identifier = options[:app_identifier] || 'com.you.app' # ֘౰ ver. ͷ dSYM Λμ΢ϯϩʔυ sh 'rm -rf ../output/dsyms' sh 'mkdir -p ../output/dsyms' download_dsyms( version: version, app_identifier: app_identifier, output_directory: 'output/dsyms' ) Dir.chdir("../") do # FirebaseCrashlytics/upload-symbols ͰΞοϓϩʔυ͢ΔεΫϦϓτΛ࣮ߦ sh 'realpath output/dsyms/*.zip ɹɹɹɹɹ | xargs -I{} ./scripts/upload_dsyms.sh {} ./note/GoogleService-Info-Prod.plist' sh 'rm -rf output/dsyms' end end