- 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.
sed
New - Modify the URL using 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
run
command?
What's going on in the 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
sed
to use the RegEx provided to exclude the matches, leaving only the string we'd like. - We use
echo
to set a variablereformatted_vercel_preview_url
which 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
lighthouse.yaml
script
The complete 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.