- 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.