Fastfile 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. # This is the minimum version number required.
  2. fastlane_version "2.58.0"
  3. ## config
  4. # add following to your shell rc:
  5. # export FASTLANE_NEXTCLOUD_STORE_FILE=""
  6. # export FASTLANE_NEXTCLOUD_STORE_PASSWORD=""
  7. # export FASTLANE_NEXTCLOUD_KEY_ALIAS=""
  8. # export FASTLANE_NEXTCLOUD_KEY_PASSWORD=""
  9. # export FASTLANE_NEXTCLOUD_GITHUB_API_TOKEN=""
  10. # export FASTLANE_NEXTCLOUD_HUAWEI_CLIENT_ID=""
  11. # export FASTLANE_NEXTCLOUD_HUAWEI_CLIENT_SECRET=""
  12. # export FASTLANE_NEXTCLOUD_HUAWEI_APP_ID=""
  13. skip_docs
  14. ## public lanes
  15. lane :screenshotsPhone do
  16. beautifyPhone()
  17. build_for_screengrab()
  18. screengrab(
  19. device_type: "phone",
  20. app_apk_path: APK_LOCATION,
  21. tests_apk_path: TEST_APK_LOCATION
  22. )
  23. end
  24. lane :screenshotsTablet do
  25. beautifyPhone()
  26. build_for_screengrab()
  27. screengrab(
  28. device_type: "sevenInch",
  29. app_apk_path: APK_LOCATION,
  30. tests_apk_path: TEST_APK_LOCATION
  31. )
  32. end
  33. desc "Release phase 1: make gplay/generic for RC, then test it"
  34. lane :RC_releasePhase1 do
  35. disableLogger()
  36. makeReleases()
  37. enableLogger()
  38. end
  39. desc "Release phase 2 for RC: checks, tag, upload gplay to playstore with values from build.gradle"
  40. lane :RC_releasePhase2 do |options|
  41. checkReleaseRequirements_RC()
  42. info = androidVersion
  43. promptVersion(info)
  44. checkChangelog(info)
  45. checkLibrary_RC()
  46. checkIfScreenshotsExist()
  47. checkIfAPKexists()
  48. tag(info)
  49. uploadToPlaystore_RC(info)
  50. createGithubRelease_RC(info)
  51. fdroidMergeRequest_RC(info)
  52. createChangelogPullRequest_RC(info)
  53. end
  54. desc "Release phase 1: make gplay/generic for FINAL, then test it"
  55. lane :Final_releasePhase1 do
  56. makeReleases()
  57. end
  58. desc "Release phase 2 for FINAL: checks, tag, upload gplay to playstore with values from build.gradle"
  59. lane :Final_releasePhase2 do |options|
  60. checkReleaseRequirements_Final()
  61. info = androidVersion
  62. promptVersion(info)
  63. checkChangelog(info)
  64. checkLibrary_Final()
  65. checkIfScreenshotsExist()
  66. checkIfAPKexists()
  67. tag(info)
  68. uploadToPlaystore_Final(info)
  69. uploadToHuawei_Final(info)
  70. createGithubRelease_Final(info)
  71. fdroidMergeRequest_Final(info)
  72. createChangelogPullRequest_Final(info)
  73. end
  74. desc "Makes gplay and generic releases in ../releases/"
  75. lane :makeReleases do
  76. info = androidVersion
  77. sh("rm -rf ../release/ && mkdir -p ../release")
  78. gradle(task: 'clean')
  79. createGenericRelease(versionCode:info["versionCode"])
  80. createGplayRelease(versionCode:info["versionCode"])
  81. createHuaweiRelease()
  82. end
  83. desc "Create GPlay release"
  84. lane :createGplayRelease do |options|
  85. buildBundle(flavor:"Gplay")
  86. sh("mv ../app/build/outputs/bundle/gplayRelease/app-gplay-release.aab ../release/")
  87. buildApkFromBundle(outputDir: "../release", bundlePath: "../release/app-gplay-release.aab")
  88. sh("rm ../release/toc.pb")
  89. sh("mv ../release/universal.apk ../release/gplay-release-#{options[:versionCode]}.apk")
  90. end
  91. desc "Create Generic release"
  92. lane :createGenericRelease do |options|
  93. SignedRelease(flavor:"Generic")
  94. sh("mv ../app/build/outputs/apk/generic/release/*.apk ../release/")
  95. sh("mv ../release/generic-release-#{options[:versionCode]}.apk ../release/nextcloud-#{options[:versionCode]}.apk")
  96. end
  97. desc "Create Huawei release"
  98. lane :createHuaweiRelease do
  99. SignedRelease(flavor:"Huawei")
  100. sh("mv ../app/build/outputs/apk/huawei/release/*.apk ../release/")
  101. end
  102. desc "Create Dev release"
  103. lane :createDevRelease do
  104. SignedRelease(flavor:"VersionDev")
  105. sh("mv ../app/build/outputs/apk/versionDev/release/*.apk ../release/")
  106. end
  107. desc "Beautify phone for screenshots: set time, remove other icons, no charging"
  108. lane :beautifyPhone do
  109. sh("adb shell settings put global sysui_demo_allowed 1")
  110. sh("adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1200")
  111. sh("adb shell am broadcast -a com.android.systemui.demo -e command network -e mobile show -e level 4 -e datatype false")
  112. sh("adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false")
  113. sh("adb shell am broadcast -a com.android.systemui.demo -e command battery -e plugged false -e level 100")
  114. end
  115. # to install
  116. # bundle exec fastlane add_plugin huawei_appgallery_connect
  117. # bundle install --path build/vendor/bundle
  118. private_lane :uploadToHuawei_Final do |options|
  119. huawei_appgallery_connect(
  120. client_id: ENV["FASTLANE_NEXTCLOUD_HUAWEI_CLIENT_ID"],
  121. client_secret: ENV["FASTLANE_NEXTCLOUD_HUAWEI_CLIENT_SECRET"],
  122. app_id: ENV["FASTLANE_NEXTCLOUD_HUAWEI_APP_ID"],
  123. apk_path: "release/huawei-release-" + options["versionCode"] + ".apk",
  124. submit_for_review: true,
  125. delay_before_submit_for_review: 30,
  126. )
  127. end
  128. ## private lanes
  129. desc "Build debug and test APK for screenshots"
  130. private_lane :build_for_screengrab do
  131. build_android_app(
  132. task: 'assemble',
  133. flavor: 'Generic',
  134. build_type: 'Debug'
  135. )
  136. APK_LOCATION = lane_context[SharedValues::GRADLE_ALL_APK_OUTPUT_PATHS].select{ |i| i[/00/] }[0]
  137. build_android_app(
  138. task: 'assemble',
  139. flavor: 'Generic',
  140. build_type: 'DebugAndroidTest'
  141. )
  142. TEST_APK_LOCATION = lane_context[SharedValues::GRADLE_ALL_APK_OUTPUT_PATHS].select{ |i| i[/androidTest/] }[0]
  143. end
  144. private_lane :checkReleaseRequirements_common do
  145. sh("if ! command -v fdroid &>/dev/null; then echo 'fdroid command not found' && exit 1; fi")
  146. sh("if ! command -v bundletool &>/dev/null; then echo 'bundletool command not found' && exit 1; fi")
  147. end
  148. private_lane :checkReleaseRequirements_RC do
  149. checkReleaseRequirements_common()
  150. sh("if ! command -v fdroidMergeRequestRC &>/dev/null; then echo 'fdroidMergeRequestRC command not found'; exit 1; fi")
  151. sh("if ! command -v createChangelogPullRequestRC &>/dev/null; then echo 'createChangelogPullRequestRC command not found'; exit 1; fi")
  152. end
  153. private_lane :checkReleaseRequirements_Final do
  154. checkReleaseRequirements_common()
  155. sh("if ! command -v fdroidMergeRequestFinal &>/dev/null; then echo 'fdroidMergeRequestFinal command not found'; exit 1; fi")
  156. sh("if ! command -v createChangelogPullRequestFinal &>/dev/null; then echo 'createChangelogPullRequestFinal command not found'; exit 1; fi")
  157. end
  158. private_lane :createChangelogPullRequest_RC do |options|
  159. sh("createChangelogPullRequestRC " + options["tag"] + " \"" + options["versionName"] + "\" " + options["versionCode"] + " \"" + options["branch"] + "\" ")
  160. end
  161. private_lane :createChangelogPullRequest_Final do |options|
  162. sh("createChangelogPullRequestFinal " + options["tag"] + " \"" + options["versionName"] + "\" " + options["versionCode"] + " \"" + options["branch"] + "\" ")
  163. end
  164. private_lane :checkIfAPKexists do |options|
  165. sh("if [ $(/bin/ls -1 ../release | wc -l) -ne 4 ]; then echo 'Release artifacts not present or wrong number present; aborting!' ; exit 1 ;
  166. fi")
  167. end
  168. desc "compute version"
  169. private_lane :androidVersion do
  170. File.open("../app/build.gradle","r") do |f|
  171. text = f.read
  172. # everything between Document and Authors
  173. major = text.match(/def versionMajor = ([0-9]*)$/)
  174. minor = text.match(/def versionMinor = ([0-9]*)$/)
  175. patch = text.match(/def versionPatch = ([0-9]*)$/)
  176. build = text.match(/def versionBuild = ([0-9]*).*$/)
  177. majorInt = major[1].to_i
  178. minorInt = minor[1].to_i
  179. patchInt = patch[1].to_i
  180. buildInt = build[1].to_i
  181. versionCode = majorInt * 10000000 + minorInt * 10000 + patchInt * 100 + buildInt
  182. if buildInt > 89
  183. name = major[1] + "." + minor[1] + "." + patch[1]
  184. tag = "stable-" + major[1] + "." + minor[1] + "." + patch[1]
  185. branch = "stable-" + major[1] + "." + minor[1]
  186. elsif buildInt > 50
  187. name = major[1] + "." + minor[1] + "." + patch[1] + " RC" + (buildInt - 50).to_s
  188. tag = "rc-" + major[1] + "." + minor[1] + "." + patch[1] + "-" + format('%02d', (buildInt - 50))
  189. branch = "stable-" + major[1] + "." + minor[1]
  190. else
  191. name = major[1] + "." + minor[1] + "." + patch[1] + " Alpha " + format('%02d', (buildInt + 1))
  192. tag = "/"
  193. branch = "stable-" + major[1] + "." + minor[1]
  194. end
  195. { "versionCode" => versionCode.to_s, "versionName" => name, "tag" => tag, "branch" => branch }
  196. end
  197. end
  198. desc "Show versions and prompt for confirmation"
  199. private_lane :promptVersion do |options|
  200. print "VersionCode: " + options["versionCode"].to_s + "\n"
  201. print "Name: " + options["versionName"] + "\n"
  202. print "Tag: " + options["tag"] + "\n"
  203. print "Branch: " + options["branch"] + "\n"
  204. print "\ndisable IPv6 to upload to Gplay!!!\n"
  205. answer = prompt(text: "is this okay?", boolean: true)
  206. if !answer
  207. exit
  208. end
  209. end
  210. desc "check if library is set correctly"
  211. private_lane :checkLibrary_RC do
  212. sh(" if [ $(egrep 'androidLibraryVersion.*master.*' ../build.gradle -c) -eq 1 ] ; then echo 'Library is set to master tag; aborting!' ; exit 1 ; fi")
  213. end
  214. desc "check if library is set correctly: must NOT contain master nor rc"
  215. private_lane :checkLibrary_Final do
  216. sh(" if [ $(grep 'androidLibraryVersion' ../build.gradle | egrep 'master|rc' -c) -eq 1 ] ; then echo 'Library is still set to rc tag; aborting!' ; exit 1 ; fi")
  217. end
  218. desc "check if screenshots exists and exit"
  219. private_lane :checkIfScreenshotsExist do
  220. sh(" if [ -e metadata/android/*/images ] ; then echo 'Screenshots in fastlane folder exist; aborting!' ; exit 1 ; fi")
  221. end
  222. private_lane :tag do |options|
  223. add_git_tag(
  224. tag: options["tag"],
  225. sign: true
  226. )
  227. push_git_tags(
  228. tag: options["tag"])
  229. end
  230. private_lane :disableLogger do
  231. sh("sed -i s'#<bool name=\"logger_enabled\">false</bool>#<bool name=\"logger_enabled\">true</bool>#' ../app/src/main/res/values/setup.xml")
  232. end
  233. private_lane :enableLogger do
  234. sh("sed -i s'#<bool name=\"logger_enabled\">true</bool>#<bool name=\"logger_enabled\">false</bool>#' ../app/src/main/res/values/setup.xml")
  235. end
  236. desc "Upload to play store (beta)"
  237. private_lane :uploadToPlaystore_RC do |options|
  238. upload_to_play_store(
  239. skip_upload_images: true,
  240. track: 'beta',
  241. aab: "release/app-gplay-release.aab"
  242. )
  243. end
  244. desc "Upload to play store"
  245. private_lane :uploadToPlaystore_Final do |options|
  246. upload_to_play_store(
  247. skip_upload_images: true,
  248. aab: "release/app-gplay-release.aab"
  249. )
  250. end
  251. desc "Build app bundle"
  252. private_lane :buildBundle do |options|
  253. gradle(
  254. task: 'bundle',
  255. flavor: options[:flavor],
  256. build_type: 'Release',
  257. print_command: false,
  258. properties: {
  259. "android.injected.signing.store.file" => ENV["FASTLANE_NEXTCLOUD_UPLOAD_STORE_FILE"],
  260. "android.injected.signing.store.password" => ENV["FASTLANE_NEXTCLOUD_UPLOAD_STORE_PASSWORD"],
  261. "android.injected.signing.key.alias" => ENV["FASTLANE_NEXTCLOUD_UPLOAD_KEY_ALIAS"],
  262. "android.injected.signing.key.password" => ENV["FASTLANE_NEXTCLOUD_UPLOAD_KEY_PASSWORD"],
  263. }
  264. )
  265. end
  266. desc "Generate signed universal APK from app bundle"
  267. private_lane :buildApkFromBundle do |options|
  268. sh(command:"bundletool build-apks --mode universal --output '#{options[:outputDir]}' --output-format DIRECTORY" +
  269. " --ks '#{ENV["FASTLANE_NEXTCLOUD_STORE_FILE"]}'"+
  270. " --ks-pass 'pass:#{ENV["FASTLANE_NEXTCLOUD_STORE_PASSWORD"]}'"+
  271. " --ks-key-alias '#{ENV["FASTLANE_NEXTCLOUD_KEY_ALIAS"]}'"+
  272. " --key-pass 'pass:#{ENV["FASTLANE_NEXTCLOUD_KEY_PASSWORD"]}'"+
  273. " --bundle '#{options[:bundlePath]}'",
  274. log:false)
  275. end
  276. desc "Build signed APK"
  277. private_lane :SignedRelease do |options|
  278. gradle(
  279. task: 'assemble',
  280. flavor: options[:flavor],
  281. build_type: 'Release',
  282. print_command: false,
  283. properties: {
  284. "android.injected.signing.store.file" => ENV["FASTLANE_NEXTCLOUD_STORE_FILE"],
  285. "android.injected.signing.store.password" => ENV["FASTLANE_NEXTCLOUD_STORE_PASSWORD"],
  286. "android.injected.signing.key.alias" => ENV["FASTLANE_NEXTCLOUD_KEY_ALIAS"],
  287. "android.injected.signing.key.password" => ENV["FASTLANE_NEXTCLOUD_KEY_PASSWORD"],
  288. }
  289. )
  290. end
  291. private_lane :createGithubRelease_RC do |options|
  292. set_github_release(
  293. repository_name: "nextcloud/android",
  294. api_token: ENV["FASTLANE_NEXTCLOUD_GITHUB_API_TOKEN"],
  295. name: options["versionName"],
  296. tag_name: options["tag"],
  297. is_prerelease: true,
  298. description: (File.read("metadata/android/en-US/changelogs/" + options["versionCode"] + ".txt") rescue "No changelog provided"),
  299. upload_assets: [ "release/gplay-release-" + options["versionCode"] + ".apk", "release/nextcloud-" +
  300. options["versionCode"] + ".apk" ]
  301. )
  302. end
  303. private_lane :createGithubRelease_Final do |options|
  304. set_github_release(
  305. repository_name: "nextcloud/android",
  306. api_token: ENV["FASTLANE_NEXTCLOUD_GITHUB_API_TOKEN"],
  307. name: options["versionName"],
  308. tag_name: options["tag"],
  309. description: (File.read("metadata/android/en-US/changelogs/" + options["versionCode"] + ".txt") rescue "No changelog provided"),
  310. upload_assets: [ "release/gplay-release-" + options["versionCode"] + ".apk", "release/nextcloud-" +
  311. options["versionCode"] + ".apk" ]
  312. )
  313. end
  314. private_lane :fdroidMergeRequest_RC do |options|
  315. sh("fdroidMergeRequestRC " + options["tag"] + " \"" + options["versionName"] + "\" " + options["versionCode"])
  316. end
  317. private_lane :fdroidMergeRequest_Final do |options|
  318. sh("fdroidMergeRequestFinal " + options["tag"] + " \"" + options["versionName"] + "\" " + options["versionCode"])
  319. end
  320. private_lane :checkChangelog do |options|
  321. sh(" if [ ! -e metadata/android/en-US/changelogs/" + options["versionCode"] + ".txt ] ; then echo 'Changelog fastlane/metadata/android/en-US/changelogs/" + options["versionCode"] + ".txt does not exist' ; exit 1 ; fi")
  322. sh(" if [ $(wc -m metadata/android/en-US/changelogs/" + options["versionCode"] + ".txt | cut -d' ' -f1) -ge 500 ] ; then echo 'Changlog more than 500 chars' ; exit 1 ; fi")
  323. end