Skip to content

Commit

Permalink
add update-notion-database composite action
Browse files Browse the repository at this point in the history
  • Loading branch information
liyaka committed Jan 5, 2025
1 parent b0eb96a commit 27f6d7c
Show file tree
Hide file tree
Showing 4 changed files with 286 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/new-tag-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ jobs:

# Runs a single command using the runners shell
- name: get version
id: tag
uses: comet-ml/gha-tools/get-new-tag@main
with:
do-checkout: 'true'
default-tag: '0.0.1'
do-tag-create: 'true'

- name: Summary
run: |
echo "New tag is ${{steps.tag.outputs.tag}}" >> $GITHUB_STEP_SUMMARY
1 change: 1 addition & 0 deletions get-new-tag/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,4 @@ runs:
set -x
git tag ${TAG}
git push origin ${TAG}
65 changes: 65 additions & 0 deletions update-notion-database/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# update Notion database

To use it:

Set up the secrets in your GitHub repository:

* NOTION_TOKEN
* NOTION_DATABASE_ID


Trigger the workflow manually and provide the fields as a JSON string. Examples:

``` json
// Example 1 - Version update
{
"Date": "today",
"Component": "MyApp",
"Old Version": "1.0.0",
"New Version": "1.1.0"
}

// Example 2 - Task tracking
{
"Title": "New Feature",
"Status": "In Progress",
"Priority": "High",
"Due Date": "2024-12-31"
}
```

The script will:

Parse the JSON input
Convert values to appropriate types
Add a new row to your Notion database, if row with the same values already exists, it will not be added - the check is based on the unique_fields comma seprated list

# Example workflow using the composite action
```yaml
name: Update Notion
on:
workflow_dispatch:
inputs:
fields_json:
description: 'Fields to update'
required: true
type: string
unique_fields:
description: 'Unique fields to cjeck for duplicates'
required: true
type: string

jobs:
update-notion:
runs-on: ubuntu-latest
steps:
- uses: comet-ml/gha-tools/notion-update@main # If publishing as a separate repo
with:
notion_token: ${{ secrets.NOTION_TOKEN }}
database_id: ${{ secrets.NOTION_DATABASE_ID }}
fields_json: ${{ inputs.unique_fields }}

```

For your Notion page you want to update - https://developers.notion.com/docs/create-a-notion-integration#give-your-integration-page-permissions

215 changes: 215 additions & 0 deletions update-notion-database/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
# action.yml
name: 'Update Notion Database'
description: 'Add a new row to a Notion database with field validation and duplicate checking'

inputs:
notion_token:
description: 'Notion API token'
required: true
database_id:
description: 'Notion database ID'
required: true
fields_json:
description: 'JSON string containing field names and values'
required: true
unique_fields:
description: 'Comma-separated list of fields to check for duplicates'
required: true

runs:
using: "composite"
steps:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'

- name: Install dependencies
shell: bash
run: |
python -m pip install --upgrade pip
pip install notion-client pandas python-dateutil
- name: Update Notion Database
shell: python
env:
NOTION_TOKEN: ${{ inputs.notion_token }}
DATABASE_ID: ${{ inputs.database_id }}
FIELDS_JSON: ${{ inputs.fields_json }}
UNIQUE_FIELDS: ${{ inputs.unique_fields }}
run: |
import os
import json
import sys
from notion_client import Client
import pandas as pd
from datetime import datetime
from dateutil import parser
def format_date(date_str):
"""Convert various date formats to Notion's expected ISO format"""
try:
parsed_date = parser.parse(date_str)
return parsed_date.isoformat()
except Exception as e:
print(f"Error parsing date {date_str}: {str(e)}")
return None
def get_property_value(property_item):
property_type = property_item['type']
if property_type == 'title':
return property_item['title'][0]['plain_text'] if property_item['title'] else ''
elif property_type == 'rich_text':
return property_item['rich_text'][0]['plain_text'] if property_item['rich_text'] else ''
elif property_type == 'number':
return property_item['number']
elif property_type == 'select':
return property_item['select']['name'] if property_item['select'] else ''
elif property_type == 'multi_select':
return [option['name'] for option in property_item['multi_select']]
elif property_type == 'date':
if property_item['date']:
return property_item['date']['start']
return None
elif property_type == 'checkbox':
return property_item['checkbox']
return None
def create_property_value(value, property_type):
print(f"Creating property value for type {property_type} with value {value}")
if property_type == 'title':
return {'title': [{'text': {'content': str(value)}}]}
elif property_type == 'rich_text':
return {'rich_text': [{'text': {'content': str(value)}}]}
elif property_type == 'number':
try:
return {'number': float(value)}
except (TypeError, ValueError):
return {'number': None}
elif property_type == 'select':
return {'select': {'name': str(value)}}
elif property_type == 'multi_select':
if isinstance(value, list):
return {'multi_select': [{'name': str(v)} for v in value]}
return {'multi_select': [{'name': str(value)}]}
elif property_type == 'date':
formatted_date = format_date(value)
print(f"Formatted date: {formatted_date}")
if formatted_date:
return {
'date': {
'start': formatted_date
}
}
return {'date': None}
elif property_type == 'checkbox':
return {'checkbox': bool(value)}
return {'rich_text': [{'text': {'content': str(value)}}]}
def main():
try:
# Get environment variables
notion_token = os.environ['NOTION_TOKEN']
database_id = os.environ['DATABASE_ID']
fields_json = os.environ['FIELDS_JSON']
unique_fields = os.environ['UNIQUE_FIELDS'].split(',')
# Initialize Notion client
notion = Client(auth=notion_token)
# Parse fields JSON
try:
fields = json.loads(fields_json)
except json.JSONDecodeError:
print("Error: Invalid JSON format in fields_json")
sys.exit(1)
print(f"Processing fields: {fields}")
# Get database schema
database = notion.databases.retrieve(database_id)
properties = database['properties']
print("Database properties:")
for prop_name, prop_data in properties.items():
print(f"- {prop_name}: {prop_data['type']}")
# Query existing entries
print("\nQuerying existing entries...")
results = []
query = notion.databases.query(database_id)
results.extend(query['results'])
while query.get('has_more'):
query = notion.databases.query(
database_id,
start_cursor=query['next_cursor']
)
results.extend(query['results'])
# Check for duplicates
print("\nChecking for duplicates...")
duplicate_found = False
for result in results:
matches = 0
needed_matches = len(unique_fields)
for unique_field in unique_fields:
# Handle the space in "Date " field name
field_name = unique_field.strip()
if field_name not in fields:
continue
if field_name not in result['properties']:
continue
existing_value = get_property_value(result['properties'][field_name])
new_value = fields[field_name]
if str(existing_value).strip().lower() == str(new_value).strip().lower():
matches += 1
if matches == needed_matches:
duplicate_found = True
print(f"Duplicate entry found!")
break
if duplicate_found:
print("Skipping upload due to duplicate entry")
sys.exit(0)
# Prepare properties for new page
new_properties = {}
for field_name, field_value in fields.items():
# Handle the space in field names
matching_field = next((prop for prop in properties.keys()
if prop.strip() == field_name.strip()), None)
if matching_field:
prop_type = properties[matching_field]['type']
print(f"\nProcessing field: {matching_field}")
print(f"Type: {prop_type}")
print(f"Value: {field_value}")
new_properties[matching_field] = create_property_value(field_value, prop_type)
print(f"Converted to: {new_properties[matching_field]}")
# Create new page
print("\nCreating new page with properties:")
print(json.dumps(new_properties, indent=2))
response = notion.pages.create(
parent={'database_id': database_id},
properties=new_properties
)
print("Successfully updated Notion database")
except Exception as e:
print(f"Error: {str(e)}")
print(f"Error type: {type(e)}")
import traceback
print(traceback.format_exc())
sys.exit(1)
if __name__ == "__main__":
main()

0 comments on commit 27f6d7c

Please sign in to comment.