<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Sebastian Cipolat on Medium]]></title>
        <description><![CDATA[Stories by Sebastian Cipolat on Medium]]></description>
        <link>https://medium.com/@sebastiancipolat?source=rss-176d4152a94b------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*opb3KGrAoZJcKNPh.</url>
            <title>Stories by Sebastian Cipolat on Medium</title>
            <link>https://medium.com/@sebastiancipolat?source=rss-176d4152a94b------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 01:35:21 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@sebastiancipolat/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Aumenta tu productividad creando proyectos Android con Plop.js”]]></title>
            <link>https://medium.com/@sebastiancipolat/aumenta-tu-productividad-creando-proyectos-android-con-plop-js-a02a8613ad19?source=rss-176d4152a94b------2</link>
            <guid isPermaLink="false">https://medium.com/p/a02a8613ad19</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[seniors]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[tools]]></category>
            <category><![CDATA[mobile]]></category>
            <dc:creator><![CDATA[Sebastian Cipolat]]></dc:creator>
            <pubDate>Mon, 04 Mar 2024 02:01:30 GMT</pubDate>
            <atom:updated>2024-03-04T02:01:30.830Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4lbpQmh5Rz6aip47QW65YA.png" /></figure><p>Iniciar un nuevo proyecto es la oportunidad de crear una nueva feature, usar nuevas api, explorar nuevas practicas, pero muchas veces todo esto se ve demorado por la necesidad de incluir configuraciones iniciales, como dependencias, crear arboles de directorios, etc. En el mundo laboral mejorar este escenario es un plus.</p><p>Pero que tal si te digo que puedes usar una herramienta que te permite crear un nuevo proyecto a vos y demas equipos con todas esas configuraciones en un instante.</p><p>El dia de hoy veremos una tool basada en NodeJs llamada <a href="https://plopjs.com/">https://plopjs.com/</a></p><p>Plop.js es una herramienta de generación de código que ayuda a los desarrolladores a automatizar tareas repetitivas durante el proceso de desarrollo de software. Permite definir y ejecutar “generadores”, que son pequeños scripts o plantillas que crean archivos y estructuras de directorios de manera programática. Esto es útil para evitar la repetición de configuraciones y patrones comunes en proyectos de software, lo que ahorra tiempo y reduce errores. Plop.js es especialmente útil en entornos de desarrollo web, pero también se puede utilizar en una variedad de otros contextos de desarrollo de software tales como Android como veremos hoy.</p><h3>Comencemos:</h3><p>Veamos rapidamente de que se trata pllopjs</p><p><strong>1-Instalar NodeJs</strong></p><p>Lo primero que debemos hacer es instalar NodeJS, aqui dejo un articulo de como hacerlo <a href="https://kinsta.com/es/blog/como-instalar-node-js/">https://kinsta.com/es/blog/como-instalar-node-js/</a></p><p><strong>2-Instalar PlopJS</strong></p><pre>npm install -g plop</pre><p><strong>3-Crear archivo plop.js</strong></p><p>Este es el archivo que sera el generador de template en este se distinguen 2 array prompts y actions.</p><pre>export default function (plop) {<br>    // controller generator<br>    plop.setGenerator(&#39;controller&#39;, {<br>        description: &#39;application controller logic&#39;,<br>        prompts: [{<br>            type: &#39;input&#39;,<br>            name: &#39;name&#39;,<br>            message: &#39;controller name please&#39;<br>        }],<br>        actions: [{<br>            type: &#39;add&#39;,<br>            path: &#39;src/{{name}}.js&#39;,<br>            templateFile: &#39;plop-templates/controller.hbs&#39;<br>        }]<br>    });<br>};</pre><p>“<strong>prompts</strong>” seran los inputs que se le mostraran al usuario.</p><p><strong>“actions” </strong>son las acciones que se realizaran con los inputs</p><p><strong>4- Ejecución</strong></p><pre>npm run plop</pre><p>Al ejecutarlo veremos lo siguiente:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/322/1*1ln9BI2DRHXmJ_F0uzQQ2w.png" /></figure><p>Este input responde al contenido de array prompts</p><pre>{<br>  type: &#39;input&#39;,<br>  name: &#39;name&#39;,<br>  message: &#39;controller name please&#39;<br>}</pre><p>Al ingresar un valor lo mapeara a una variable llamada <strong>“name”</strong></p><p>Luego ejecutara un action</p><pre>{<br>   type: &#39;add&#39;,<br>   path: &#39;src/{{name}}.js&#39;,<br>   templateFile: &#39;plop-templates/controller.hbs&#39;<br> }</pre><p>En este caso utilizara el action<strong> “add” </strong><a href="https://plopjs.com/documentation/#add">https://plopjs.com/documentation/#add</a></p><p>este agregara dentro del path “<strong>src/{{name}}.js”</strong></p><p><strong>name=</strong> sera el valor ingresado en el input previo.</p><p>el contenido del template definido en<strong> “plop-templates/controller.hbs’”</strong></p><p>Ej, si en el input ingresamos el valor “<strong>helper</strong>” el archivo final se llamara src/helper.js&#39; y el cotenido obtenido de <strong>plop-templates/controller.hbs </strong>sera procesado y en caso de contar con<strong> {{name}}</strong>. tambien sera modificado .</p><h3><strong>DroidTemplateWizard</strong></h3><p>Arme una pequeña tool basado en lo anterior la cual nos va permitir crear nuevos proyectos usando como base un proyecto de Android Studio.</p><p><strong>Repositorio: </strong><a href="https://github.com/sebacipolat/DroidTemplateWizard">https://github.com/sebacipolat/DroidTemplateWizard</a></p><p>Este manejara 2 datos: name packageID</p><p>El archivo plop sera el siguiente:</p><pre>const logo = require(&#39;./logo.js&#39;);<br><br><br>function welcome() {<br>    console.log(logo);<br>    console.log(&quot;********************************************&quot;); <br>    console.log(&quot;  Welcome to the Android Module Generator   &quot;); <br>    console.log(&quot;********************************************&quot;); <br>}<br><br>// Configuración de Plop<br>module.exports = function (plop) {<br>    welcome();<br>    // controller generator<br>    plop.setGenerator(&#39;controller&#39;, {<br>        description: &#39;application controller logic&#39;,<br>        prompts: [{<br>            type: &#39;input&#39;,<br>            name: &#39;name&#39;,<br>            message: &#39;Module name:&#39;<br>        },<br>        {<br>            type: &#39;input&#39;,<br>            name: &#39;packageID&#39;,<br>            message: &#39;Package:&#39;<br>        }],<br>        actions: [{<br>            type: &#39;addMany&#39;,<br>            destination: &#39;output/&#39;,<br>            templateFiles: &#39;template/**/*&#39;<br>        }]<br>    });<br>};</pre><p>Al ejecutarlo se crearan las siguientes variables las cuales utilizadas en los templates para ser reemplazada por el contenido ingresada en estos.</p><p><strong>name</strong>= nombre del proyecto<strong> {{name}}</strong></p><p><strong>package</strong>= el package que usaremos tanto para la app y modulo <strong>{{packageID}}</strong></p><p>En la consolo veremos:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/518/0*cMVMDRhAfk59ku1E" /></figure><p>El action a ejecutar sera “addMany” <a href="https://plopjs.com/documentation/#addmany">https://plopjs.com/documentation/#addmany</a></p><pre>  actions: [{<br>            type: &#39;addMany&#39;,<br>            destination: &#39;output/&#39;,<br>            templateFiles: &#39;template/**/*&#39;<br>        }]</pre><p>Este tomara todos los archivos ubicado en el folder /template y los copiara al path ouput/</p><p>A su vez tambien examinara el contenido de todos los archivos del template para reemplazar si existiese el contenido de alguna de las variables ya mensionada.</p><h3><strong>Template:</strong></h3><p>Este sera la plantilla que plop utilizara para armar el output, sobre este seran reemplazadas las variables que hayan sido definidas en pasos previos.</p><p>En mi caso esta compuesto por una app y un modulo dentro, esto fue pensado para el uso en apps modulares ya que permitiria crear nuevos modulos a todos los equipos usando las mismas configuaciones iniciales.</p><p>Se lo encuentra dentro de la carpeta template:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/574/1*n0lJpuU9eGQB7vzZ-uAWbw.png" /></figure><p>El nombre del proyecto y el modulo sera <strong>{{name}}</strong></p><p><strong>{{packageID}} </strong>sera el package que usaremos</p><p>Al ejecutar el action recorrera el template y reemplazara las variables “<strong>{{name}},{{packageID}}” </strong>por los valores ingresados. Se lo reemplazara tanto en el contenido de los archidos como en su nombre.</p><p><strong>Algunos Ejemplos:</strong></p><p>*build.gradle</p><p>el namespace y appID sera armado usando la variable <strong>{{packageID}}</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/690/1*SWIChMX8nLv4kjZVbWX1og.png" /></figure><p>*Agregar el modulo como dependencia</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/648/1*3AHNeZcR7yqB3vYX-pgsvA.png" /></figure><p>*Package dentro de cada archivo</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/377/1*yuCTCXcRBw7g_6Fa47e3Rw.png" /></figure><p>Como veras es muy simple solo debes reemplazar por una variable el contenido que deseas que se modifique segun un valor ingresador por consola. En este caso fue pensado para Android pero puede ser adaptado para cualquier lenguaje</p><h3><strong>Demo:</strong></h3><p>Ejecutamos</p><pre>npm run plop</pre><p>Ingresaremos:</p><p><strong>Module name:</strong> pdf-viewer</p><p><strong>Package:</strong> com.pdf.sdk</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/610/1*D0t3uOG8RvnNp7Z3cszfHQ.png" /></figure><p>Veremos que luego de ingresar los valores requeridos comenzara a copiar los archivos dentro de la carpeta output</p><p>El proyecto resultante sera el siguiente:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/493/1*kEJ8i0Qps6eevCxx9wTawg.png" /></figure><p>De esta forma puedes armar tu propio generador para tus proyectos usando tus templates y ahorrar tiempo.</p><p>Agregar nuevos campos es muy facil como se muestra en los ejemplos.</p><p>Espero que te sea de utilidad!!</p><p>Plop tiene muchas funcionalidades mas de las aqui expuestas, si quieres conocer un poco mas te dejo un par de links.</p><p><a href="https://plopjs.com/documentation/#getting-started">Plop: Consistency Made Simple</a></p><p><a href="https://www.paradigmadigital.com/dev/plop-js-creando-archivos-con-uniformidad/">https://www.paradigmadigital.com/dev/plop-js-creando-archivos-con-uniformidad/</a></p><p><a href="https://medium.com/@fgmonaghan/boost-your-coding-productivity-with-plop-tutorial-68f2a50b15f3">Boost your coding productivity with Plop: Tutorial</a></p><p><a href="https://claritydev.net/blog/scaffolding-redux-boilerplate-with-code-generators">https://claritydev.net/blog/scaffolding-redux-boilerplate-with-code-generators</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a02a8613ad19" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Como publicar tu primera libreria Android en MavenCentral!]]></title>
            <link>https://medium.com/@sebastiancipolat/como-publicar-tu-primera-libreria-android-en-mavencentral-50f0aa60fa93?source=rss-176d4152a94b------2</link>
            <guid isPermaLink="false">https://medium.com/p/50f0aa60fa93</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[gradle]]></category>
            <category><![CDATA[android-development]]></category>
            <category><![CDATA[maven-central]]></category>
            <category><![CDATA[sdk]]></category>
            <dc:creator><![CDATA[Sebastian Cipolat]]></dc:creator>
            <pubDate>Fri, 19 Jan 2024 19:28:11 GMT</pubDate>
            <atom:updated>2024-01-20T00:09:33.713Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-Az3yN1vI9gw1HK8qEItTQ.jpeg" /></figure><p>Recientemente termine mi primera libreria para Android llamada <a href="https://github.com/sebacipolat/WolfGuard">Wolfguard</a> esta permite realizar RASP (Runtime Application Self-Protection) para proteger nuestra app.</p><p>Para poder disponibilizarla a la comunidad debi atravezar el proceso de publicación en MavenCentral, este fue bastante complejo y me tomo casi mas tiempo que la libreria en si. Asi que el dia de hoy te explicare los pasos que realice para poder publicarla, el cual es en parte recopilación de varios post y parte mia.</p><p>Omitire todo lo relacioando a creacion de una libreria ya que no es el proposito del post.</p><h3>Pasos a realizar</h3><ol><li>Registrar el Group ID en MavenCentral creando un ticket de jira</li><li>Configurar el plugin maven-publish dentro del archivo gradle.</li><li>Configurar credenciales de publicación y creación de llave para firmar</li><li>Publicar en ambiente Staging, Release</li><li>Consumir libreria dese MavenCentral</li></ol><h3><strong>1-Registrar el Group ID en MavenCentral creando un ticket de jira</strong></h3><p>El acceso a maven se gestions mediante la creación de un ticket de jira por lo que primero deberas crear credenciales para poder acceder.</p><p>Acceder a <a href="https://issues.sonatype.org/secure/Signup!default.jspa">https://issues.sonatype.org/secure/Signup!default.jspa</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/590/1*UFsaC7bBdnjq007TuUU9GQ.png" /></figure><p><strong>Es importante que tengas presente estas credenciales ya que las usaremos mas adente.</strong></p><p>Inicia sesión con las credenciales creadas recientemente.</p><p><strong>Aqui te dejo la documentación oficial sobre este proceso</strong>.<a href="https://central.sonatype.org/publish/publish-guide/#deployment">https://central.sonatype.org/publish/publish-guide/#deployment</a></p><p>Luego pulsa el boton create para crear un ticket nuevo.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/725/1*2iUu0_ZFiMdyiOruu9B6OA.png" /></figure><p>Aqui te dejo de ejemplo el ticket que cree yo para que uses de referencia <a href="https://issues.sonatype.org/browse/OSSRH-98284">https://issues.sonatype.org/browse/OSSRH-98284</a></p><p>Debes indicar la url del repositorio en summary.</p><p>Campo <strong>Groud id :</strong></p><p><a href="https://central.sonatype.org/publish/requirements/coordinates/">https://central.sonatype.org/publish/requirements/coordinates/</a></p><p>Este es el package que va identificar a tu libreria.</p><p>Aqui es donde empieza a complicarse el proceso ya que el valor a utilizar dependera de si eres dueño del dominio.</p><h4><strong>Ejemplo:</strong></h4><p>El package inicial de mi liberia incluia mi apellido <strong>com.cipolat.wolfguard</strong> pero para poder usarlo debia poseer el dominio cipolat.com (el cual no lo tengo) ya que debia tener que hacer una modificacion en el DNS del hosting . Mas info <a href="https://central.sonatype.org/faq/how-to-set-txt-record/">https://central.sonatype.org/faq/how-to-set-txt-record/</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/991/1*IuW6mnEyvvEJdk3WaL_XRg.png" /></figure><p>Si cargo el ticket usando ese dominio se me pedira que lo demuestre .</p><p>En este caso donde solo tengo el repositorios se me sugiere un group id <strong>io.github.sebacipolat </strong>este se armo usando la direccion de mi repositorio, por lo que opto por :</p><p><strong>io.github.sebacipolat.wolfguard.sdk</strong></p><p>una vez definido debemos colocarlo en el campo correspondiente y continuar con los demas, puede que necesites modificar los package dentro de tu codigo para adecuarse.</p><p>Una vez creado el ticket tardaran algunos minutos en procesarlo.</p><p>Si todo fue correcto veras un mensaje de este tipo</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/904/1*k8p2-cRGv3U6wCgK8vDUCw.png" /></figure><p>En mi caso se me asigno el ambiente <strong>s01.oss.sonatype.org</strong></p><h3><strong>2-Configurar el plugin maven-publish dentro del archivo gradle.</strong></h3><p>Para realizar la subida de nuestro aar a maven usaremos el gradle de plugin <strong>maven-publish</strong></p><p>En mi caso estoy usando la version gradle-8.0 del wraper de gradle-</p><p>Vamos a crear dentro de nuestro modulo un archivo llamado publish-package.gradle con el siguiente contenido</p><pre>apply plugin: &#39;maven-publish&#39;<br>apply plugin: &#39;signing&#39;<br><br>task androidJavadoc(type: Javadoc) {<br>    source = android.sourceSets.main.java.srcDirs<br>    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))<br><br>    exclude &#39;**/R.html&#39;, &#39;**/R.*.html&#39;, &#39;**/index.html&#39;<br>    options.encoding &#39;utf-8&#39;<br>    options {<br>        addStringOption &#39;docencoding&#39;, &#39;utf-8&#39;<br>        addStringOption &#39;charset&#39;, &#39;utf-8&#39;<br>        links &#39;https://docs.oracle.com/javase/7/docs/api/&#39;<br>        links &#39;https://d.android.com/reference&#39;<br>        links &#39;https://developer.android.com/reference/androidx/&#39;<br>    }<br>}<br><br>task androidJavadocJar(type: Jar, dependsOn: androidJavadoc) {<br>    archiveClassifier.set(&#39;javadoc&#39;)<br>    from androidJavadoc.destinationDir<br>    preserveFileTimestamps = false<br>    reproducibleFileOrder = true<br>}<br><br>task javaSourcesJar(type: Jar) {<br>    archiveClassifier.set(&#39;sources&#39;)<br>    from android.sourceSets.main.java.srcDirs<br>    preserveFileTimestamps = false<br>    reproducibleFileOrder = true<br>}<br><br>afterEvaluate {<br>    publishing {<br>        publications {<br>            release(MavenPublication) {<br>                from components.release<br>                groupId &#39;GROUP_ID&#39;<br>                version VERSION_NAME<br>                pom {<br>                    name = artifactId<br>                    description = POM_DESCRIPTION<br>                    url = &#39;URL repositorio&#39;<br>                    licenses {<br>                        license {<br>                            name = &#39;name licenca&#39;<br>                            url = &#39;url licencia&#39;<br>                        }<br>                    }<br>                    scm {<br>                        connection = &#39;scm:url repo en formato ssh&#39; // ej en mi caso git@github.com:sebacipolat/WolfGuard.git<br>                        url =&#39;https://github.com/sebacipolat/WolfGuard.git&#39;// en mi caso fue &#39;https://github.com/sebacipolat/WolfGuard.git&#39;<br>                    }<br>                    developers {<br>                        developer {<br>                            id = POM_DEVELOPER_ID<br>                            name = POM_DEVELOPER_NAME<br>                            email = POM_DEVELOPER_EMAIL<br>                        }<br>                    }<br>                }<br>            }<br>        }<br>        repositories {<br>            maven {<br>                name = &quot;SonatypeSnapshot&quot;<br>                url = &quot;https://s01.oss.sonatype.org/content/repositories/snapshots/&quot;<br><br>                credentials {<br>                    username ossrhUsername<br>                    password ossrhPassword<br>                }<br>            }<br><br>            maven {<br>                name = &quot;sonatype&quot;<br>                def releasesRepoUrl = &quot;https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/&quot;<br>                def snapshotsRepoUrl = &quot;https://s01.oss.sonatype.org/content/repositories/snapshots/&quot;<br>                url = version.endsWith(&#39;SNAPSHOT&#39;) ? snapshotsRepoUrl : releasesRepoUrl<br>                credentials {<br>                    username ossrhUsername<br>                    password ossrhPassword<br>                }<br>            }<br>        }<br>    }<br>}<br><br>signing {<br>    sign publishing.publications<br>}</pre><p>En el build gradle de tu modulo deberas agregar</p><pre>apply(from = &quot;../publish-package.gradle&quot;)</pre><p>Luego agregaremos dentro de nuestro gradle.properties los siguientes valores:</p><pre>#PUBLISHIN MAVEN CENTRAL<br>VERSION_NAME=#Version de la lib ej 1.0.0<br>VERSION_CODE=#version code ej 1000<br>GROUP=group_ID # el mismo que pusimos en el ticket de jira io.github.sebacipolat.wolfguard<br><br>POM_DESCRIPTION=#Desciprcion de la libreria<br>POM_URL=#URL repositorio<br>POM_SCM_URL=#URL repositorio<br>POM_SCM_CONNECTION=scm:git@github.com/sebacipolat/WolfGuard.git #reemplazar por el correspondiente en tu caso<br>POM_SCM_DEV_CONNECTION=#idem anterior<br>POM_LICENCE_NAME=MIT License #licencia <br>POM_LICENCE_URL=https://github.com/GeofriendTech/AndroidUtils/blob/main/LICENSE<br>POM_LICENCE_DIST=repo<br>POM_DEVELOPER_ID=#username de jira<br>POM_DEVELOPER_NAME=#Nombre del developer<br>POM_DEVELOPER_EMAIL=#email<br><br>ossrhUsername=#username de jira<br>ossrhPassword=#Password de jira<br></pre><h3><strong>3- Configurar credenciales de publicación y creación de llave para firmar</strong></h3><p><strong>Crear clave GPG:</strong></p><p>Los artefactor que subiremos deberan estar firmados con una clave la cual crearemos de la siguiente forma:</p><p>En mi caso lo hice usando Linux ubuntu</p><pre> gpg --gen-key</pre><p>Te solicitara nombre, apellido, email y luego generar un passprhase</p><p>Una vez creado deberas ejecutar el siguiente para obtener el ID de la key generada</p><pre>gpg --list-keys --keyid-format short</pre><p>La respuesta sera de este tipo</p><pre>pub   rsa4096/AAAA12345 2024-01-14 [SC]<br>      FA0BA8858D1CC91A433F38470760324FDF2A3EE5<br>uid      [  absoluta ] Nombre y apellido &lt;email&gt;<br>sub   rsa4096/F2ED5C25 2024-01-14 [E]</pre><p>pon atención a la primera linea pub rsa4096/<strong>AAAA12345</strong> 2024–01–14 [SC]</p><p>en este caso <strong>AAAA12345 </strong>sera tu ID.</p><p>Luego debemos exportar estas key a un file</p><pre>gpg --export-secret-keys -o secring.gpg </pre><p>Luego debemos volver al archivo gradle.properties y agregar lo siguiente:</p><pre>signing.keyId=#id creado usando gdg en nuestro caso ej:AAAA12345<br>signing.password=#passprhase<br>signing.secretKeyRingFile=#path del archivo secring.gpg<br><br>ossrhUsername=#jira username<br>ossrhPassword=#jira password</pre><p>Debemos enviar nuestra clave pública identificada por “AAAA12345” a dos servidores de claves diferentes. Estos son usados por maven para poder leer nuestro aar</p><pre>gpg --keyserver hkp://pool.sks-keyservers.net --send-keys AAAA12345 #idclave<br>gpg --keyserver hkp://keyserver.ubuntu.com --send-keys AAAA12345   #idclave</pre><h3><strong>4- Publicar en ambiente Staging, Release</strong></h3><p>En maven existen 2 tipos de publicaciones:</p><h4>Snapshot:</h4><p>En el contexto de Maven, un “snapshot” se refiere a una versión de desarrollo de un proyecto que está en constante evolución que aún no ha alcanzado un estado de estabilidad para ser liberada como una versión final o estable.</p><p>Estas versiones suelen tener el sufijo “-SNAPSHOT” en su número de versión. Por ejemplo, “1.0-SNAPSHOT”.</p><h4>Release:</h4><p>Se refiere a una versión estable y final de un proyecto que se considera apta para su uso en entornos de producción.</p><h4>Generando aar:</h4><p>Antes de comenzar a publicar primero sugiero generar un .aar y verificar su contenido.</p><pre>gradle :module-name:assemble</pre><p>Dentro de la carpeta /outputs/aar del modulo veremos que se generaran 2 archivos</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/238/1*YWueHQP6ech6EUSCe_FdxA.png" /></figure><p>Sugiero utilizar la herramienta <a href="http://java-decompiler.github.io/">http://java-decompiler.github.io/</a> para poder inspeccionar el contenido dentro, si puedes ver el codigo dentro del jar classes.jar este se empaqueto correctamente.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/369/1*QcvS3J7OvwxsA8jYdZcp1A.png" /></figure><p>En caso de que no este revisa la configuración del build.gradle del modulo ya que tal vez debas ajustar tu archivo proguard.</p><h4>Publicando en Maven:</h4><p>Una vez que ya sabemos que nuestro aar esta correcto vamos a publicarlo.</p><h4>Subir Snapshot.</h4><p>Cambiemos nuestra version del modulo en el gradle.properties a</p><pre>VERSION_NAME=0.0.1-SNAPSHOT</pre><p>Luego ejecuta</p><pre>gradle :module-name:publishReleasePublicationToSonatypeSnapshotRepository</pre><p>Debes usar la url que se te asigno al momento de crear el ticket.</p><p><a href="https://s01.oss.sonatype.org/content/repositories/snapshots/io/github/sebacipolat/">https://s01.oss.sonatype.org/content/repositories/snapshots/&lt;</a>group_id&gt;</p><p>En mi caso: <a href="https://s01.oss.sonatype.org/content/repositories/snapshots/io/github/sebacipolat/wolfguard-sdk/">https://s01.oss.sonatype.org/content/repositories/snapshots/io/github/sebacipolat/</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0zUnZRA4GVsw9JKagE7FZg.png" /></figure><p>Si abres la versión snapshot veras el aar</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/815/1*HEFDLQsuPvJTDBInOALLag.png" /></figure><h4>Subir Relase:</h4><p>Cambiar versión en gradle.properties:</p><pre>VERSION_NAME=1.0.0</pre><p>Ejecuta:</p><pre>gradle :module-name:publishReleasePublicationToSonatypeRepository</pre><p>Aqui se pone un poco mas complicado el tema ya que deberas lanzarlo manualmente desde gradle</p><p>Accede a al ambiente que se nos asigno al crear el ticket. en mi caso es</p><p><a href="https://s01.oss.sonatype.org/#welcome">https://s01.oss.sonatype.org/#welcome</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GSIOK3DSBO5bEhzRRizTKg.png" /></figure><p>Inicia sesión usando las credenciales de jira.</p><p>En el menu lateral izquierdo deberas ir a <strong>“Snapshot Repositories”</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/179/1*Eeljiiv5IgMTxujKCugAnw.png" /></figure><p>Veras algo de este tipo</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jHSTOwdTt2joci62B0DhFg.png" /></figure><p>Debras escogerlo y clickear en <strong>“Close”</strong></p><p>Esto va iniciar un proceso que tardara algunos minutos en terminar.</p><p>Debajo veras un tab “Activity” con el progreso, si no ves avance, recarga la pagina.</p><p>Una vez terminado veras algo de este tipo</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/402/1*-qqYetyCKydi5iUR3E45AA.png" /></figure><p>Tambien te llegara un email con el reporte del analisis de tu libreria.</p><p>Una vez llegado a este punto se habilitara la opción<strong> “Release”</strong> la cual deberas pulsar</p><p>Este proceso tomara algunos minutos, pero cuando termine podras verlo publicado aqui.</p><p>en mi caso <a href="https://repo1.maven.org/maven2/io/github/sebacipolat/wolfguard-sdk/1.0.0/">https://repo1.maven.org/maven2/io/github/sebacipolat/wolfguard-sdk/1.0.0/</a></p><p>Tambien si ingresamos a <a href="https://central.sonatype.com/">https://central.sonatype.com/</a></p><p>y buscamos por el nombre de nuestra libreria podremos encontrarla.</p><p>Ej: <a href="https://central.sonatype.com/artifact/io.github.sebacipolat/wolfguard-sdk">https://central.sonatype.com/artifact/io.github.sebacipolat/wolfguard-sdk</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FIsB6fQbXmyvEEvIfpMg2w.png" /></figure><p><a href="https://central.sonatype.com/artifact/io.github.sebacipolat/wolfguard-sdk">Maven Central: io.github.sebacipolat:wolfguard-sdk</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5FAJUQT4-kSLIFmVkK2RAA.png" /></figure><p>Una vez ya publicado cualquiera que obtenga dependencias de mavencentral podra consumirla agregando simplemente</p><pre>implementation(&quot;io.github.sebacipolat:wolfguard-sdk:1.0.2&quot;)</pre><p>Este proceso debe repetirse cada vez que deseas subir una nueva versión</p><p>Hasta aqui llegamos el dia de hoy.</p><p>Ahora ya no tienes exucsas para no publicar tus propias librerias y compartilas con la comunidad!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=50f0aa60fa93" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[La odisea de publicar una app en Google Play y los 20 testers]]></title>
            <link>https://medium.com/@sebastiancipolat/la-odisea-de-publicar-una-app-en-google-play-y-los-20-testers-8cc315f4d0f1?source=rss-176d4152a94b------2</link>
            <guid isPermaLink="false">https://medium.com/p/8cc315f4d0f1</guid>
            <category><![CDATA[mobile-apps]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[google-play]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Sebastian Cipolat]]></dc:creator>
            <pubDate>Thu, 21 Dec 2023 18:03:26 GMT</pubDate>
            <atom:updated>2023-12-21T18:03:26.903Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/568/1*WuG7XuGivumh7lbt5E_POA.png" /></figure><p>Hace algunas semanas Google play introdujo <a href="https://support.google.com/googleplay/android-developer/answer/14151465?hl=en">nuevos cambios</a> que aplican a todas las cuentas nuevas para usuarios particulares posteriores al 13 de Noviembre del 2023 que estan complicando a todos los desarrolladores indie.</p><p>Estos solicitan que para poder publicar una nueva aplicación deben cumplir con lo siguiente:</p><ul><li>Realizar una etapa de pruebas cerradas durante <strong>14 dias </strong>con al menos<strong> 20 testers.</strong></li><li>Las pruebas deben ser continuas y nunca disminuir el minimo de testers requeridos ya que de lo contrarion deberan volver a realizar el ciclo de pruebas cuando cumplan con la cantidad necesaria.</li></ul><p>La etapa de pruebas cerradas es algo que tiene sentido y es recomendable pero para un dev indie que muchas veces es el solo le resultara demasiado dificl conseguir esa cantidad de gente.</p><h4>¿Cuales son los motivos por los que Google tomo esta decision?</h4><p>En su comunicado menciona que es para elevar la calidad de la apps, pero esto suena raro ya que en las cuentas de tipo empresa no lo requieren.</p><p>A mi parecer es para poner un tope al tipo de apps que se estaban publicando ya que los devs indie no van a crear aplicaciones tan complejas como la de una empresa con un producto detras, sino muchisimo mas simples con una calidad muchisimo mas inferior.</p><h4>¿Es el fin de Google Plays?</h4><p>La realidad que no lo creo, solo va hacer que publicar una app sea mucho mas trabajoso y de seguro va desestimar la creacioón de muchas apps, tal vez gane popularidad algun store alternativo que tenga menos requerimientos, pero al ser Android la plataforma mas popular mundialmente y la mayoria ya traen pre instalado la app del playstore no creo que cambie mucho el panorama.</p><h4>¿Soy un dev indie y ahora como voy a poder cumplir con todo eso yo solo?</h4><p>Tranquilos que he atravezado este proceso y podido publicar una app en una cuenta nueva de forma exitosa y les voy a compartir todo lo que necesitan saber.</p><h3>Subiendo nuestra app a producción</h3><p>Una vez creada nuestra cuenta y dada de alta nuestra app, preparado la ficha, subir capturas, texto, etc lo primero que veremos al quere subirla a producción sera:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hDX4G3XseDqKehOMa9g_kw.png" /></figure><h3>1. Iniciando:</h3><p>Debemos crear una version de prueba usando el canal prueba cerra o closed testing, esto es algo relativamente muy simple de hacer <a href="https://support.google.com/googleplay/android-developer/answer/9845334?hl=en">https://support.google.com/googleplay/android-developer/answer/9845334?hl=en</a></p><h3>2. 20 Testers</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I-WseQDHkb0vKqvZ3MXm7A.png" /></figure><p>Aqui es donde empieza lo dificil conseguir 20 testers para que prueben nuestra app de forma continua durante 14 dias, en este punto hay 2 caminos que podemos seguir:</p><h4>Conseguir 20 personas dispuestas a probar nuestra app diariamente:</h4><p>En una empresa es algo relativamente simple de hacer con los miembros de los diversos equipos prueben y den feedback.</p><p>Para a un dev indie que probablemente sea el solo es muy dificil ya que tiene que salir a buscar gente dispuesta a probar su app de forma voluntaria.<br>Podria hacerse de varias formas:</p><ul><li><strong>Comunidades: </strong>Intentar conseguir gente que lo ayude, hay varias donde mediante discord crearon canales para tal fin.<br><strong> Redes sociales:</strong> ej reddit:</li></ul><p>Esto va ser dificil ya que va depender de la voluntad de otras personas.</p><p><a href="https://www.reddit.com/r/AndroidClosedTesting/">https://www.reddit.com/r/AndroidClosedTesting/</a></p><ul><li><strong>Contratar un servicio: <br></strong>El unico que encontre de momento es <a href="https://www.20testers.com/">https://www.20testers.com/</a> <br>No lo he probado, pero parece estar pensado para resolver este problema.</li></ul><h4>Crear 20 cuentas de Google:</h4><p>Este camino lo he probado con buenos resultados pero no puedo asegurar que te funcione ya que depende de Google pero basicamente debemos crear 20 cuentas de google, este camino es un poco trabajoso ya que cada cuenta debe estar asociado a un numero de telefono y este solo puede tener 4 cuentas asociadas, por lo que se debera conseguir varias lineas para poder crearlas.</p><p>Una vez creadas se deben agregar en el canal de prueba interna y mediante el link de invitacion web se puede ir iniciando sesion en cada una e ir uniendo manualmente a la prueba interna.</p><p>No es necesario logearlos en un telefono ni instala la aplicación.</p><p>En mi caso no hubo pruebas diarias con estos usuarios solo se crearon las cuentas y unieron a la prueba interna.</p><blockquote>A mi parecer Google no valida si se prueba la app realmente solo es un bache que ponene en el camino para asegurarse que la app sea revisada previa a su lanzamiento, pero solo es mi conjetura, no tengo forma de validarlo.</blockquote><p>No obstante seria buena idea que te unas con tu telefono y pruebes la app desde la prueba interna para comprobar como funciona tu apliación descargada del store.</p><h3>3. Esperar</h3><p>Una vez conseguida la cantidad de testers debemos esperar 14 dias.</p><p>Al pasar los dias el texto ira cambiando y nos indicaran cuantos faltan.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EiPBRGMisbht0QB1K69SfQ.jpeg" /></figure><h3>4. 14 dias</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9w-YFKwOjI3tSPf4dW8MdA.png" /></figure><p>Al llegar a esta fecha se cumplio el tiempo requerido por google play y se habilitara el boton <strong>“Solicitar acceso a producción”.</strong></p><p>Si no se te habilita verifica si tienes los permisos necesarios, en mi caso solo el owner de la cuenta tenia la opción habilitada.</p><h3>5. Formularios</h3><p>Nos solicitara información sobre como fue este proceso y que feedback nos dieron los testers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zw_0Bk-4mBCfgsEPMLaEyA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9WO5BxuQ2UVW5jyG4MQxbw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MAuJlleZt7u_aFxUyBrk2A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*90BTnbhulJ1IBUgjXRtzcw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sFRd8MgawfqCgE3QHq1Mdw.png" /></figure><p>Una vez completado todo esto la app quedara en review.</p><h3>6. Acceso a producción otorgado.</h3><p>Si todo fue bien recibiras un mail de este tipo</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/883/1*SHXju8PygsKIXlXtILmfnQ.png" /></figure><p>En este punto ya podemos realizar el lanzamiento de nuestra app</p><h3>Duración de esta etapa:</h3><p>Lamentablemente esta nueva politica introducida por Google nos impone 14 dias para realizar el lanzamiento, por lo que los tiempos serian</p><p>14 dias pruebas cerrada</p><p><strong>7</strong> dias como maximo puede tardar la revision de nuestra etapa de pruebas.</p><p>En mi caso tardo <strong>1</strong> dia.</p><p>Review del build en Google Play, tardo <strong>1</strong> dia en mi caso.</p><p>En resumen lanzar nuestra app nos llevara mas de 20 dias, en mi caso fueron 22.</p><p>Recomiendo ni bien se tenga un MVP muy basico subirla a Google play para ir ganando tiempo.</p><p>Tengan presente que anteriormente solo tardaba alrededor de 7 dias Google play en revision para lanzar una app.</p><h3>Conclusión:</h3><p>El nuevo proceso complica el lanzamiento de una app de forma considerable pero sigue siendo posible realizarlo.</p><p>Hay que tener presente los tiempos y comunicarlos en casos de desarrollos para terceros.</p><p>Esperemos que Google revise estas nuevas politicas, las revierta o le de la facilidad a los devs indie de poder cumplirlas de manera mas facil.</p><p>Espero que te haya servido y cualquier consulta te invito a que la dejes en la caja de comentarios y vere si puedo resolvertela.</p><p>Gracias!</p><p>Saludos, Sebastian</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8cc315f4d0f1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Navegación desacoplada en Android mediante DeepLinks.]]></title>
            <link>https://medium.com/@sebastiancipolat/navegaci%C3%B3n-desacoplada-mediante-deeplinks-en-android-ecf9e28bb797?source=rss-176d4152a94b------2</link>
            <guid isPermaLink="false">https://medium.com/p/ecf9e28bb797</guid>
            <category><![CDATA[androiddev]]></category>
            <category><![CDATA[navigation]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[deeplink]]></category>
            <dc:creator><![CDATA[Sebastian Cipolat]]></dc:creator>
            <pubDate>Mon, 18 Jul 2022 00:17:14 GMT</pubDate>
            <atom:updated>2022-07-20T02:04:56.560Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/341/1*qQ_s005fT0m1Gr7hY4bfBA.png" /></figure><p>Una practica habitual en el mundo del desarrollo mobile es preestablecer la navegación de los flujos de una app en el codigo. Esto puede bastar en un proyecto simple con casos de usos muy chicos, pero en apps grandes no escala ya que para modificar un flujo es necesario subir un nuevo update.</p><p>Pensemos este escenario uno de los flujo de nuestra app consta de 3 pantallas en donde al realizar una acción avanzamos en el flujo, en cada una de estas hay una consulta al backend y este al respondernos pasamos a la que le sigue.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/416/1*dZil-X_Ue39XcgPmRJg_Zg.png" /></figure><p>Supongamos que el dia de mañana se nos indica que la pantalla 2 ya no es necesaria mostrarla y debemos quitarla del flujo.</p><h4><strong>¿Como harías para dejar de mostrar una pantalla en producción?</strong></h4><p>Este es un caso complicado debido a que la app recibir el status code 200 navegara a la siguiente pantalla ya que esta prefijo su comportamiento en el código.</p><p>A lo largo de mi carrera he visto varios intentos de resolverlo uno fue mapear diferentes status al response del back y este asociarlo a una pantalla, pero no escala ya que debe mapearse todos los estados posibles lo que complica la parte backend también. Otra forma es leer del response algún elemento del json que usemos como identificador y realizar alguna acción, sigue sin ser la mejor forma.</p><p>Para poder dar solución a este escenario a mi parecer uno de los mejores camino es usar una feature que nos ofrece Android desde sus primeras versiones, estos son los <a href="https://developer.android.com/training/app-links/deep-linking">DeepLinks</a> ya son usados comúnmente para acceder a una app desde el exterior como una link en un post, un ad, etc, pero el uso poco conocido es que tmb pueden usarse para mapear pantallas dentro de una app y usarlos para navegar internamente.</p><blockquote>Al igual que Android esta feature también esta disponible en iOS, por lo que esta solución es compatible con ambas plataforma.</blockquote><p><strong>Ej:</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/277/1*HgE_C4jw8d8dW3lxwqi1YA.jpeg" /></figure><p>Al momento de pulsar el boton en la “pantalla 1” este realizo un request al backend al endpoint <strong>/sendform </strong>quien<strong> </strong>devolvera en alguna parte del json en el body de su response junto al status code 200 lo siguiente:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/860/1*6riOK3PEs7OR_ggronuIrQ.png" /></figure><p>En este campo “<strong>path_next_screen</strong>” se encuentra el deeplink que apunta a la proxima pantalla a mostrar <strong>“app://screen”</strong></p><p>En este caso nos enviara a la pantalla “Screen3” por lo que ya no se mostrara la pantalla intermedia.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/531/1*5RguFdxrMySFRisEht3f-Q.png" /></figure><h4>Este cambio de paradigma implicara lo siguiente:</h4><ul><li>Contemplar todos los request como correctos y solo manejar el status code 200 sin importar si la operación del usuario fue exitosa o no.</li><li>Los códigos de respuesta 500, 403, etc se continuaran usando pero solo para el caso de fallas en el back, unauthorized, etc.</li><li>La app ya no sabra a donde redirigir al user, solo manejara los códigos asociados a error en el backend (los previamentes descriptos).</li><li>La logica de navegación sera movida al backend este sera quien en base al estado del user debera saber a donde redirigirlo, lo que puede aumentar la complejidad del lado del backend.</li><li>Entender que esta flexibilidad nos ahorrara esfuerzo a futuro.</li></ul><h4>Cambios requeridos a nivel app:</h4><p>Deberemos asignar a cada pantalla involucrada un deeplink.</p><p>En el caso de una app con 3 activities el mapeo dentro del AndroidManifest.xml seria el siguiente:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aj85uWSeluB5K8_V2nA4UA.png" /></figure><p>Como veras el deeplink mapeado sera app://screen1,2,3</p><blockquote>En caso de tratarse de una app Single Activity puede hacerse algo similar mediante deeplinks usando <a href="https://developer.android.com/guide/navigation/navigation-deep-link">navigation component</a>.</blockquote><p><strong>Ejecutar navegación mediante deeplink:</strong></p><p>Ya una vez obtenido el deeplink lo unico que debemos hacer es navegar dentro de la app usandolo como base.</p><p>Ej en caso de activities.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/992/1*JBMLvxtc6FSLL8OC9Ptl9A.png" /></figure><h3><strong>Seguridad en Deeplinks:</strong></h3><p>Por defecto en Android todos los activities son públicos por lo que es una buena practica que estos solo puedan ser accedido desde nuestra app solamente, ya que de otra forma cualquiera va poder acceder, ademas si por ej en un mensaje incluyo el deeplink a nuestra pantalla podrían saltar a una parte especifica de un flujo .<br>Para bloquear estos podemos usar el atributo <a href="https://developer.android.com/guide/topics/manifest/activity-element#exported"><strong>exported</strong></a> en el AndroidManifest.xml (<a href="https://developer.android.com/about/versions/12/behavior-changes-12#exported">a partir Android 12 es obligatorio declarar su valor </a>)</p><p>También se podra agregar una validación previa a ejecutarlos para controlar que no nos saque de la app, ya que si le paso la url de otra app o una web navegara hacia estos, a su vez también la navegación debera contar con un manejo de exception por si el deeplink no existe.</p><h4>Beneficios de este nuevo enfoque:</h4><p>Este enfoque nos permite que el dia de mañana contemplar nuevos casos de uso mejorar el manejo de errores ya que si el dia de mañana hay un cambio en la logica de negocio podremos enviar al user a la pantalla de error correspondiente o en el caso de tratarse de una app modular podrias enviar al user a otro flujo.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/531/1*E1hWpW64NiGiP15G-r_pXw.png" /></figure><h3>Alimentar datos a una pantalla desde el backend:</h3><p>Un deeplink es basicamente una uri al que aplican los mismos conceptos que en web por lo que podemos agregarle parametros y en estos incluir contenido que consuma nuestras pantallas, por lo que el back al momento de armar su reponse podría agregar un objeto json el cual nos brindara el contenido</p><p><strong>EJ:</strong></p><p>Al deeplink de la pantalla 1 le agregamos parametria mediante el param ?json</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/776/1*RJYzJFTp-QTQaBTgX-T_gg.png" /></figure><p>Para poder ser interpretada esta debe estar encodeada en formate HTML, para nuestro ejemplo el response con el deeplink codificado seria:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*r3jdmGI8ahwkiyKy5nNc0g.png" /></figure><p>este fue generado con <a href="https://meyerweb.com/eric/tools/dencoder/">https://meyerweb.com/eric/tools/dencoder/</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/460/1*n3ogSeMbHrfMXri5Tq0kHA.jpeg" /></figure><p>Nuestra activity para poder recuperar los datos debería tomarlos del parametro <strong>?json</strong>, una forma de hacerlo puede ser la siguiente:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ev2jV9fxw5F6oSbzLXxK8w.png" /></figure><p>En este caso obtenemos el uri del intent que abrio el activity para extraer el parametro “json” en formato string para luego convertirlo usando la libreria <a href="https://github.com/google/gson">Gson</a>. <a href="https://mkyong.com/java/how-do-convert-java-object-to-from-json-format-gson-api/">Esta nos permite convertir un string en un objeto </a>en este caso mediante el metodo fromJson() le indicamos que debera realizarlo usando como referencia el modelo ResponseObject el cual contiene el formato del json enviado en el deeplink.</p><h3>Pros y Contras:</h3><p>Ya casi llegando al final veamos algunos pros y contras.</p><h4>Pros:</h4><ul><li>Darle flexibilidad al producto.</li><li>Navegación modificable sin necesidad de nuevos updates de la app.</li><li>Posibilidad de suministrar datos para el contenido de una pantalla desde el backend.</li><li>Muy fácil A/B Testing</li><li>Fácil implementación ya que se basa en una feature propia del SDK de Android.</li><li>Compatible con iOS.</li></ul><p><strong>Contras:</strong></p><ul><li>Al mover la logica de navegación al backend se crea una dependencia fuerte a este.</li><li>Aumenta la complejidad del backend ya que los casos de uso deberán controlarse desde este lado.</li></ul><p>Esto fue todo!</p><p>Gracias por llegar hasta aquí, espero que les haya sido util.</p><p>Hasta el proximo articulo!</p><p>Saludos</p><p>Sebastian</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ecf9e28bb797" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Monitor de Scoring App en Slack]]></title>
            <link>https://medium.com/@sebastiancipolat/monitor-de-scoring-app-en-slack-319bd5a41516?source=rss-176d4152a94b------2</link>
            <guid isPermaLink="false">https://medium.com/p/319bd5a41516</guid>
            <category><![CDATA[google-playstore]]></category>
            <category><![CDATA[marketing]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[cx]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Sebastian Cipolat]]></dc:creator>
            <pubDate>Mon, 11 Jul 2022 04:07:24 GMT</pubDate>
            <atom:updated>2022-07-12T03:04:45.405Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/225/0*mAqeOLA0I9xE4ETV.jpeg" /></figure><p>El score de una app es una de las primeras cosas que ven tus futuros usuarios en los stores. Un buen o mal puntaje influira en la decisión sobre la instalación de la app.</p><p>Esta es una metrica que puede variar muy rapido por eso es importante estar al dia siempre.</p><p>Es por este motivo que arme un pequeño script el cual al ejecutarse obtiene el score de una app de Google Playstore y la publica en un canal de slack, lo que le permita en un ambiente laboral que los diferentes sectores tengan visibilidad de esta.</p><p>Para esto cree un pequeño proyecto en node.js el cual se encuentra aqui:</p><p><a href="https://github.com/sebacipolat/app-score-monitor">GitHub - sebacipolat/app-score-monitor</a></p><p>Este utiliza la libreia<a href="https://github.com/facundoolano/google-play-scraper"> google-play-scraper</a> para extraer los datos del Google PlayStore mediante un scrapping ya que no existe un api oficial que proporcione esta información.</p><p>Al momento de ejecutar el codigo lo primero que realizara es leer un archivo de texto “last_score.txt” del cual extraera el ultimo puntaje guardado en caso de no existir creara el archivo. Luego obtendra mediante dicha libreria el score de la app y lo guardara en el archivo de texto, con el score obtenido realizara un analisis y enviara un mensaje de slack.</p><h3><strong>Estado contemplados.</strong></h3><h4><strong>Scoring muy bajo:</strong></h4><p>Si el puntaje es menor a 4.0 (puede modficarse en el file notifier.js)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/471/1*xfX6rhaeZ_ptAM5GRFa5Hw.png" /></figure><p><strong>El scoring en subida:</strong></p><p>El score de la app subio respecto de la ultima ejecución.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/420/1*Fs9XJyLhaC49e_pTcYvB8w.png" /></figure><p><strong>El scoring en bajada:</strong></p><p>El score de la app bajo respecto de la ultima ejecución.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/429/1*Pin0dwnv0Je3BzKF6ptsnw.png" /></figure><p><strong>Scoring Actual:</strong></p><p>El score de la app no vario respecto de la ultima ejecución.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/424/1*CkLYVvzwmWqUfmktALh_ug.png" /></figure><h4><strong>Botones:</strong></h4><p><strong>App</strong> te llevara a la ficha de la app en Google Playstore</p><p><strong>Score Historial </strong>Deberas definir la url de la sección Estadisticas de tu Play Console,para poder hacerlo deberas editar los archivos dentro de la carpeta ‘<em>slack_blocks</em>’</p><h3><strong>¿Como ejecutar el script?</strong></h3><p>Para poder ejecutarlo debemos setear las siguientes variables de entorno:</p><p><strong>PACKAGE_ID: </strong>Es el nombre del paquete que identifica a la app</p><p>Ejemplo para mi app Anotadroid (una de mis primeras apps)</p><p><a href="https://play.google.com/store/apps/details?id=cipolat.Anotadroid">https://play.google.com/store/apps/details?id=cipolat.Anotadroid</a></p><p>el package id seria: cipolat.Anotadroid</p><p><strong>COUNTRY_ID:</strong></p><p>La libreria requiere el codigo del pais</p><ul><li>country (optional, defaults to &#39;us&#39;): the two letter country code used to retrieve the applications. Needed when the app is available only in some countries. <a href="https://www.iso.org/obp/ui/#search">https://www.iso.org/obp/ui/#search</a></li></ul><p>Ejemplo:</p><p>Argentina= ar</p><p>USA= us</p><p><strong>SLACK_WEBHOOK: </strong>Webhook de Slack al canal donde se enviara el mensaje</p><h4><strong>Instalar dependencias:</strong></h4><p>npm install</p><h4><strong>Run:</strong></h4><p>node app.js</p><p>Veremos lo siguiente:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/385/1*_3N2WkH8_axGzmUK2OrS8g.png" /></figure><h3>Ejecución en CI:</h3><p>Este script es ideal para setear en un workflow de un CI y establecer que se ejecute mediante una tarea programada al inicio del dia por ejemplo.</p><p>Debe tenerse en cuenta lo siguiente:</p><p>Clonar este proyecto en un repositorio interno.</p><p>Configura variables de entorno.</p><p>Luego de la ejecución del script debe pushearse al repositorio donde el archivo “last_score.txt”</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=319bd5a41516" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Guia rapida para dashboard de versiones en app modulares]]></title>
            <link>https://medium.com/@sebastiancipolat/guia-rapida-para-dashboard-de-versiones-en-app-modulares-51cc7c878df?source=rss-176d4152a94b------2</link>
            <guid isPermaLink="false">https://medium.com/p/51cc7c878df</guid>
            <category><![CDATA[mobile-devops]]></category>
            <category><![CDATA[ci]]></category>
            <category><![CDATA[andriod-app-development]]></category>
            <category><![CDATA[android-modular-app]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Sebastian Cipolat]]></dc:creator>
            <pubDate>Mon, 13 Dec 2021 12:02:41 GMT</pubDate>
            <atom:updated>2021-12-13T14:49:09.307Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*-w71YOTA1ObSWbkDVcd3dA.jpeg" /></figure><p>En el mundo de las aplicaciones móviles las aplicaciones modulares son cada vez mas populares y el camino a tomar para todo proyecto que va escalar e ira mas alla de una app pequeña.</p><p>En mi caso me especializo en el desarrollo de apps Android por lo que esta guia estara orientado a esa tecnologia.</p><p>Al trabajar con modulos es muy común utilizar herramientas como maven en donde se publicaran las diversas versiones.</p><p>Es muy importante poder saber cuales son las ultimas versiones liberadas para poder estar siempre al dia. Si utilizas algunas herramienta como jfrog no sera posible utilizar el badge de version como si podríamos hacerlo con maven publico.</p><p>Para poder resolver esto se me ocurrió una solución muy simple y rapida.</p><p>Esta consiste en inlcuir a la task de nuestro CI que sube las versiones un script que actualice en un repositorio un archivo html y luego cada vez que se lo modifica se publique en gitlab pages.</p><p>Nuestro dashboard al finalizar se vera de la siguiente forma</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/399/1*MfUAWAIV-1MYq_sEp4C_7A.png" /></figure><h3><strong>Manos a la obra:</strong></h3><p><strong>1-</strong> Lo primero que debemos hacer es crear un repositorio, ej. version-status</p><p><strong>2- </strong>Podemos crear un simple archivo html con el siguiente contenido:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ccb71e42e48a4a472eb1db3f4c2846f0/href">https://medium.com/media/ccb71e42e48a4a472eb1db3f4c2846f0/href</a></iframe><p>En este pondremos el nombre de todos los modulos y la url con el badge y su version.</p><p>Para los badges usaremos <a href="https://shields.io/">https://shields.io/</a> el cual nos permite generar un badge con la parametria enviada en la url</p><p>Ej: En este caso un modulo se llama player y la ver es la 4.0.1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5517fd68901b7f8c8c8db6fd35889ada/href">https://medium.com/media/5517fd68901b7f8c8c8db6fd35889ada/href</a></iframe><p>Su apariencia sera la siguiente:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/193/1*JvqD0vAd4YyFN_I8hpbuOw.png" /></figure><p><strong>3-</strong> Debemos asegurarnos que todos los pipeline que suban versiones en el CI puedan tener acceso a este.</p><p><strong>4-</strong> En la tarea de nuestro pipeline que genera el release del modulo debemos poder contar con las siguientes variables de entorno:</p><p>“<strong>$MODULE”</strong> Nombre del modulo, esta puede estar prefija por nosotros al momento de configurar el pipeline o ser obtenida de alguna forma</p><p>“$<strong>VERSION”</strong> hace referencia a la version que acabamos de generar.</p><p>Para poder obtener la version de un .aar podemos obtenerla del manifest</p><p>ej:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/787/1*WGyYCWK2OvgOPDKLR86f_A.png" /></figure><p>En mi caso utilizo Bitrise con una imagen de Linux Ubunut quien nos proporciona un plugin que extrae esta información y las disponibiliza como variables de entorno</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/805/1*BYxTbltTmV_PvpFbfwZnqw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*stePu-Y65zkYFxdwRm1vZg.png" /></figure><p>A este plugin debemos decirle cual es el path del AndroidManifest.xml resultante del proceso de release final:</p><p>En mi caso es:</p><p><strong>“./$MODULE/build/intermediates/aapt_friendly_merged_manifests/release/aapt/AndroidManifest.xml”</strong></p><pre>- android-manifest-info@1.0:<br>    inputs:<br>       - manifest_file: &quot;./$MODULE/build/intermediates/aapt_friendly_merged_manifests/release/aapt/AndroidManifest.xml&quot;</pre><p>Usando esta tool la variable $VERSION seria reemplazada por $AMI_VERSION_CODE</p><p>En caso de no utilizar bitrise podrás obtener esta info leyendo el archivo directamente.</p><p>Como hacerlo desde bash: <a href="https://stackoverflow.com/questions/17333755/extract-xml-value-in-bash-script">https://stackoverflow.com/questions/17333755/extract-xml-value-in-bash-script</a></p><p><strong>5-</strong></p><p>Luego deberas cargar el siguiente script posterior al momento de la subida del modulo.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/09bae444ed348835bda135ffc7b1bafc/href">https://medium.com/media/09bae444ed348835bda135ffc7b1bafc/href</a></iframe><p>Explico cada linea</p><blockquote>git clone git@gitlab.com:nx/app/version-modules.git</blockquote><p>Clona el repositorio y descarga los archivos</p><blockquote>cd ‘version-modules’</blockquote><p>cambia a la carpeta clonada recientemente</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e088c867d167e8372913e02d11fd4911/href">https://medium.com/media/e088c867d167e8372913e02d11fd4911/href</a></iframe><p>Busca dentro del archivo last_version.html si existe la sección</p><blockquote>search=”&lt;tr&gt;&lt;td&gt;&lt;strong&gt;$MODULE&lt;/strong&gt;&lt;/td&gt;”</blockquote><p>si nuestro modulo se llama player al momento de buscar, encontrara la primera row de la tabla</p><blockquote>&lt;tr&gt;&lt;td&gt;&lt;strong&gt;player&lt;/strong&gt;&lt;/td&gt;</blockquote><p>Mediante grep busca dentro del archivo si existe una row con ese contenido en caso de existir ejecutara el comando <strong>sed</strong> buscara linea donde se encuentre la coincidencia y la reemplazara con la linea completa.</p><blockquote>sed -i “/$MODULE/c\&lt;tr&gt;&lt;td&gt;&lt;strong&gt;$MODULE&lt;/strong&gt;&lt;/td&gt;&lt;td style=’text-align: center;’&gt;&lt;img src=’https://img.shields.io/badge/version-$VERSION-brightgreen&#39;/&gt;&lt;/td&gt;&lt;/tr&gt;&quot; $FILE</blockquote><p>En caso de no encontrar la linea en el archivo la agregara, por lo que el script permitira que nuevos modulos puedan irse incorporando sin necesidad de modificar manualmente el archivo</p><p>Luego commitea y realiza un push del cambio.</p><p><strong>6-</strong></p><p><strong>Agregar Gitlab Page</strong></p><p>Nuestro repositorio necesitara tener activado esta feature.</p><p>Cada vez que se pushe un archivo queremos que se actualice la Gitlab Page por lo que crearemos el archivo <a href="https://gitlab.naranja.dev/nx/core-mobile/android/version-modules/blob/master/.gitlab-ci.yml"><strong>gitlab-ci.yml</strong></a></p><pre>pages:<br>  stage: deploy<br>  script:<br>  - mkdir .public<br>  - cp -r * .public<br>  - mv .public public<br>  artifacts:<br>    paths:<br>    - public<br>  only:</pre><pre>  - main</pre><p>Veremos que corre el pipeline cada vez que se corre el script.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/639/1*7aOqxLm6J1mFjYSTV0gbBQ.png" /></figure><p>Ahora solo deberias acceder a tu gitlab page, para ver la url debers ir a</p><p>Settings-&gt;Pages</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E6MlfsfUPBzhMeF03OqE_w.png" /></figure><p>En mi caso es <a href="https://scipolat.gitlab.io/last-version-badges">https://scipolat.gitlab.io/last-version-badges</a></p><p>per la url completa seria:</p><p><a href="https://scipolat.gitlab.io/last-version-badges/last_version.html">https://scipolat.gitlab.io/last-version-badges/last_version.html</a></p><p>Si deseas modificar la privacidad de la gitlab page puedes hacerlo en</p><p>Settings-&gt;General</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/517/1*hldgZF8Kqb2tDCCD7Eqhxg.png" /></figure><p>Espero que este contenido te haya sido util.</p><p>Hasta la proxima!</p><p>Sebastian</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=51cc7c878df" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Automatiza tus Code Review]]></title>
            <link>https://medium.com/@sebastiancipolat/automatiza-y-trollea-tus-codes-review-con-danger-ae5853cebd1a?source=rss-176d4152a94b------2</link>
            <guid isPermaLink="false">https://medium.com/p/ae5853cebd1a</guid>
            <category><![CDATA[androiddev]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[code-review]]></category>
            <category><![CDATA[hacker]]></category>
            <dc:creator><![CDATA[Sebastian Cipolat]]></dc:creator>
            <pubDate>Tue, 14 Sep 2021 01:17:19 GMT</pubDate>
            <atom:updated>2024-02-02T16:08:49.086Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/961/1*bz8OkoNf7Dots-IMTTukqA.png" /></figure><p>Hola en el último tiempo estuve buscando formas de mejorar los code review y me tope con una tool muy interesante llamada <a href="https://danger.systems/ruby/">Danger</a></p><p>Danger es una herramienta basada en ruby que nos permite automatizar las tareas habituales de revisión de código mediante el envío de mensajes en los PR, esta debe ser incluida dentro del proceso de build en tu CI. al crear tus propias reglas para tu equipo puedes desligar tareas habituales para concentrarte en problemas más difíciles,tambien podras reforzar la cultura de pull request.</p><p>En este artículo veremos cómo integrar danger usando Gitlab + Bitrise</p><h3><strong>Setup:</strong></h3><p>La forma más fácil de instalar Danger es mediante Bundler.</p><p>Bundler es un administrador de dependencias para Ruby que usa un Gemfile para definir todos los proyectos de Ruby que desea usar.</p><p>Abre la consola:</p><p>Primero deberías revisar si tiene instalados gem y bundler.</p><p>Deberás ejecutar</p><pre>gem install bundler</pre><p>Luego tendrás que crear un gemfile</p><pre>bundler init</pre><p>Modfica el archivo con lo siguiente</p><pre>source &quot;https://rubygems.org&quot;</pre><pre>git_source(<em>:github</em>) { |repo_name| &quot;https://github.com/#{repo_name}&quot; }</pre><pre>gem &#39;danger-gitlab&#39;</pre><p>En nuestro caso usaremos danger-gitlab el cual esta pensado para poder ser usado en Gitlab, en caso que queramos usar Github habría que usar</p><pre>gem ‘danger’</pre><p>Luego instala las dependencias y valida la versión</p><pre>bundle install<br>bundle exec danger --version</pre><p>En este punto ya puedes crear tu dangerfile y empezar a escribir tus propias reglas.</p><h3><strong>Creando DangerFile</strong></h3><p>Ingresa en la terminal</p><pre>bundle exec danger init</pre><p>Te guiará a través de 4 pasos, en el que te proporcionará algunasreglas por default, y demás configuraciones para utilizar en tu repositorio y CI</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/804/0*dY98YQiiHb-h86p6" /></figure><p>Puede ejecutarlo para que cree el dangerfile.</p><p>En unos momentos veremos mas en profundidad este archivo y las reglas que puedes usar, pero llegó el momento de mostrarte cómo configurarlo en Bitrise.</p><h3><strong>Bitrise:</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/369/0*UnNUgnsdLOKVLNZj" /></figure><p>Hace un tiempo que ya vengo trabajando con esta herramienta y es uno de los CI cloud más fáciles y pensados para mobile.</p><p><strong>1- Alta de proyecto:</strong></p><p>No voy a explicar como dar de alta una app Android ya que se va del scope de este artículo, pero en el siguiente link veras como hacerlo de forma fácil.</p><p><a href="https://devcenter.bitrise.io/getting-started/getting-started-with-android-apps/">https://devcenter.bitrise.io/getting-started/getting-started-with-android-apps/</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/948/0*QexVWS6qQxvT1_ON" /></figure><p>Una vez que tu pipeline se ejecute correctamente, podemos pasar al siguiente paso.</p><p><strong>2- Definir variables</strong></p><p>Tendremos que definir algunas variables de entorno que utilizaremosen la configuración.</p><p>Necesitaremos dar de alta un access token en Gitlab que nos permitaacceder a nuestro repositorio, asegurate ponerle permisossuficientes para poder realizar comentarios.</p><p>Puede ser buena idea que crees una cuenta especial para danger.</p><p>Referencia: https://danger.systems/guides/getting_started.html</p><p>Ahora si abre el workflow de tu proyecto en Bitrise y ve a la seccion</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/965/0*5OmbxKlhv19CRrEo" /></figure><p>Ingresa las siguientes:</p><p><strong>DANGER_GITLAB_API_TOKEN </strong>token de acceso al repositorio</p><p><strong>DANGER_GITLAB_HOST </strong>Host donde esta corriendo gitlab</p><p>ej gitlab.com (solo el nombre del dominio no incluir http o https)</p><p><strong>DANGER_GITLAB_API_BASE_URL </strong>Url de GitLab Api.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/707/0*_MVdSi9Op9uTnXnb" /></figure><h3><strong>Ejecutar danger en tu pipeline:</strong></h3><p><strong>Dirigite a la sección</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/172/0*CHysfqQqI3PF3Fqj" /></figure><p>Luego en alguna parte del workflow deberas agregar un bloque de script</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/368/0*r4__Jgky08sqR2pa" /><figcaption>c</figcaption></figure><h4><strong>Script:</strong></h4><pre>- script@1:<br>   run_if: &quot;.IsPR&quot;<br>   inputs:<br>   - content: |-<br>       #!/bin/bash<br>       set -ex<br>       if [ -f &#39;Dangerfile&#39; ] ; then<br>       bundle install<br>       # Running Danger<br>       bundle exec danger --fail-on-errors=true<br>       fi</pre><p>El siguiente script ejecutará danger solamente cuando se trate de un Pull request y el Dangerfile exista, al agregar <em>— fail-on-errors=true</em> el pipeline fallara, lo veremos mas adelante</p><p><a href="https://danger.systems/guides/getting_started.html#including-danger">Getting Set Up</a></p><h3><strong>Conociendo el DangerFile:</strong></h3><p>En este archivo es donde haremos nuestras reglas que nos permitirán acceder al contenido del pull request y en base a este poder dejar comentarios, fallar el pipeline, leer reportes de test xml, etc.</p><p>Como te comente danger está desarrollada en Ruby por lo que este archivo estará escrito en este lenguaje pero existen diversidad de plugins que te permitirán kotlin, swift, javascript.</p><p><a href="https://github.com/danger/awesome-danger">https://github.com/danger/awesome-danger</a></p><p>En nuestro caso usaremos ruby.</p><p>Existen 3 tipos de mensajes que puedes incluir en un comentario.</p><p>Aquí te dejo un ejemplo de cómo se verían dentro del danger file y en el repositorio.</p><p><strong>fail</strong> “Por favor incluye un resumen detallado a tu Merge Request. Puedes usar de guía el template configurado en tu repositorio.”</p><p><strong>warn</strong> “:construction_worker: Happy coding [WIP]”</p><p><strong>message</strong> “Gracias por tu pull request! :+1:”</p><p>En el repositorio lo veias asi:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/850/0*aM0pwqiDbCio6yLs" /></figure><p>El plugin Danger Gitlab nos dejará acceder a diversos elementos pull request:</p><p>tales como el título, cuerpo del repositorio, listado de archivos incluidos, etc.</p><p>En el siguiente link podras ver mas información y algunos ejemplos:</p><p><a href="https://www.rubydoc.info/gems/danger/3.4.1/Danger/DangerfileGitLabPlugin">https://www.rubydoc.info/gems/danger/3.4.1/Danger/DangerfileGitLabPlugin</a></p><h3><strong>Ejemplos:</strong></h3><p>Supongamos que quieres automatizar algunas reglas que todo pull request deba cumplir y si no lo hacentrollearlos mediante un meme con un comentario de aviso.</p><h4><strong>Validar demasiados cambios:</strong></h4><pre>#Pull Request demasido grande</pre><pre>if git.lines_of_code.length &gt;35</pre><pre>warn “&lt;img src=’https://i.pinimg.com/564x/3e/90/0f/3e900f828399313ad142fd1ea25486f3.jpg&#39; width=’140&#39;/&gt;</pre><pre>:monkey_face: Parece que tu pull request es demasiado grande, tal vez puedas dividirlo en otros mas pequeños.”</pre><pre>end</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/896/0*S4EtIvm7e5Tr7Ta7" /></figure><p>Programáticamente válida si la cantidad de líneas incluidas supera a 35</p><p><strong>“if git.lines_of_code.length &gt;35”</strong></p><p>Cuando se cumpla esa condición incluirá un comentario del tipo</p><p><strong>warn</strong> con una imagen y texto.</p><h4><strong>Ticket de jira incluido en la descripción:</strong></h4><pre>#Validar si incluyo ticket de jira en la descripción</pre><pre>if !gitlab.mr_body.include? &quot;jira&quot;</pre><pre>warn &quot;&lt;img src=&#39;https://pics.me.me/thumb_what-ifitold-you-no-jira-%3Eno-merge-meme-creator-funny-50240445.png</pre><pre>width=&#39;200&#39;/&gt;</pre><pre>:pizza: Seria genial si puede incluir el ticket de Jira asociado a este cambio.&quot;</pre><pre>end</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/654/0*iGp0gscBsKXSokH6" /></figure><p><strong>if !gitlab.mr_body.include? “jira”</strong></p><p><strong>Válida si dentro del body de la descripción del PR no se encuentra la palabra “jira”</strong></p><p>En caso afirmativo mostrará un meme y un aviso.</p><h4><strong>Fallar pipeline</strong></h4><p>Puedes hacer fallar un pipeline mediante el uso de “<strong>fail</strong>”</p><p>y al momento de iniciar danger incluir el siguiente parametro</p><pre><em> — fail-on-errors=true</em></pre><h4><strong>Ej:</strong></h4><h4><strong>Fallar pipeline cuando el contenido es poco.</strong></h4><pre>if gitlab.mr_body.length &lt; 5</pre><pre>fail “:pencil:Por favor incluye un resumen detallado a tu Merge Request.</pre><pre>Puedes usar de guia el template configurado en tu repositorio.”</pre><pre>end</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/659/0*28pIdssklNDD23WD" /></figure><h4><strong>Presencia de unit test?</strong></h4><p>Validamos si en tu pull request modificaste código Kotlin pero no incluiste su test unitario.</p><pre>#Detecta cuando hubo un cambio en un archivo *.kt pero no se incluyeron test unitarios.</pre><pre>modified_test = git.modified_files.select { |path| path.include? “test/” }</pre><pre>if git.modified_files.include? “*.kt” &amp;&amp; modified_test.empty?</pre><pre>warn “&lt;img src=’https://memegenerator.net/img/instances/75590953/unit-tests-cant-fail-if-there-are-no-unit-tests.jpg&#39; width=’200&#39;/&gt;</pre><pre>:exclamation: No olvides incluir los test unitarios!”</pre><pre>end</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/484/0*OhbKms3_YD7nPyd9" /></figure><p><strong>modified_test = git.modified_files.select { |path| path.include? “test/” }</strong></p><p>Obtiene listado de archivos que incluyan en su path la carpeta de test unitarios de android.</p><p><strong>“if git.modified_files.include? “*.kt” &amp;&amp; modified_test.empty?”</strong></p><p>Si en los archivos modificados hay uno terminado en *.kt pero no haya test enviará un meme y el mensaje de error.</p><h3><strong>Ejecutar Dangerfile Desde otro repositorio</strong></h3><p>Seguramente querrás centralizar tus rules en un solo lugar y poder consumirlo desde otros repositorios.</p><p>Para poder hacerlo estos deberás crear un repositorio en donde alojar el Dangerfile</p><p>Supongamos que el repo se llama:</p><p><a href="https://gitlab.com/user/dangerrepo">https://gitlab.com/user/dangerrepo</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/302/0*hEmWVPd_jL6ztJjB" /></figure><p>Este se encuentre dentro de una carpeta rules en el branch main</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/243/0*YcmF7RlqVrdmqsdB" /></figure><p>Dentro del proyecto de tu aplicacion deberas tener un Dangerfile</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/332/0*u0RnM03p09_PbVs8" /></figure><p>Dentro debera incluir lo siguiente:</p><p><strong>Ejemplo:</strong></p><pre>danger.import_dangerfile( gitlab: 29385092 , branch: “main” , path:”rules/Dangerfile” )</pre><p>Listo de esta forma cuando corra tu pipeline obtendra las rules de un unico lugar.</p><p>En resumen:</p><p>Danger nos permite enfocarnos en las tareas importante y dejar validaciones triviales a una maquina, al poder hacer tus propias reglas existen infinitas posibilidades.</p><p>Esto fue todo por hoy, en futuros articulos veremos como integrar los reportes del lint de android y llevar tus code review a otro nivel.</p><h3>Gracias <strong>por</strong> tu tiempo!</h3><h4>Si te gusto mi contenido te invito a que me sigas!</h4><h3><strong>Fuentes:</strong></h3><p><a href="https://git.panter.ch/open-source/danger-rules">https://git.panter.ch/open-source/danger-rules</a></p><p><a href="https://www.wearemobilefirst.com/blog/how-to-automate-the-android-code-review-process-using-danger">https://www.wearemobilefirst.com/blog/how-to-automate-the-android-code-review-process-using-danger</a></p><p><a href="https://blog.bitrise.io/post/danger-danger-uh-that-is-using-danger-with-bitrise">https://blog.bitrise.io/post/danger-danger-uh-that-is-using-danger-with-bitrise</a></p><p><a href="https://danger.systems/guides/getting_started.html#including-danger">https://danger.systems/guides/getting_started.html#including-danger</a></p><p><a href="https://blog.bitrise.io/post/automating-code-review-tasks-for-multi-module-android-projects">https://blog.bitrise.io/post/automating-code-review-tasks-for-multi-module-android-projects</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ae5853cebd1a" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>