Retrieving an artifact from a previous GitHub Actions workflow

While configuring some end-to-end tests with Playwright, I wanted to achieve a visual comparison between the current run and the previous one.

Playwright expects to have a snapshot available for its comparison. When I run this on GitHub Actions, the snapshots should be taken from my previous GitHub Actions workflow run. Unfortunately, the download artifacts action only allows you to download artifacts from the current workflow run.

To overcome this, I made a GitHub script that finds the previous successful run and downloads my snapshots.

Scripting

To download the artifact, I used the GitHub Script action.

The code of the script action looks as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
module.exports = async ({
  github,
  context,
  core
}) => {
  const owner = context.repo.owner;
  const repo = context.repo.repo;

  const workflows = await github.rest.actions.listRepoWorkflows({
    owner,
    repo
  })

  const workflow = workflows.data.workflows.find(w => w.path.includes(process.env.WORKFLOW_FILENAME));

  if (!workflow) {
    core.setFailed("No workflow found");
    return;
  }

  const runs = await github.rest.actions.listWorkflowRuns({
    owner,
    repo,
    workflow_id: workflow.id,
    status: "success",
    per_page: 1
  })

  if (runs.data.total_count === 0) {
    core.setFailed("No runs found");
    return;
  }

  const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
    owner,
    repo,
    run_id: runs.data.workflow_runs[0].id
  });

  const artifact = artifacts.data.artifacts.find(artifact => artifact.name === process.env.ARTIFACT_NAME);
  if (artifact) {
    const response = await github.rest.actions.downloadArtifact({
      owner,
      repo,
      artifact_id: artifact.id,
      archive_format: 'zip'
    });
    require('fs').writeFileSync(process.env.ARTIFACT_FILENAME, Buffer.from(response.data));
    require('child_process').execSync(`unzip -o ${process.env.ARTIFACT_FILENAME} -d ${process.env.UNZIP_DIR}`);

    console.log("Artifact downloaded successfully");
  } else {
    core.setFailed("No artifact found");
  }
}

To keep the workflow file clean, I put the above code in a separate file and configured the actions as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
- name: Download artifact
  uses: actions/github-script@v6
  continue-on-error: true
  env:
    WORKFLOW_FILENAME: testing.yml
    ARTIFACT_NAME: playwright-snapshots
    ARTIFACT_FILENAME: playwright-snapshots.zip
    UNZIP_DIR: tests
  with:
    script: |
      const script = require('./scripts/download-previous-artifact.js')
      await script({github, context, core})      

One more thing you need to do is to assign the permissions for the workflow job. By default, you will not be able to get previous workflow run information. To get this information, add actions: read to the workflow jobs.

Here is what my complete workflow looks like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
name: E2E Testing

on:
  schedule:
    - cron: "0 6 * * *"

jobs:
  testing:
    name: Start E2E Testing
    timeout-minutes: 60
    runs-on: ubuntu-latest

    # We need to make sure that we have actions read access to get the previous artifact
    permissions:
      contents: read
      actions: read
      packages: write

    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright Browsers
        run: npx playwright install --with-deps

      - name: Download artifact
        uses: actions/github-script@v6
        continue-on-error: true
        env:
          WORKFLOW_FILENAME: testing.yml
          ARTIFACT_NAME: playwright-snapshots
          ARTIFACT_FILENAME: playwright-snapshots.zip
          UNZIP_DIR: tests
        with:
          script: |
            const script = require('./scripts/download-previous-artifact.js')
            await script({github, context, core})            

      - name: Run Playwright tests
        run: npx playwright test
        continue-on-error: true

      - uses: actions/upload-artifact@v3
        if: always()
        with:
          name: playwright-snapshots
          path: tests/*-snapshots/
          retention-days: 30

Comments

Back to top