Using GitHub Actions to automatically unpack a zip archive
Tags: git, automation, devops, cicd
Published: 2022-12-19 18:19:37

> This article originally appeared on my personal dev blog: [Byte High, No Limit](https://andrewowen.net/blog/).

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:

```yaml
name: extract a zip file

    on:
      push:
        paths:
        - '**.zip'
      workflow_dispatch:
    
    jobs:
      unzip:
        runs-on: ubuntu-latest
    
        steps:
          - uses: actions/checkout@v2
    
          - name:
            run: |
              rm -r css
              rm -r en
              rm -r fonts
              rm -r js
              filename=$(basename -s .zip *.zip)
              unzip *.zip
              rm *.zip
              mv $filename temp
              mv temp/out/* .
              rm -r temp
              git config user.name github-actions
              git config user.email github-actions@github.com
              git add .
              git commit -m "unzip"
              git push origin main
```

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

```shell
rm -r css

    rm -r en
    rm -r fonts
    rm -r js
```

The idea here is that the contents of the zip file should replace what is already in that particular branch of the repository. You might want to call the branch **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.

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

```shell
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).

```shell  
git config user.name github-actions

    git config user.email github-actions@github.com
    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.