Skip to content
This repository has been archived by the owner on Aug 2, 2021. It is now read-only.

Commit

Permalink
Merge pull request #1 from jkfran/code
Browse files Browse the repository at this point in the history
GitHub Action code
  • Loading branch information
jkfran authored Jun 3, 2020
2 parents b0e0e2b + b4a6d91 commit 26fc907
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ celerybeat.pid

# Environments
.env
.env.local
.venv
env/
venv/
Expand Down
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM ubuntu:focal

# Install required system packages for our CronJob
RUN apt-get update && apt-get install --yes --no-install-recommends python3-pip

COPY requirements.txt .
COPY importer.py .

RUN pip3 install --no-cache-dir -r requirements.txt

ENTRYPOINT python3 importer.py
91 changes: 91 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Google Spreadsheet - CSV importer GitHub Action
This action allows you to upload your CSV file to a Google Spreadsheet.


## Usage

To use the action add the following step to your workflow file (e.g.
`.github/workflows/main.yml`)


```yml
- name: Upload CSV to Spreadsheet
uses: canonical-web-and-design/csv-to-google-spreadsheet
with:
csv_path: path/file.csv
spreadsheet_id: ${{ secrets.google_spreadsheet_id }}
worksheet: 0
google_service_account_email: ${{ secrets.google_service_account_email }}
google_service_account_private_key: ${{ secrets.google_service_account_private_key }}
```
A common use case could be to upload CSV only on a tagged commit, to do you can add a
conditional to the step:
```yml
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
```
So the full step would look like:
```yml
- name: Upload CSV to Spreadsheet
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
uses: canonical-web-and-design/csv-to-google-spreadsheet
with:
csv_path: path/file.csv
spreadsheet_id: ${{ secrets.google_spreadsheet_id }}
worksheet: 0
google_service_account_email: ${{ secrets.google_service_account_email }}
google_service_account_private_key: ${{ secrets.google_service_account_private_key }}
```
**If you are wondering how to get a Service Account**
A service account is a special type of Google account intended to represent a non-human user that needs to authenticate and be authorized to access data in Google APIs.
Since it’s a separate account, by default it does not have access to any spreadsheet until you share it with this account. Just like any other Google account.
Here’s how to get one:
1. Enable API Access for a Project if you haven’t done it yet.
2. Go to “APIs & Services > Credentials” and choose “Create credentials > Service account key”.
3. Fill out the form
4. Click “Create key”
5. Select “JSON” and click “Create”
6. Extract the account email and the account private key from there
## Non-goals
This GitHub Action only updates the content of a Google Spreadsheet with the same content of a CSV file.
## Append content
It is possible to append content to the worksheet, that means the content of your CSV will be added in the next free row.
The action invocation in this case would look like:
```yml
- name: Upload CSV to Spreadsheet
uses: canonical-web-and-design/csv-to-google-spreadsheet
with:
csv_path: path/file.csv
spreadsheet_id: ${{ secrets.google_spreadsheet_id }}
worksheet: 0
append_content: true
google_service_account_email: ${{ secrets.google_service_account_email }}
google_service_account_private_key: ${{ secrets.google_service_account_private_key }}
```
## License
The Dockerfile and associated scripts and documentation in this project
are released under the [GNU Lesser General Public License v3.0](LICENSE).
[Creating & using secrets]:
https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets
36 changes: 36 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# action.yml
name: 'Google Spreadsheet - CSV importer'
description: 'Import a CSV file into a Google Spreadsheet'
inputs:
csv_path:
description: ''
required: true
spreadsheet_id:
description: ''
required: true
worksheet:
description: ''
required: true
append_content:
description: ''
required: false
default: false
google_service_account_email:
description: ''
required: true
google_service_account_private_key:
description: ''
required: true
branding:
color: yellow
icon: upload-cloud
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.csv_path }}
- ${{ inputs.spreadsheet_id }}
- ${{ inputs.worksheet }}
- ${{ inputs.append_content }}
- ${{ inputs.google_service_account_email }}
- ${{ inputs.google_service_account_private_key }}
57 changes: 57 additions & 0 deletions importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from csv import reader
from distutils.util import strtobool
from os import getenv

import gspread
from google.oauth2.service_account import Credentials

# Input vars
csv_path = getenv("INPUT_CSV_PATH")
spreadsheet_id = getenv("INPUT_SPREADSHEET_ID")
worksheet = int(getenv("INPUT_WORKSHEET", 0))
append_content = strtobool(getenv("INPUT_APPEND_CONTENT", "False"))

service_account_info = {
"token_uri": "https://oauth2.googleapis.com/token",
"client_email": getenv("INPUT_GOOGLE_SERVICE_ACCOUNT_EMAIL"),
"private_key": getenv("INPUT_GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY").replace(
"\\n", "\n"
),
}
scopes = [
"https://spreadsheets.google.com/feeds",
]


def next_available_row(worksheet):
"""
Return the next available row in the first column
gspread doesn't have a method to return the last row used
"""
str_list = list(filter(None, worksheet.col_values(1)))
return str(len(str_list) + 1)


# Read csv file as a list of lists
with open(csv_path, "r") as read_obj:
# pass the file object to reader() to get the reader object
csv_reader = reader(read_obj)
# Pass reader object to list() to get a list of lists
list_of_rows = list(csv_reader)

creds = Credentials.from_service_account_info(
service_account_info, scopes=scopes
)

client = gspread.authorize(creds)

spreadsheet = client.open_by_key(spreadsheet_id)
ws = spreadsheet.get_worksheet(0)

if append_content:
start_from = f"A{next_available_row(ws)}"
else:
ws.clear()
start_from = "A1"

ws.update(start_from, list_of_rows)
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
gspread==3.6.0
google-auth==1.16.0

0 comments on commit 26fc907

Please sign in to comment.