This article explains how to replace double quotes in string literal when replacing stuff in GitHub Actions using sed. Or rather, how to replace stuff with double quotes in it in GitHub Actions overall. Because it’s not as straightforward as one would think.
Or maybe I’m missing something obvious here?
Either way, here’s another thoughtful workaround!
Background
A while back I was setting up a pipeline to build my MAUI app, push it to the App Center and automatically offer the update to a group of testers. Setting all of this up took perhaps an hour (including signing up for App Center, which I had never done before), but I was faced with a bit of a problem: All of my builds would always get version 1.0.0 (1) (even though new versions would properly be uploaded to App Center), and that doesn’t trigger an auto-update.
Long story short, since MAUI versions don’t currently propagate from ApplicationVersion to the Platform-specific versions, you’d need to update the Android version (at least the versionCode) in the manifest manually.
But who’d want to do that? That’s a job for a robot, not a human.
GitHub Actions to the rescue!
I figured I could modify the pipeline to change the version (versionCode) in the Android manifest. But while replacing stuff using sed is quite simple, the markup for versionCode has something sed hates: double-quotes:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
package="my.package"
android:versionName="1.0.0">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
And the row with android:versionName=”1.0.0″ is exactly where I need to replace the version number – inside double quotes.
Problem
With sed, this should’ve been easy, quick, well-performing, elegant, and all the other good stuff. But it wasn’t.
My actual script (that I adapted from this one) was this:
echo 'Setting Android:versionCode (build version) to ${{ env.NEW_VERSION }} in ${{ env.MANIFEST_FILE }}'
sed -rn 's|(android:versionCode=")(.*)(")|Old: \1\2\3|p' ${{ env.MANIFEST_FILE }}
sed -i -E 's|(android:versionCode=")(.*)(")|android:versionCode="${{ env.NEW_VERSION }}"|g' ${{ env.MANIFEST_FILE }}
sed -rn 's|(android:versionCode=")(.*)(")|New: \1\2\3|p' ${{ env.MANIFEST_FILE }}
And it worked great! Except for always ignoring the double quotes.
But why?
Reason
The official, simple solution is to just escape (or “quote”) all of your weird characters, like double quotes. Depending on the operating system, which terminal or shell you’re running, and apparently a multitude of other factors, you might need to escape or double-escape (depending on how many times your literals get rendered and evaluated) your letters with one or a combination of the following letters: ` \ “
This means, that if you wanted to have this work (preserving the double quotes):
echo 'My variable has the following value: "${{ env.variable }}"!'
You’d need one of the following:
echo 'My variable has the following value: ""${{ env.variable }}""!'
echo 'My variable has the following value: \"${{ env.variable }}\"!'
echo 'My variable has the following value: \\"${{ env.variable }}\\"!'
echo 'My variable has the following value: \`"${{ env.variable }}\`"!'
echo 'My variable has the following value: `"`"${{ env.variable }}`"`"!'
… or something else altogether. But which ones to go with?
No worries! I’ve got the solution. None of these work. You need to do something else.
You could try setting the double quotes in the string variable instead. That won’t work either. Double quotes really seem to be an elusive species in the GitHub Actions world!
See, GitHub Actions seems to have a bit of a history on this. I could find discussions going back years about similar issues – and it’s no wonder, properly handling arbitrary inputs – especially scripts you need to then evaluate – is pretty darn difficult.
Solution
Ditch sed, use PowerShell.
Does this sound preposterous? Because it should!
See, sed – Stream EDitor – is an old and reliable command from the world of bearded wizards and black-and-green terminals. Sed was here before you, and sed will be here after you. Sed doesn’t care about your double quotes.
So my advice to you? Don’t care about sed. Instead, use PowerShell.
echo 'Setting Android:versionCode (build version) to ${{ env.NEW_VERSION }} in ${{ env.MANIFEST_FILE }}'
sed -rn 's|(android:versionCode=")(.*)(")|Old: \1\2\3|p' ${{ env.MANIFEST_FILE }}
(Get-Content ${{ env.MANIFEST_FILE }}) -replace '(android:versionCode=")(.*)(")', 'android:versionCode="${{ env.NEW_VERSION }}"' | Out-File ${{ env.MANIFEST_FILE }}
sed -rn 's|(android:versionCode=")(.*)(")|New: \1\2\3|p' ${{ env.MANIFEST_FILE }}
And that – it works like a charm. You can still pretend like you used sed – just like I did – by leaving it to check for the value before and after the replacement – but let PowerShell actually do the heavy lifting.
Brilliant? No. Does it work? Yes.
I welcome you to leave your opinion (or a better solution) in the comments section below! 😄
References
- “Performing cleanup” – Excel is stuck with an old, conflicted file and will never recover. - November 12, 2024
- How to add multiple app URIs for your Entra app registration? - November 5, 2024
- How to access Environment Secrets with GitHub Actions? - October 29, 2024