- Published on
Github Action With Sed In the Middle
- Authors
- Name
- Jason R. Stevens, CFA
- @thinkjrs
If you program or write software for a living I'm willing to bet that you use Github Acions for CI/CD.
This week I was cleaning up an old actions script that runs Google Lighthouse on web properties for work @Tincre and needed to modify a URL returned by an action step with RegEx.
Here's the setup and how I accomplished that. Hopefully it helps you move quicker and get more done!
Modifying a variable
First of all, I needed to keep this script in its current form to fit with our release schedule. I also needed to not modify any other steps, aside from variable names.
But it was failing due to a URL being changed upstream, which I needed to now modify insie the action. Let's dive into what the script does and what I did to rectify the problem.
Grab a URL from an external service
The script grabs a preview URL from Vercel when our apps build. To do so, we use the vercel-preview-url-action by aaimio.
This provides a variable we can access with steps.vercel_preview_url.outputs.vercel_preview_url in proceeding steps.
New - Modify the URL using sed
Now that URL has some cruft at the beginning and end of which we want to rid ourselves. So let's grab the varable, use echo to pipe it to sed and some RegEx to remove the cruft. After all that we'll save it to a new variable.
- name: reformat_vercel_preview_url
id: reformat_vercel_preview_url
run: |
URL=$(echo "${{ steps.vercel_preview_url.outputs.vercel_preview_url }}" | sed -E 's|^(https://)vercel\.live/open-feedback/(.*)(\?.*)$|\1\2|')
echo "::set-output name=reformatted_vercel_preview_url::$URL"
shell: bash
What's going on in the run command?
Let's break down what's happening in that run directive.
- We echo the previous URL variable, setting it to the local URL variable, only available in that Github action step. Importantly, this executes the entire command (including
sed). - We pipe
|that value to the linux utilitysed. - We use
sedto use the RegEx provided to exclude the matches, leaving only the string we'd like. - We use
echoto set a variablereformatted_vercel_preview_urlwhich we can use in the next step.
Use the modified url in the proceeding step
The proceeding step then uses the variable we set prior to send to lighthouse.
- uses: actions/checkout@v4
- name: Audit preview URL with Lighthouse
id: lighthouse_audit
uses: treosh/lighthouse-ci-action@v11
with:
urls: |
${{ steps.reformat_vercel_preview_url.outputs.reformatted_vercel_preview_url }}
uploadArtifacts: true
temporaryPublicStorage: true
The complete lighthouse.yaml script
For completeness, here's a complete Github Action script to run Google Lighthouse on your Vercel deployments in your Github Pull Requests.
name: Vercel Preview URL Lighthouse Audit
on:
issue_comment:
types: [edited]
jobs:
generate_lighthouse_audit:
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- name: Add comment to PR
id: loading_comment_to_pr
uses: marocchino/sticky-pull-request-comment@v1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
number: ${{ github.event.issue.number }}
header: lighthouse
message: |
Running Lighthouse audit...
- name: Capture Vercel preview URL
id: vercel_preview_url
uses: aaimio/vercel-preview-url-action@v2.2.0
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: reformat_vercel_preview_url
id: reformat_vercel_preview_url
run: |
URL=$(echo "${{ steps.vercel_preview_url.outputs.vercel_preview_url }}" | sed -E 's|^(https://)vercel\.live/open-feedback/(.*)(\?.*)$|\1\2|')
echo "::set-output name=reformatted_vercel_preview_url::$URL"
shell: bash
- uses: actions/checkout@v4
- name: Audit preview URL with Lighthouse
id: lighthouse_audit
uses: treosh/lighthouse-ci-action@v11
with:
urls: |
${{ steps.reformat_vercel_preview_url.outputs.reformatted_vercel_preview_url }}
uploadArtifacts: true
temporaryPublicStorage: true
- name: Format lighthouse score
id: format_lighthouse_score
uses: actions/github-script@v3
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
const result = ${{ steps.lighthouse_audit.outputs.manifest }}[0].summary
const links = ${{ steps.lighthouse_audit.outputs.links }}
const formatResult = (res) => Math.round((res * 100))
Object.keys(result).forEach(key => result[key] = formatResult(result[key]))
const score = res => res >= 90 ? '🟢' : res >= 50 ? '🟠' : '🔴'
const comment = [
`⚡️ [Lighthouse report](${Object.values(links)[0]}) for the changes in this PR:`,
'| Category | Score |',
'| --- | --- |',
`| ${score(result.performance)} Performance | ${result.performance} |`,
`| ${score(result.accessibility)} Accessibility | ${result.accessibility} |`,
`| ${score(result['best-practices'])} Best practices | ${result['best-practices']} |`,
`| ${score(result.seo)} SEO | ${result.seo} |`,
`| ${score(result.pwa)} PWA | ${result.pwa} |`,
' ',
`*Lighthouse ran on [${Object.keys(links)[0]}](${Object.keys(links)[0]})*`
].join('\n')
core.setOutput("comment", comment);
- name: Add comment to PR
id: comment_to_pr
uses: marocchino/sticky-pull-request-comment@v1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
number: ${{ github.event.issue.number }}
header: lighthouse
message: |
${{ steps.format_lighthouse_score.outputs.comment }}
I hope this helped and/or you enjoyed the write up.