Skip to content

v1.1.1

v1.1.1 #19

name: Update Zenodo Metadata
on:
push:
tags:
- 'v*' # Only standard releases (v1.0.0, v1.1.0, etc.)
- '!v*-*' # Exclude pre-releases like v1.0.0-beta
- '!python-v*' # Exclude Python library tags
release:
types: [published]
permissions:
contents: write
jobs:
update-zenodo:
name: Update Zenodo Metadata
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract release information
id: release_info
run: |
echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
echo "release_date=$(date -u +%Y-%m-%d)" >> $GITHUB_OUTPUT
- name: Update CITATION.cff with new version
run: |
VERSION="${{ steps.release_info.outputs.version }}"
DATE="${{ steps.release_info.outputs.release_date }}"
# Update version in CITATION.cff
sed -i "s/^version: .*/version: ${VERSION}/" CITATION.cff
sed -i "s/^date-released: .*/date-released: ${DATE}/" CITATION.cff
- name: Update README.md version and last updated date
run: |
VERSION="${{ steps.release_info.outputs.version }}"
DATE="${{ steps.release_info.outputs.release_date }}"
# Remove 'v' prefix if present
CLEAN_VERSION="${VERSION#v}"
# Format date as "Month Day, Year"
FORMATTED_DATE=$(date -d "$DATE" "+%B %d, %Y")
# Update version in README.md
sed -i "s/^\*\*Version:\*\* .*/**Version:** ${CLEAN_VERSION}/" README.md
# Update last updated date in README.md
sed -i "s/^\*\*Last Updated:\*\* .*/**Last Updated:** ${FORMATTED_DATE}/" README.md
- name: Update CHANGELOG.md with release notes
run: |
VERSION="${{ steps.release_info.outputs.version }}"
RELEASE_DATE="${{ steps.release_info.outputs.release_date }}"
RELEASE_BODY="${{ github.event.release.body }}"
# Remove 'v' prefix if present
CLEAN_VERSION="${VERSION#v}"
# Create new changelog entry
cat > changelog_entry.tmp << EOF
## [${CLEAN_VERSION}] - ${RELEASE_DATE}
### Release Notes
${RELEASE_BODY}
EOF
# Insert the new entry after the Unreleased section
awk -v entry="$(cat changelog_entry.tmp)" '
/^## \[Unreleased\]/ {
print
getline
print
print entry
next
}
{print}
' CHANGELOG.md > CHANGELOG.md.tmp
# Add comparison link at the end if not already present
if ! grep -q "\[${CLEAN_VERSION}\]:" CHANGELOG.md.tmp; then
echo "" >> CHANGELOG.md.tmp
echo "[${CLEAN_VERSION}]: https://github.com/upss-standard/universal-prompt-security-standard/releases/tag/${VERSION}" >> CHANGELOG.md.tmp
fi
# Replace original file
mv CHANGELOG.md.tmp CHANGELOG.md
rm -f changelog_entry.tmp
- name: Commit version updates
run: |
VERSION="${{ steps.release_info.outputs.version }}"
# Configure git user
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
# Stage modified files
git add README.md
git add CITATION.cff
git add CHANGELOG.md
# Check if there are changes to commit
if git diff --staged --quiet; then
echo "::notice::No version changes to commit"
else
git commit -m "chore(release): update version to ${VERSION} [skip ci]"
# Create a release branch and push to it
# Remove 'v' prefix if present to avoid double 'v' in branch name
CLEAN_VERSION="${VERSION#v}"
RELEASE_BRANCH="release/zenodo-v${CLEAN_VERSION}"
git checkout -b "${RELEASE_BRANCH}"
if git push origin "${RELEASE_BRANCH}"; then
echo "✅ Created release branch: ${RELEASE_BRANCH}"
echo "::warning::Please create a pull request to merge ${RELEASE_BRANCH} into main"
echo "::warning::The workflow will continue assuming version files will be merged"
else
echo "::error::Failed to create release branch"
exit 1
fi
fi
- name: Prepare Zenodo metadata
id: zenodo_metadata
run: |
VERSION="${{ steps.release_info.outputs.version }}"
RELEASE_DATE="${{ steps.release_info.outputs.release_date }}"
RELEASE_NAME="${{ github.event.release.name }}"
RELEASE_BODY="${{ github.event.release.body }}"
# Load metadata from config file and replace placeholders
if [ ! -f "config/zenodo/metadata.json" ]; then
echo "❌ Error: config/zenodo/metadata.json not found"
exit 1
fi
# Use jq to replace placeholders with proper JSON escaping
jq --arg version "$VERSION" \
--arg publication_date "$RELEASE_DATE" \
--arg release_body "$RELEASE_BODY" \
'
walk(if type == "string" then
gsub("{{VERSION}}"; $version) |
gsub("{{PUBLICATION_DATE}}"; $publication_date) |
gsub("{{RELEASE_BODY}}"; $release_body)
else
.
end)
' config/zenodo/metadata.json > zenodo_metadata.json
echo "Generated metadata:"
cat zenodo_metadata.json
- name: Update Zenodo deposition
env:
ZENODO_ACCESS_TOKEN: ${{ secrets.ZENODO_ACCESS_TOKEN }}
ZENODO_DEPOSITION_ID: ${{ secrets.ZENODO_DEPOSITION_ID }}
run: |
if [ -z "$ZENODO_ACCESS_TOKEN" ]; then
echo "Warning: ZENODO_ACCESS_TOKEN not set. Skipping Zenodo update."
echo "Please add ZENODO_ACCESS_TOKEN to repository secrets to enable automatic Zenodo updates."
exit 0
fi
if [ -z "$ZENODO_DEPOSITION_ID" ]; then
echo "Warning: ZENODO_DEPOSITION_ID not set. Skipping Zenodo update."
echo "Please add ZENODO_DEPOSITION_ID to repository secrets to enable automatic Zenodo updates."
exit 0
fi
# Function to create a new version, handling existing drafts
create_new_version() {
echo "Creating new version on Zenodo..."
NEW_VERSION_RESPONSE=$(curl -sS -X POST \
"https://zenodo.org/api/deposit/depositions/${ZENODO_DEPOSITION_ID}/actions/newversion" \
-H "Authorization: Bearer ${ZENODO_ACCESS_TOKEN}")
echo "New version response: ${NEW_VERSION_RESPONSE}"
# Check if the response contains an error about existing files
ERROR_MESSAGE=$(echo "$NEW_VERSION_RESPONSE" | jq -r '.message // empty')
STATUS=$(echo "$NEW_VERSION_RESPONSE" | jq -r '.status // empty')
if [ "$STATUS" = "400" ] && echo "$ERROR_MESSAGE" | grep -q "Please remove all files first"; then
echo "⚠️ Detected existing unpublished draft version"
# Check if there's a latest_draft link in the error response
LATEST_DRAFT_URL=$(echo "$NEW_VERSION_RESPONSE" | jq -r '.links.latest_draft // empty')
if [ -n "$LATEST_DRAFT_URL" ] && [ "$LATEST_DRAFT_URL" != "null" ]; then
EXISTING_DRAFT_ID=$(echo "$LATEST_DRAFT_URL" | grep -oP '/depositions/\K[0-9]+')
if [ -n "$EXISTING_DRAFT_ID" ]; then
echo "🗑️ Deleting existing unpublished draft: ${EXISTING_DRAFT_ID}"
DELETE_DRAFT_RESPONSE=$(curl -sS -X DELETE \
"https://zenodo.org/api/deposit/depositions/${EXISTING_DRAFT_ID}" \
-H "Authorization: Bearer ${ZENODO_ACCESS_TOKEN}")
DELETE_STATUS=$(echo "$DELETE_DRAFT_RESPONSE" | jq -r '.status // empty')
if [ "$DELETE_STATUS" = "400" ] || [ "$DELETE_STATUS" = "500" ]; then
echo "❌ Error: Failed to delete existing draft"
echo "Response: $DELETE_DRAFT_RESPONSE"
exit 1
fi
echo "✅ Successfully deleted existing draft"
echo "🔄 Retrying new version creation..."
# Retry creating new version
NEW_VERSION_RESPONSE=$(curl -sS -X POST \
"https://zenodo.org/api/deposit/depositions/${ZENODO_DEPOSITION_ID}/actions/newversion" \
-H "Authorization: Bearer ${ZENODO_ACCESS_TOKEN}")
echo "Retry response: ${NEW_VERSION_RESPONSE}"
fi
fi
fi
# Extract the new draft deposition ID
NEW_DRAFT_URL=$(echo "$NEW_VERSION_RESPONSE" | jq -r '.links.latest_draft')
NEW_DRAFT_ID=$(echo "$NEW_DRAFT_URL" | grep -oP '/depositions/\K[0-9]+')
if [ -z "$NEW_DRAFT_ID" ]; then
echo "❌ Error: Failed to create new version. Response:"
echo "$NEW_VERSION_RESPONSE"
exit 1
fi
echo "✅ New draft deposition ID: ${NEW_DRAFT_ID}"
}
# Call the function to create new version
create_new_version
# Keep existing files from the previous version instead of deleting them
# This ensures Zenodo has at least one file for publishing
# Update the metadata for the new draft
echo "Updating metadata for new version..."
UPDATE_RESPONSE=$(curl -sS -X PUT \
"https://zenodo.org/api/deposit/depositions/${NEW_DRAFT_ID}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ZENODO_ACCESS_TOKEN}" \
-d @zenodo_metadata.json)
echo "Update response: ${UPDATE_RESPONSE}"
# Check for errors in update response
UPDATE_STATUS=$(echo "$UPDATE_RESPONSE" | jq -r '.status // empty')
if [ "$UPDATE_STATUS" = "400" ] || [ "$UPDATE_STATUS" = "500" ]; then
echo "❌ Error: Failed to update metadata"
echo "Status: $UPDATE_STATUS"
echo "Message: $(echo "$UPDATE_RESPONSE" | jq -r '.message // empty')"
echo "Errors: $(echo "$UPDATE_RESPONSE" | jq -r '.errors // empty')"
exit 1
fi
# Publish the new version
echo "Publishing new version..."
PUBLISH_RESPONSE=$(curl -sS -X POST \
"https://zenodo.org/api/deposit/depositions/${NEW_DRAFT_ID}/actions/publish" \
-H "Authorization: Bearer ${ZENODO_ACCESS_TOKEN}")
echo "Publish response: ${PUBLISH_RESPONSE}"
# Check for errors in publish response
PUBLISH_STATUS=$(echo "$PUBLISH_RESPONSE" | jq -r '.status // empty')
if [ "$PUBLISH_STATUS" = "400" ] || [ "$PUBLISH_STATUS" = "500" ]; then
echo "❌ Error: Failed to publish new version"
echo "Status: $PUBLISH_STATUS"
echo "Response: $PUBLISH_RESPONSE"
exit 1
fi
# Extract and display the new DOI
NEW_DOI=$(echo "$PUBLISH_RESPONSE" | jq -r '.doi // empty')
if [ -z "$NEW_DOI" ] || [ "$NEW_DOI" = "null" ]; then
echo "❌ Error: Failed to extract DOI from publish response"
echo "Response: $PUBLISH_RESPONSE"
exit 1
fi
echo "✅ Successfully published new version to Zenodo!"
echo "New DOI: ${NEW_DOI}"
echo "Zenodo URL: https://doi.org/${NEW_DOI}"
- name: Summary
run: |
echo "## Zenodo Metadata Update Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Version**: ${{ steps.release_info.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- **Release Date**: ${{ steps.release_info.outputs.release_date }}" >> $GITHUB_STEP_SUMMARY
echo "- **Status**: ✅ Workflow completed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Next Steps" >> $GITHUB_STEP_SUMMARY
echo "If Zenodo secrets are configured, check the Zenodo record for the updated metadata." >> $GITHUB_STEP_SUMMARY