<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Iván Valdés</title>
    <description>The latest articles on DEV Community by Iván Valdés (@ivanvc).</description>
    <link>https://dev.to/ivanvc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F526800%2Fec2dbd32-bb36-4c28-929b-c104ca2006ea.jpeg</url>
      <title>DEV Community: Iván Valdés</title>
      <link>https://dev.to/ivanvc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ivanvc"/>
    <language>en</language>
    <item>
      <title>Automating Building Android APKs with GitHub Actions</title>
      <dc:creator>Iván Valdés</dc:creator>
      <pubDate>Sun, 01 Oct 2023 20:39:47 +0000</pubDate>
      <link>https://dev.to/ivanvc/automating-building-android-apks-with-github-actions-150h</link>
      <guid>https://dev.to/ivanvc/automating-building-android-apks-with-github-actions-150h</guid>
      <description>&lt;p&gt;As part of my goal to decrease my smartphone addiction, I recently bought a Unihertz Jelly phone, which could be a good compromise between a smartphone and a dumbphone. The phone has a multi-purpose function button. You can assign it to specific pre-defined actions or launch any application. As I regularly use the phone screen in grayscale mode, I decided to assign the button to an application that would toggle this mode. I searched and couldn't find a simple app to toggle it when launching. So I decided to write my own. However, this previous background could be a post on its own.&lt;/p&gt;

&lt;p&gt;As I've been trying to leverage GitHub actions for manual tasks, I &lt;a href="https://github.com/search?q=release+apk+action&amp;amp;type=repositories"&gt;searched GitHub&lt;/a&gt; and found many actions that could do this for me. I tried with a couple of them, and they didn't work. One of the issues is that the actions are using obsolete dependencies, and I spent way more time trying to make them run than I wanted.&lt;/p&gt;

&lt;p&gt;I decided to make it work without a pre-built action and write all of the required steps in a GitHub workflow, which, in the end, was very simple. Here's the action. I will do a walk-through so you can use it in your projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release APK&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workflow will run when pushing a tag to a repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Gradle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout code&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the standard step to checkout the code. It can run with the latest &lt;code&gt;checkout&lt;/code&gt; action (v3).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;setup jdk&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt;
        &lt;span class="na"&gt;distribution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;temurin'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we need to set up the JDK. Again, using the latest &lt;code&gt;setup-java&lt;/code&gt; action (v3). I set the Java version to 17, which is the one that my Android Project uses. You can adjust the distribution, too. Refer to &lt;a href="https://github.com/actions/setup-java#usage"&gt;&lt;code&gt;setup-java&lt;/code&gt;s documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, to sign the released APK, we'll need to load the Keystore (you can read how to generate it on &lt;a href="https://developer.android.com/studio/publish/app-signing"&gt;Android's official documentation&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Load keystore&lt;/span&gt;
      &lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;echo "${{ secrets.KEYSTORE_FILE_CONTENTS }}" | base64 -d &amp;gt; keystore.jks &amp;amp;&amp;amp; \&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The secret &lt;code&gt;KEYSTORE_FILE_CONTENTS&lt;/code&gt;, contains the base64 encoded content of the keystore.jks file you generated. You can get the text for the secret by running &lt;code&gt;cat keystore.jks  | base64 -w0&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="s"&gt;cat &amp;lt;&amp;lt;EOL &amp;gt; local.properties&lt;/span&gt;
        &lt;span class="s"&gt;storeFilePath=$PWD/keystore.jks&lt;/span&gt;
        &lt;span class="s"&gt;storePassword=${{ secrets.RELEASE_STORE_PASSWORD }}&lt;/span&gt;
        &lt;span class="s"&gt;keyAlias=${{ secrets.RELEASE_KEY_ALIAS }}&lt;/span&gt;
        &lt;span class="s"&gt;keyPassword=${{ secrets.RELEASE_KEY_PASSWORD }}&lt;/span&gt;
        &lt;span class="s"&gt;EOL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rest of the secrets are the ones you entered when configuring your keystore.&lt;/p&gt;

&lt;p&gt;Next, we'll build the APK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Release APK&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew assembleRelease&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GRADLE_USER_HOME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradle-config&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And set the current directory as a safe repository, as this is a known issue with &lt;code&gt;actions/checkout@v3&lt;/code&gt;. And because we'll later use &lt;code&gt;github-cli&lt;/code&gt; to do the release, I didn't want it to complain that it couldn't read the repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set current directory as a safe repository&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git config --global --add safe.directory /github/workspace&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ButterCam/setup-github-cli@master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, release the APK and upload it to the repository's releases page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release using github cli&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh release create ${GITHUB_REF##*/} ./app/build/outputs/apk/release/**.apk&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll need to generate a token with &lt;code&gt;repo&lt;/code&gt; access for this to work. For some reason, using the default repository's &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; won't work. &lt;/p&gt;

&lt;p&gt;And here's the full YAML in case you want to copy-paste it. &lt;a href="https://github.com/ivanvc/android-grayscale-toggle/blob/main/.github/workflows/release.yml"&gt;You can also check it in my repository&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release APK&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout code&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;setup jdk&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt;
        &lt;span class="na"&gt;distribution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;temurin'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Load keystore&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;echo "${{ secrets.KEYSTORE_FILE_CONTENTS }}" | base64 -d &amp;gt; keystore.jks &amp;amp;&amp;amp; \&lt;/span&gt;
        &lt;span class="s"&gt;cat &amp;lt;&amp;lt;EOL &amp;gt; local.properties&lt;/span&gt;
        &lt;span class="s"&gt;storeFilePath=$PWD/keystore.jks&lt;/span&gt;
        &lt;span class="s"&gt;storePassword=${{ secrets.RELEASE_STORE_PASSWORD }}&lt;/span&gt;
        &lt;span class="s"&gt;keyAlias=${{ secrets.RELEASE_KEY_ALIAS }}&lt;/span&gt;
        &lt;span class="s"&gt;keyPassword=${{ secrets.RELEASE_KEY_PASSWORD }}&lt;/span&gt;
        &lt;span class="s"&gt;EOL&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Release APK&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew assembleRelease&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GRADLE_USER_HOME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradle-config&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set current directory as a safe repository&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git config --global --add safe.directory /github/workspace&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ButterCam/setup-github-cli@master&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release using github cli&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh release create ${GITHUB_REF##*/} ./app/build/outputs/apk/release/**.apk&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's still one thing that needs configuration to sign the APK properly. You'll need to edit your &lt;code&gt;app/build.gradle.kts&lt;/code&gt; file so we can feed the properties from GitHub secrets to the &lt;code&gt;assmbleRelease&lt;/code&gt; task. Kudos to &lt;a href="https://stackoverflow.com/questions/18328730/how-to-create-a-release-signed-apk-file-using-gradle/61188101#61188101"&gt;Willi Metzel's Stack Overflow answer&lt;/a&gt;. Inside &lt;code&gt;android&lt;/code&gt; in &lt;code&gt;app/build.gradle.kts&lt;/code&gt; add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;    &lt;span class="nf"&gt;signingConfigs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"release"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;properties&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"local.properties"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;storeFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"storeFilePath"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;storePassword&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"storePassword"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;keyPassword&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"keyPassword"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;keyAlias&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"keyAlias"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, add &lt;code&gt;signingConfig = signingConfigs.getByName("release")&lt;/code&gt; to &lt;code&gt;release&lt;/code&gt; inside &lt;code&gt;buildTypes&lt;/code&gt;. It should look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;   &lt;span class="nf"&gt;buildTypes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;release&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;isMinifyEnabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
            &lt;span class="nf"&gt;proguardFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;getDefaultProguardFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"proguard-android-optimize.txt"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="s"&gt;"proguard-rules.pro"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;signingConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;signingConfigs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"release"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/ivanvc/android-grayscale-toggle/blob/main/app/build.gradle.kts"&gt;See here for a complete reference to my &lt;code&gt;app/build.gradle.kts&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Credits to &lt;a href="https://github.com/r0adkll"&gt;r0adkll&lt;/a&gt; for his previous work; without it, building this would have been more difficult.&lt;/p&gt;

&lt;p&gt;You can follow me at &lt;a href="https://github.com/ivanvc"&gt;GitHub (@ivanvc)&lt;/a&gt;. And check the repository (and source code for my grayscale switching app) if you're interested.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ivanvc/android-grayscale-toggle"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X5ZxAnrN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://opengraph.githubassets.com/bdbcb8d1aae43dbf9d83e917a53a1ee933092df99d6efeab41ba5df3a02c82d8/ivanvc/android-grayscale-toggle" alt="GitHub Repo" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>githubactions</category>
      <category>automation</category>
    </item>
    <item>
      <title>Publishing Alpine Linux packages using GitHub actions</title>
      <dc:creator>Iván Valdés</dc:creator>
      <pubDate>Thu, 17 Aug 2023 18:09:57 +0000</pubDate>
      <link>https://dev.to/ivanvc/publishing-alpine-linux-packages-using-github-actions-78p</link>
      <guid>https://dev.to/ivanvc/publishing-alpine-linux-packages-using-github-actions-78p</guid>
      <description>&lt;p&gt;Not so long ago, I decided to install Alpine Linux on some compact laptops I use when I'm out and about. One of them is an 11" 2015 Macbook Air. I have often installed Linux on Macbooks, but the experience could be more optimal, as there are many issues with the firmware support, as most of the time is closed. Alpine would be an excellent fit for this old Macbook, as the RAM and CPU specs are fundamental, and any other modern OS (macOS or other Linux distribution) would make it slow and unusable.&lt;/p&gt;

&lt;p&gt;However, there were two firmware drivers that I couldn't find for this Macbook:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The wireless network card (broadcom-wl)&lt;/li&gt;
&lt;li&gt;The FaceTime HD webcam (facetimehd)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make this portable laptop something I could use when I'm not at home and to be able to work and take video calls using Zoom. I needed these two to work. So, &lt;a href="https://gitlab.alpinelinux.org/alpine/tsc/-/issues/23"&gt;with the deprecation of the non-free aports repository&lt;/a&gt;, I needed to do it from scratch if I wanted to build them. Given that the laptop has limited resources, I didn't want to create the &lt;code&gt;apk&lt;/code&gt;s on it, so I made them on my main computer and installed the packages from the &lt;code&gt;.apk&lt;/code&gt; files. This worked, but then I wanted to host the packages somewhere, so I could install them by adding a new repository.&lt;/p&gt;

&lt;p&gt;After &lt;a href="https://github.com/acj/action-abuild"&gt;searching GitHub&lt;/a&gt;, I found an action that builds the packages, but it stops there. It doesn't publish them anywhere. So, I wrote a &lt;a href="https://github.com/marketplace/actions/alpine-package-releaser"&gt;GitHub action&lt;/a&gt; to release Alpine Linux APKs to its repository page. I wanted to build an index page for the repository's packages, so I wrote &lt;a href="https://github.com/ivanvc/tpl"&gt;&lt;code&gt;tpl&lt;/code&gt;&lt;/a&gt; (interested on reading about it? &lt;a href="https://dev.to/ivanvc/bringing-go-templates-everywhere-365l"&gt;check my previous post&lt;/a&gt;) to make this easy. And this is what it looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8neh9-Mo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ei1jo52t15t6npv8uv97.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8neh9-Mo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ei1jo52t15t6npv8uv97.png" alt="GitHub pages screenshot" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given that &lt;a href="https://dev.alpinelinux.org/~clandmeter/other/forum.alpinelinux.org/forum/general-discussion/it-not-possible-install-old-version-packages.html"&gt;Alpine Linux doesn't keep previous versions of the packages&lt;/a&gt;; at work, we needed to lock some packages (i.e., Docker) to an old version. I thought this would also be an easy way to build and publish these packages.&lt;/p&gt;

&lt;p&gt;Find the documentation at the &lt;a href="https://github.com/ivanvc/abuild-releaser-action"&gt;repository&lt;/a&gt; and &lt;a href="https://github.com/marketplace/actions/alpine-package-releaser"&gt;GitHub's marketplace&lt;/a&gt;. Pull Requests and new features are welcome.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ivanvc/abuild-releaser-action"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aag5a3KO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://opengraph.githubassets.com/bdbcb8d1aae43dbf9d83e917a53a1ee933092df99d6efeab41ba5df3a02c82d8/ivanvc/abuild-releaser-action" alt="GitHub Repo" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>automation</category>
      <category>linux</category>
      <category>alpinelinux</category>
    </item>
    <item>
      <title>Bringing Go Templates everywhere</title>
      <dc:creator>Iván Valdés</dc:creator>
      <pubDate>Sat, 05 Aug 2023 06:20:42 +0000</pubDate>
      <link>https://dev.to/ivanvc/bringing-go-templates-everywhere-365l</link>
      <guid>https://dev.to/ivanvc/bringing-go-templates-everywhere-365l</guid>
      <description>&lt;p&gt;As developers, we often copy and paste code, configurations, and templates between projects. This duplication leads to tech debt and missed optimization opportunities. That's why I created &lt;a href="https://github.com/ivanvc/tpl" rel="noopener noreferrer"&gt;&lt;code&gt;tpl&lt;/code&gt;&lt;/a&gt; - a simple, flexible templating tool to help developers standardize and reuse elements across their stack.&lt;/p&gt;

&lt;p&gt;There are many instances in which I could use a &lt;em&gt;gotemplate&lt;/em&gt; to avoid a repetitive task. I searched for a simple tool (ideally a binary) that would help to achieve running &lt;em&gt;gotemplates&lt;/em&gt; in an arbitrary file (i.e., I love Helm &lt;em&gt;templating&lt;/em&gt;, but it's limited to YAML files), however, after doing a &lt;a href="https://github.com/topics/gotemplate" rel="noopener noreferrer"&gt;GitHub search&lt;/a&gt;. I couldn't find what I wanted.&lt;/p&gt;

&lt;p&gt;So, as I was working on a project that needed what I wanted. I paused that other project and decided to run a simple &lt;em&gt;gotemplate&lt;/em&gt; wrapper.&lt;/p&gt;

&lt;p&gt;Ideally, I wanted it to be not opinionated, so it supports reading input files from &lt;em&gt;stdin&lt;/em&gt;, a file, or receiving it as an argument. However, a simple &lt;em&gt;gotemplate&lt;/em&gt; with an environment would be helpful. So, it supports JSON, TOML, and YAML inputs for the environment. It tries to guess the format for the given environment, but it's also possible to force the format (in case it's wrongly parsed using another format). You can specify the environment inline as an argument, or using a file (if the first character is &lt;code&gt;@&lt;/code&gt;, similar to curl).&lt;/p&gt;

&lt;p&gt;Here are a some samples on how to use &lt;code&gt;tpl&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON environment from GitHub's API using &lt;em&gt;stdin&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;There are many instances in which I want to run a template using an external resource (i.e., an HTTP API). I could do this using bash and jq. But doing it with a &lt;em&gt;gotemplate&lt;/em&gt; is way easier. Note that, in this case, the response is a JSON array. Like other tools I tried, it doesn't break, which would, as they expected to, be a JSON object. You need to handle &lt;code&gt;.&lt;/code&gt; in the template as an array.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9271nhw8a5fbdlx57jfi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9271nhw8a5fbdlx57jfi.gif" alt="JSON example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  TOML environment building an index page using an input file
&lt;/h3&gt;

&lt;p&gt;In my recent project (see my post on &lt;a href="https://dev.to/ivanvc/publishing-alpine-linux-packages-using-github-actions-78p"&gt;Publishing Alpine Linux Packages using GitHub Actions&lt;/a&gt;), I wanted to build index page(s). So, a TOML input is an easy way to pass a list of files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60ag0h5bt4lq2bz5gwbr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60ag0h5bt4lq2bz5gwbr.gif" alt="TOML example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  YAML environment input defining a Terraform module
&lt;/h3&gt;

&lt;p&gt;I wrote &lt;a href="https://github.com/ivanvc/mleh" rel="noopener noreferrer"&gt;&lt;code&gt;mleh&lt;/code&gt;&lt;/a&gt; years ago when I was trying to generate a Helm template with a Terraform output. Of course, Helm didn't like the format, which didn't work. While &lt;code&gt;mleh&lt;/code&gt; is helpful for complex templates (i.e., it follows Helm's practices ignoring files that start with an underscore, and you can specify a &lt;code&gt;values.yaml&lt;/code&gt; file as environment), there are some instances in which I need something more straightforward.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff48b4htvl4jhn59ypf0s.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff48b4htvl4jhn59ypf0s.gif" alt="YAML example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, if you want to give &lt;code&gt;tpl&lt;/code&gt; a try, you can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install it by downloading the latest binary from its &lt;a href="https://github.com/ivanvc/tpl/releases" rel="noopener noreferrer"&gt;GitHub releases page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install it using Go:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/ivanvc/tpl@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use it with Docker:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; ivan/tpl:latest &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Or, you could use it in your &lt;code&gt;Dockerfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=ivan/tpl:latest /bin/tpl /bin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://github.com/ivanvc/tpl" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2Fbdbcb8d1aae43dbf9d83e917a53a1ee933092df99d6efeab41ba5df3a02c82d8%2Fivanvc%2Ftpl" alt="GitHub Repo"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>programming</category>
      <category>coding</category>
    </item>
  </channel>
</rss>
