developing android plugin Сергей Боиштян
обо мне android преподаю team lead разработчик в TFS Android член один программного один из ведущих архитектор из организаторов комитета #AndroidDevPodcast « Mosdroid » « Mobius » 2
о чем поговорим о проблеме о том как связать task o том как писать для которой мне из своего plugin plugin понадобился plugin со сторонними 3
предисловие например сделать apk для тестирования появилось много ответственностей связанных с процессом я стал «Лидом»/ «Архитектором» 4
сделать сборку тестировщику саму сборку не просто понять, что сделать просто: тестировать на сборке • задача и сборка не связаны • сделать apk • может быть несколько сборок • залить в hockeyapp, Beta параллельно 5
алгоритм решения 1 2 3 4 перевести проставить отправить сделать apk задачи внутри в hockeyapp, versionname, в нужный задач beta versioncode, статус версию archivename для связи связать с со сборкой версией 6
алгоритм решения apk JIRA hockeyAPP версия статус c вязать apk в задачах задач c версией 7
проблемы нет явного триггера для действия много шагов можно заболеть легко забыть что - нибудь 8
9
когда «накипело» начал искать оказалось, что их и было то, которое решения много я взял за основу 10
решение, взятое за основу есть специальная ветка в git задачи меняют а pk попадает статус в hockeyApp она собирает apk versionName, versionCode проставляются в нее попадают в задаче изменения versioncode — триггерится versionname teamcity сборка на ci берется buildnumber из локального файла 11
алгоритм решения инкремент commit versionCode git teamcity проставить в задаче APK versioncode, versionCode=buildNumber versionname versionName= из файла поменять статус задачам hockeyAPP JIRA 12
недостатки решения для инкремента versionCode = триггерим версии нужно синтетический вручную сделать commit buildNumber 13
что я улучшил что позволило автоматизировать изменил инкремент версии триггер, для формирования сборки 14
инкремент версии: формат формат — Semantic Versioning Specification MAJOR.MINOR.PATCH 1.0.0-rc1 1.1.1-rc2 1.2.3-beta 15
инкремент версии: хранение git tag -a 1.0.0-rc1 - m ‘message’ • не ломает историю • легче добавить/удалить на remote • своя система прав 16
триггер инкремента версии когда появились задачи в нужном статусе в JIRA 17
реализация инкремента версии доработал https://github.com/gladed/gradle-android-git-version реализовал инкремент Из 1.1.0 -rc10 в 1.1.1 -rc1 Из 1.1.1 -rc1 в 1.1.1 -rc2 Из 1.1.10 -rc2 в 1.2.1 -rc1 18
реализация инкремента версии добавил: • запись в tag • push tag в remote 19
мое решение инкремент versionCode появление задач в Jira teamcity проставить в задаче apk versioncode, versionCode= git tag versionname versionName= git tag поменять статус задачам hockeyAPP JIRA 20
автоматизируем ➔ bash ➔ fastline (ruby) ➔ gradle ➔ etc. 21
почему gradle? возможность писать нативная система плагинная на java, kotlin, scala :? сборки система но кого я обманываю groovy 22
знакомство build script build script plugin writer plugin writer app developer writer writer plugin writer 23
gadle plugin легко шарить легче поддерживать легче тестировать 24
структура плагина ➔ это gradle проект ➔ build.gradle ➔ plugin class ➔ descriptor ➔ one or more tasks ➔ extension 25
структура плагина plugin extention task descriptor build.gradle 26
структура плагина apply plugin: 'groovy' apply plugin: 'idea' repositories { mavenCentral() } dependencies { compile localGroovy() compile gradleApi() compile 'commons-io:commons-io:2.4' testCompile 'junit:junit:4.12' } 27
plugin class c оздание c вязь c оздание extension с build chain task 28
plugin class class HockeyAppPlugin implements Plugin<Project> { void apply(Project project) { project.extensions.create('hockeyapp', HockeyAppPluginExtension, project) if (project.plugins.hasPlugin(AppPlugin)) { AppExtension android = project.android android.applicationVariants.all { variant -> def taskName = "upload${variant.name.capitalize()}ToHockeyApp" def uploadTask = project.tasks.create(taskName, HockeyAppUploadTask) uploadTask.group = 'HockeyApp' uploadTask.dependsOn variant.assemble } } } } 29
plugin class — create task class HockeyAppPlugin implements Plugin<Project> { void apply(Project project) { project.extensions.create('hockeyapp', HockeyAppPluginExtension, project) if (project.plugins.hasPlugin(AppPlugin)) { AppExtension android = project.android android.applicationVariants.all { variant -> def taskName = "upload${variant.name.capitalize()}ToHockeyApp" def uploadT adTas ask = projec ect.tas asks.cr creat ate(tas askNam ame, Hockey eyAp AppUp UploadT adTas ask) uploadTask.group = 'HockeyApp' uploadTask.dependsOn variant.assemble } } } } 30
plugin class — extention class HockeyAppPlugin implements Plugin<Project> { void apply(Project project) { projec ect.ex exten ension ions.cre creat ate('hock ockey eyapp app', Hockey ckeyAppPlug uginE nExtens xtension on) //... } } } 31
plugin class — связь с build chain class HockeyAppPlugin implements Plugin<Project> { void apply(Project project) { project.extensions.create('hockeyapp', HockeyAppPluginExtension, project) if (project.plugins.hasPlugin(AppPlugin)) { AppExtension android = project.android android.applicationVariants.all { variant -> def taskName = "upload${variant.name.capitalize()}ToHockeyApp" def uploadTask = project.tasks.create(taskName, HockeyAppUploadTask) uploadTask.group = 'HockeyApp' upload adTask Task.de depe pends ndsOn On variant iant.asse semb mble le } } } 32 }
task class HockeyAppUploadTask extends DefaultTask { @TaskAction def upload() throws IOException { //... } 33
task — group name class HockeyAppPlugin implements Plugin<Project> { void apply(Project project) { project.extensions.create('hockeyapp', HockeyAppPluginExtension, project) if (project.plugins.hasPlugin(AppPlugin)) { AppExtension android = project.android android.applicationVariants.all { variant -> def taskName = "upload${variant.name.capitalize()}ToHockeyApp" def uploadTask = project.tasks.create(taskName, HockeyAppUploadTask) upload adTask Task.gro group up = 'Hocke ckeyApp' p' } } } } 34
extension for users hockeyapp { notify = 1 status = 2 notesType = 0 releaseType = 0 teamCityLog = true repositoryUrl = '' variantToApplicationId = [] } 35
extention class class HockeyAppPluginExtension { def Object outputDirectory def File symbolsDirectory = null def String apiToken = null def Map<String, String> variantToApiToken = null def Map<String, String> variantToNotes = null def String status = 2 def String strategy = "add" def String notify = 0 def Map<String, String> variantToNotify = null //... } 36
find extention HockeyAppPluginExtension hockeyApp = project.hockeyapp 37
descriptor implementation-class=de.felixschulze.gradle.HockeyAppPlugin apply plugin: ‘descriptor file name’ 38
подключение к своему проекту In build.gradle apply plugin: ‘descriptor file name' hockeyapp { //... } 39
Recommend
More recommend