Using GitHub Actions to automatically unpack a zip archive

illustrations illustrations illustrations illustrations illustrations illustrations illustrations
post-thumb

Published on 3 November 2022 by Andrew Owen (3 minutes)

I was recently working with some software that could push a zip archive of content to a Git repository. However, what I really wanted was for the contents of the archive to be pushed to the repository. So I created a GitHub Action to do that for me. I’ve covered the format of GitHub Actions before. But to recap:

  • name is what gets displayed in the actions list.
  • on sets the triggers:
    • push and pull trigger the script on push and pull requests. If you don’t specify branches, they default to main.
    • paths specifies the paths to match. In this case, the script will trigger when a zip file is pushed.
    • worklflow_dispatch enables you to manually trigger the script from the actions list.
  • jobs defines one or more named tasks, in this example unzip.
  • runs-on specifies the VM environment. If you can use Ubuntu, it’s the cheapest option with hosted runners.
  • steps can be used to invoke actions such as checkout (which fetches a copy of the repository to the VM) and to execute shell commands with name: run.
  • run with a pipe character ( | ) executes a multi-line script. Without it, a single line is executed.

And here’s the action I created:

name: extract a zip file
on:
  push:
    paths:
    - 'uploads/**.zip'
  workflow_dispatch:
    jobs:
      unzip:
        runs-on: ubuntu-latest
        permissions:
          contents: write
        steps:
          - uses: actions/checkout@v4
          - name:
            run: |
              rm -r uploads/extracted
              filename=$(basename -s .zip *.zip)
              unzip *.zip
              rm *.zip
              mv $filename temp
              mv temp/out/* .
              rm -r temp
              git config --local user.email "github-actions@users.noreply.github.com"
              git config --local user.name "github-actions"
              git add .
              git commit -m "unzip"
              git push origin main              

The script is written for the Linux command line. Let’s break it down.

rm -r css

The idea here is that the contents of the zip file should replace what is already in that particular folder of the repository. You might want to call the folder uploads. The checkout action has already been run, but it’s a good idea to clear out any known folders. The -r tag makes the action recursive.

filename=$(basename -s .zip *.zip)

    unzip *.zip
    rm .zip
    mv $filename temp

This script assumes that we don’t know the name of the zip file, but that there is only one file. It will determine the name, unzip the file to the root, remove the zip file and rename the folder containing the zip to temp.

mv temp/out/ .

    rm -r temp

In this example, the contents of the zip file are two folders deep (in the out folder). This moves the contents from the nested folder to the root, and then removes the temp folder and its contents (the empty out folder). The dot (.) represents the current working directory (where the repo was checked out on the VM).

git config user.name "github-actions@users.noreply.github.com"

    git config --local user.name "github-actions"
    git add .
    git commit -m "unzip"
    git push origin main

This part of the script pushes the changes back to the repository.

Image: Detail from The Unarchiver zip file icon. I looked for an appropriate unzip image with a Creative Commons license, but the results were not safe for work.