Skip to content

Commit

Permalink
adding workflow preparing to test
Browse files Browse the repository at this point in the history
Signed-off-by: vsoch <[email protected]>
  • Loading branch information
vsoch committed Mar 4, 2022
1 parent fdadd4d commit a68bca0
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 7 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Zenodo Release

on:
release:
types: [published]

jobs:
deploy:
runs-on: ubuntu-20.04

steps:

- uses: actions/checkout@v3
- name: download archive to runner
env:
zipball: ${{ github.event.release.zipball_url }}
tarball: ${{ github.event.release.tarball_url }}
version: ${{ github.event.release.tag_name }}
run: |
name=$(basename ${tarball})
curl -L $tarball > $name
echo "archive=${name}" >> $GITHUB_ENV
- name: Run Zenodo Deploy
with:
version: ${{ github.event.release.tag_name }}
zenodo_json: .zenodo.json
archive: ${{ env.archive }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
4 changes: 3 additions & 1 deletion .zenodo.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@
"affiliation": "Ohio SuperComputer Center",
"name": "Jeff Ohrstrom"
}
]
],
"keywords": ["zenodo", "release", "archive"],
"license": "MIT"
}
66 changes: 65 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,70 @@ on release, and without needing to enable admin webhooks. To get this working yo
1. Create an account on Zenodo
2. Under your name -> Applications -> Developer Applications -> Personal Access Tokens -> +New Token and choose both scopes for deposit
3. Add the token to your repository secrets as `ZENODO_TOKEN`
4. Create a .zenodo.json file for the root of your repository (see [template](.zenodo.json))
5. Add the example action (modified for your release) to your GitHub repository.

**Important** You CANNOT create a release online first and then try to upload to the same DOI.
If you do this, you'll get:

**todo** under development!
```python
{'status': 400,
'message': 'Validation error.',
'errors': [{'field': 'metadata.doi',
'message': 'The prefix 10.5281 is administrated locally.'}]}
```

I think this is kind of silly, but that's just me.

## Usage

### GitHub Action

After you complete the steps above to create the metadata file, you might create a release
action as follows:

```yaml
name: Zenodo Release

on:
release:
types: [published]

jobs:
deploy:
runs-on: ubuntu-20.04

steps:
- uses: actions/checkout@v3
- name: download archive to runner
env:
tarball: ${{ github.event.release.tarball_url }}
run: |
name=$(basename ${tarball})
curl -L $tarball > $name
echo "archive=${name}" >> $GITHUB_ENV
- name: Run Zenodo Deploy
with:
version: ${{ github.event.release.tag_name }}
zenodo_json: .zenodo.json
archive: ${{ env.archive }}
```
Notice how we are choosing to use the .tar.gz (you could use the zip too at `${{ github.event.release.zipball_url }}`)
and using the default zenodo.json that is obtained from the checked out repository.
We also grab the version as the release tag. We are also running on the publication of a release.

### Local

If you want to use the script locally (meaning to manually push a release) you can wget
or download the release (usually .tar.gz or .zip) and then export your zenodo token and do
the following:

```bash
export ZENODO_TOKEN=xxxxxxxxxxxxxxxxxxxx
# archive # identifier # version
$ python scripts/deploy.py upload 0.0.0.tar.gz 6326700 --version 0.0.0
```

37 changes: 32 additions & 5 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,47 @@ inputs:
zenodo_json:
description: Path to zenodo.json to upload with metadata (must exist)

#outputs:
# matrix:
# description: matrix of spliced builds
# value: ${{ steps.matrix.outputs.matrix }}
outputs:
badge:
description: badge url
value: ${{ steps.deploy.outputs.badge }}
bucket:
description: bucket url
value: ${{ steps.deploy.outputs.bucket }}
conceptbadge:
description: concept badge url
value: ${{ steps.deploy.outputs.conceptbadge }}
conceptdoi:
description: concept doi url
value: ${{ steps.deploy.outputs.conceptdoi }}
doi:
description: doi url
value: ${{ steps.deploy.outputs.doi }}
latest:
description: latest url
value: ${{ steps.deploy.outputs.latest }}
latest_html:
description: latest html url
value: ${{ steps.deploy.outputs.latest_html }}
record:
description: record url
value: ${{ steps.deploy.outputs.record }}
record_html:
description: record html url
value: ${{ steps.deploy.outputs.record_html }}

runs:
using: "composite"
steps:

- name: Deploy Zenodo
id: deploy
env:
zenodo_json: ${{ inputs.zenodo_json }}
archive: ${{ inputs.archive }}
version: ${{ inputs.version }}
ACTION_PATH: ${{ github.action_path }}
run: ${{ github.action_path }}/scripts/deploy.py ${zenodo_json} ${archive} --version ${version}
run: |
pip install requests
${{ github.action_path }}/scripts/deploy.py upload ${archive} --zenodo-json ${zenodo_json} --version ${version}
shell: python
154 changes: 154 additions & 0 deletions scripts/deploy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#!/usr/bin/env python3

# This script does the following.
# 1. Takes in a space separated list of changed files
# 2. For each changed file, adds a header (title) based on the filename
# 3. Sets output for the prepared files to move into the site


import argparse
import os
import json
import sys
from datetime import datetime
import requests


def read_file(filename):
with open(filename, "r") as fd:
content = fd.read()
return content


def read_json(filename):
with open(filename, "r") as fd:
content = json.loads(fd.read())
return content


ZENODO_TOKEN = os.environ.get("ZENODO_TOKEN")
ZENODO_HOST = "zenodo.org"
if not ZENODO_TOKEN:
sys.exit("A ZENODO_TOKEN is required to be exported in the environment!")


def upload_archive(archive, zenodo_json, version):
"""
Upload an archive to zenodo
"""
archive = os.path.abspath(archive)
if not os.path.exists(archive):
sys.exit("Archive %s does not exist." % archive)

headers = {"Accept": "application/json"}
params = {"access_token": ZENODO_TOKEN}

# Create an empty upload
response = requests.post(
"https://zenodo.org/api/deposit/depositions",
params=params,
json={},
headers=headers,
)
if response.status_code != 200:
sys.exit(
"Trouble requesting new upload: %s, %s"
% (response.status_code, response.json())
)

upload = response.json()

# Using requests files indicates multipart/form-data
# Here we are uploading the new release file
url = "https://zenodo.org/api/deposit/depositions/%s/files" % upload["id"]
bucket_url = upload["links"]["bucket"]

with open(archive, "rb") as fp:
response = requests.put(
"%s/%s" % (bucket_url, os.path.basename(archive)),
data=fp,
params=params,
)
if response.status_code != 200:
sys.exit("Trouble uploading artifact %s to bucket" % archive)

# Finally, load .zenodo.json and add version
metadata = read_json(zenodo_json)
metadata["version"] = version
metadata["publication_date"] = str(datetime.now())
if "upload_type" not in metadata:
metadata["upload_type"] = "software"
url = "https://zenodo.org/api/deposit/depositions/%s" % upload["id"]
headers["Content-Type"] = "application/json"
response = requests.put(
url, data=json.dumps({"metadata": metadata}), params=params, headers=headers
)
if response.status_code != 200:
sys.exit(
"Trouble uploading metadata %s, %s" % response.status_code, response.json()
)

data = response.json()
publish_url = data["links"]["publish"]
r = requests.post(publish_url, params=params)
if r.status_code not in [200, 201, 202]:
sys.exit(
"Issue publishing record: %s, %s" % (response.status_code, response.json())
)

published = r.json()
print("::group::Record")
print(json.dumps(published, indent=4))
print("::endgroup::")
for k, v in published["links"].items():
print("::set-output name=%s::%s" % (k, v))


def get_parser():
parser = argparse.ArgumentParser(description="Zenodo Uploader")
subparsers = parser.add_subparsers(
help="actions",
title="actions",
description="Upload to Zenodo",
dest="command",
)
upload = subparsers.add_parser("upload", help="upload an archive to zenodo")
upload.add_argument("archive", help="archive to upload")
upload.add_argument(
"--zenodo-json",
dest="zenodo_json",
help="path to .zenodo.json (defaults to .zenodo.json)",
default=".zenodo.json",
)
upload.add_argument("--version", help="version to upload")
return parser


def main():
parser = get_parser()

def help(return_code=0):
parser.print_help()
sys.exit(return_code)

# If an error occurs while parsing the arguments, the interpreter will exit with value 2
args, extra = parser.parse_known_args()
if not args.command:
help()

if not args.zenodo_json or not os.path.exists(args.zenodo_json):
sys.exit(
"You must provide an existing .zenodo.json as the first positional argument."
)
if not args.archive:
sys.exit("You must provide an archive as the second positional argument.")
if not args.version:
sys.exit("You must provide a software version to upload.")

# Prepare drafts
if args.command == "upload":
upload_archive(args.archive, args.zenodo_json, args.version)


if __name__ == "__main__":
main()

0 comments on commit a68bca0

Please sign in to comment.