@uniswap/ai-toolkit-notion-publisher 0.0.1 → 0.0.2-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +408 -28
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +122 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/notion-publisher.d.ts +2 -0
- package/dist/lib/notion-publisher.d.ts.map +1 -0
- package/dist/lib/notion-publisher.js +3 -0
- package/package.json +35 -7
package/README.md
CHANGED
|
@@ -1,45 +1,425 @@
|
|
|
1
1
|
# @uniswap/ai-toolkit-notion-publisher
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A CLI tool to publish release notes and other content to Notion databases with full markdown support. This tool fills a gap in the ecosystem by creating new database entries with custom properties—something existing GitHub Actions don't support.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- ✅ **Creates new pages in Notion databases** (not just updates)
|
|
8
|
+
- ✅ **Markdown to Notion blocks conversion** using @tryfabric/martian
|
|
9
|
+
- ✅ **Custom database properties** (Name, Date, Commit Range, Branch)
|
|
10
|
+
- ✅ **Git integration** (track commit ranges and branches)
|
|
11
|
+
- ✅ **CI/CD agnostic** (works with GitHub Actions, GitLab CI, CircleCI, Jenkins, etc.)
|
|
12
|
+
- ✅ **Type-safe** TypeScript implementation
|
|
13
|
+
- ✅ **Comprehensive error handling** with detailed logs
|
|
8
14
|
|
|
9
|
-
##
|
|
15
|
+
## Installation
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
1. Configure OIDC trusted publishing for the package name `@uniswap/ai-toolkit-notion-publisher`
|
|
13
|
-
2. Enable secure, token-less publishing from CI/CD workflows
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
17
|
+
### Global Installation
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g @uniswap/ai-toolkit-notion-publisher
|
|
21
|
+
```
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
### Using npx (Recommended)
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
No installation required:
|
|
21
26
|
|
|
22
|
-
|
|
27
|
+
```bash
|
|
28
|
+
npx @uniswap/ai-toolkit-notion-publisher --title "My Release" --content "..."
|
|
29
|
+
```
|
|
23
30
|
|
|
24
|
-
|
|
25
|
-
2. Configure the trusted publisher (e.g., GitHub Actions)
|
|
26
|
-
3. Specify the repository and workflow that should be allowed to publish
|
|
27
|
-
4. Use the configured workflow to publish your actual package
|
|
31
|
+
### Local Installation
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+
```bash
|
|
34
|
+
npm install --save-dev @uniswap/ai-toolkit-notion-publisher
|
|
35
|
+
```
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
- Contains no executable code
|
|
33
|
-
- Provides no functionality
|
|
34
|
-
- Should not be installed as a dependency
|
|
35
|
-
- Exists only for administrative purposes
|
|
37
|
+
## Prerequisites
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
### 1. Create a Notion Integration
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
1. Go to <https://www.notion.so/my-integrations>
|
|
42
|
+
2. Click "New integration"
|
|
43
|
+
3. Give it a name (e.g., "Release Notes Publisher")
|
|
44
|
+
4. Select the workspace
|
|
45
|
+
5. Copy the "Internal Integration Token" (starts with `secret_`)
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
### 2. Create a Notion Database
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
1. Create a new page in Notion
|
|
50
|
+
2. Add a database (inline or full-page)
|
|
51
|
+
3. Add these properties:
|
|
52
|
+
- **Name** (Title) - Required
|
|
53
|
+
- **Date** (Date) - Required
|
|
54
|
+
- **Commit Range** (Text) - Optional
|
|
55
|
+
- **Branch** (Text) - Optional
|
|
56
|
+
4. Share the database with your integration:
|
|
57
|
+
- Click "..." in the top right
|
|
58
|
+
- Click "Add connections"
|
|
59
|
+
- Select your integration
|
|
60
|
+
|
|
61
|
+
### 3. Get the Database ID
|
|
62
|
+
|
|
63
|
+
From the database URL: `https://notion.so/workspace/DATABASE_ID?v=VIEW_ID`
|
|
64
|
+
|
|
65
|
+
The `DATABASE_ID` is the 32-character hex string.
|
|
66
|
+
|
|
67
|
+
## Usage
|
|
68
|
+
|
|
69
|
+
### Basic Usage
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
notion-publisher \
|
|
73
|
+
--title "Release v1.2.0" \
|
|
74
|
+
--content "# What's New\n\n- Feature A\n- Feature B"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Required environment variables:
|
|
78
|
+
|
|
79
|
+
- `NOTION_API_KEY` - Your Notion integration token
|
|
80
|
+
- `RELEASE_NOTES_NOTION_DATABASE_ID` - Target database ID
|
|
81
|
+
|
|
82
|
+
### With All Options
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
notion-publisher \
|
|
86
|
+
--title "Release v1.2.0" \
|
|
87
|
+
--content "$(cat CHANGELOG.md)" \
|
|
88
|
+
--from-ref "v1.1.0" \
|
|
89
|
+
--to-ref "v1.2.0" \
|
|
90
|
+
--branch "main"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Using CLI Flags for Secrets
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
notion-publisher \
|
|
97
|
+
--api-key "secret_abc123" \
|
|
98
|
+
--database-id "32-char-hex-id" \
|
|
99
|
+
--title "Release v1.2.0" \
|
|
100
|
+
--content "# Release Notes"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**⚠️ Security Warning**: Using `--api-key` flag exposes secrets in process listings. Always prefer environment variables in production.
|
|
104
|
+
|
|
105
|
+
## GitHub Actions Integration
|
|
106
|
+
|
|
107
|
+
### Basic Example
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
name: Publish Release Notes
|
|
111
|
+
|
|
112
|
+
on:
|
|
113
|
+
release:
|
|
114
|
+
types: [published]
|
|
115
|
+
|
|
116
|
+
jobs:
|
|
117
|
+
publish-to-notion:
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
steps:
|
|
120
|
+
- name: Checkout
|
|
121
|
+
uses: actions/checkout@v4
|
|
122
|
+
|
|
123
|
+
- name: Setup Node.js
|
|
124
|
+
uses: actions/setup-node@v4
|
|
125
|
+
with:
|
|
126
|
+
node-version: '22'
|
|
127
|
+
registry-url: 'https://registry.npmjs.org'
|
|
128
|
+
scope: '@uniswap'
|
|
129
|
+
|
|
130
|
+
- name: Publish to Notion
|
|
131
|
+
run: |
|
|
132
|
+
npx @uniswap/ai-toolkit-notion-publisher \
|
|
133
|
+
--title "${{ github.event.release.name }}" \
|
|
134
|
+
--content "${{ github.event.release.body }}" \
|
|
135
|
+
--from-ref "${{ github.event.release.tag_name }}" \
|
|
136
|
+
--branch "${{ github.ref_name }}"
|
|
137
|
+
env:
|
|
138
|
+
NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}
|
|
139
|
+
RELEASE_NOTES_NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### With Changelog File
|
|
143
|
+
|
|
144
|
+
```yaml
|
|
145
|
+
- name: Read Changelog
|
|
146
|
+
id: changelog
|
|
147
|
+
run: |
|
|
148
|
+
echo "content<<EOF" >> $GITHUB_OUTPUT
|
|
149
|
+
cat CHANGELOG.md >> $GITHUB_OUTPUT
|
|
150
|
+
echo "EOF" >> $GITHUB_OUTPUT
|
|
151
|
+
|
|
152
|
+
- name: Publish to Notion
|
|
153
|
+
run: |
|
|
154
|
+
npx @uniswap/ai-toolkit-notion-publisher \
|
|
155
|
+
--title "Release ${{ github.event.release.tag_name }}" \
|
|
156
|
+
--content "${{ steps.changelog.outputs.content }}" \
|
|
157
|
+
--from-ref "${{ github.event.release.target_commitish }}" \
|
|
158
|
+
--to-ref "${{ github.event.release.tag_name }}"
|
|
159
|
+
env:
|
|
160
|
+
NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}
|
|
161
|
+
RELEASE_NOTES_NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## GitLab CI Integration
|
|
165
|
+
|
|
166
|
+
```yaml
|
|
167
|
+
publish_to_notion:
|
|
168
|
+
stage: deploy
|
|
169
|
+
image: node:22
|
|
170
|
+
script:
|
|
171
|
+
- npx @uniswap/ai-toolkit-notion-publisher
|
|
172
|
+
--title "Release $CI_COMMIT_TAG"
|
|
173
|
+
--content "$(cat CHANGELOG.md)"
|
|
174
|
+
--from-ref "$CI_COMMIT_BEFORE_SHA"
|
|
175
|
+
--to-ref "$CI_COMMIT_SHA"
|
|
176
|
+
--branch "$CI_COMMIT_BRANCH"
|
|
177
|
+
variables:
|
|
178
|
+
NOTION_API_KEY: $NOTION_API_KEY
|
|
179
|
+
RELEASE_NOTES_NOTION_DATABASE_ID: $NOTION_DATABASE_ID
|
|
180
|
+
only:
|
|
181
|
+
- tags
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## CircleCI Integration
|
|
185
|
+
|
|
186
|
+
```yaml
|
|
187
|
+
version: 2.1
|
|
188
|
+
jobs:
|
|
189
|
+
publish-notion:
|
|
190
|
+
docker:
|
|
191
|
+
- image: cimg/node:22.0
|
|
192
|
+
steps:
|
|
193
|
+
- checkout
|
|
194
|
+
- run:
|
|
195
|
+
name: Publish to Notion
|
|
196
|
+
command: |
|
|
197
|
+
npx @uniswap/ai-toolkit-notion-publisher \
|
|
198
|
+
--title "Release ${CIRCLE_TAG}" \
|
|
199
|
+
--content "$(cat CHANGELOG.md)" \
|
|
200
|
+
--from-ref "${CIRCLE_TAG}" \
|
|
201
|
+
--branch "${CIRCLE_BRANCH}"
|
|
202
|
+
environment:
|
|
203
|
+
NOTION_API_KEY: ${NOTION_API_KEY}
|
|
204
|
+
RELEASE_NOTES_NOTION_DATABASE_ID: ${NOTION_DATABASE_ID}
|
|
205
|
+
|
|
206
|
+
workflows:
|
|
207
|
+
release:
|
|
208
|
+
jobs:
|
|
209
|
+
- publish-notion:
|
|
210
|
+
filters:
|
|
211
|
+
tags:
|
|
212
|
+
only: /^v.*/
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Jenkins Integration
|
|
216
|
+
|
|
217
|
+
```groovy
|
|
218
|
+
pipeline {
|
|
219
|
+
agent any
|
|
220
|
+
environment {
|
|
221
|
+
NOTION_API_KEY = credentials('notion-api-key')
|
|
222
|
+
RELEASE_NOTES_NOTION_DATABASE_ID = credentials('notion-database-id')
|
|
223
|
+
}
|
|
224
|
+
stages {
|
|
225
|
+
stage('Publish to Notion') {
|
|
226
|
+
steps {
|
|
227
|
+
sh '''
|
|
228
|
+
npx @uniswap/ai-toolkit-notion-publisher \
|
|
229
|
+
--title "Release ${GIT_TAG_NAME}" \
|
|
230
|
+
--content "$(cat CHANGELOG.md)" \
|
|
231
|
+
--from-ref "${GIT_PREVIOUS_COMMIT}" \
|
|
232
|
+
--to-ref "${GIT_COMMIT}" \
|
|
233
|
+
--branch "${GIT_BRANCH}"
|
|
234
|
+
'''
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## CLI Arguments
|
|
242
|
+
|
|
243
|
+
| Argument | Environment Variable | Required | Description |
|
|
244
|
+
| --------------- | ---------------------------------- | -------- | --------------------------------------------------- |
|
|
245
|
+
| `--api-key` | `NOTION_API_KEY` | Yes | Notion integration token |
|
|
246
|
+
| `--database-id` | `RELEASE_NOTES_NOTION_DATABASE_ID` | Yes | Target Notion database ID (32-char hex) |
|
|
247
|
+
| `--title` | - | Yes | Page title for the release notes |
|
|
248
|
+
| `--content` | - | Yes | Page content in markdown format |
|
|
249
|
+
| `--from-ref` | - | No | Starting git reference (e.g., previous version tag) |
|
|
250
|
+
| `--to-ref` | - | No | Ending git reference (e.g., current version tag) |
|
|
251
|
+
| `--branch` | - | No | Branch name where the release was made |
|
|
252
|
+
|
|
253
|
+
**Note**: Environment variables take precedence over CLI flags for API key and database ID.
|
|
254
|
+
|
|
255
|
+
## Markdown Support
|
|
256
|
+
|
|
257
|
+
The tool uses [@tryfabric/martian](https://github.com/tryfabric/martian) to convert markdown to Notion blocks. Supported markdown features include:
|
|
258
|
+
|
|
259
|
+
- Headers (H1, H2, H3)
|
|
260
|
+
- **Bold**, _italic_, ~~strikethrough~~ text
|
|
261
|
+
- Lists (ordered and unordered)
|
|
262
|
+
- Code blocks with syntax highlighting
|
|
263
|
+
- Links
|
|
264
|
+
- Images (as external URLs)
|
|
265
|
+
- Blockquotes
|
|
266
|
+
- Tables
|
|
267
|
+
- And more!
|
|
268
|
+
|
|
269
|
+
### Example Markdown
|
|
270
|
+
|
|
271
|
+
```markdown
|
|
272
|
+
# Release v1.2.0
|
|
273
|
+
|
|
274
|
+
## 🚀 New Features
|
|
275
|
+
|
|
276
|
+
- Added dark mode support
|
|
277
|
+
- Improved performance by 50%
|
|
278
|
+
- New API endpoints for user management
|
|
279
|
+
|
|
280
|
+
## 🐛 Bug Fixes
|
|
281
|
+
|
|
282
|
+
- Fixed memory leak in data processing
|
|
283
|
+
- Resolved authentication issues
|
|
284
|
+
|
|
285
|
+
## 📝 Documentation
|
|
286
|
+
|
|
287
|
+
Updated the [Getting Started Guide](https://example.com/docs)
|
|
288
|
+
|
|
289
|
+
## Contributors
|
|
290
|
+
|
|
291
|
+
Thanks to @user1 and @user2 for their contributions!
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Troubleshooting
|
|
295
|
+
|
|
296
|
+
### Error: "NOTION_API_KEY is required"
|
|
297
|
+
|
|
298
|
+
**Cause**: Missing API key
|
|
299
|
+
|
|
300
|
+
**Solution**: Set the `NOTION_API_KEY` environment variable or use `--api-key` flag
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
export NOTION_API_KEY="secret_abc123"
|
|
304
|
+
notion-publisher --title "..." --content "..."
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Error: "RELEASE_NOTES_NOTION_DATABASE_ID is required"
|
|
308
|
+
|
|
309
|
+
**Cause**: Missing database ID
|
|
310
|
+
|
|
311
|
+
**Solution**: Set the environment variable or use `--database-id` flag
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
export RELEASE_NOTES_NOTION_DATABASE_ID="32-char-hex-id"
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Error: "Could not find database"
|
|
318
|
+
|
|
319
|
+
**Cause**: Database doesn't exist or integration doesn't have access
|
|
320
|
+
|
|
321
|
+
**Solution**:
|
|
322
|
+
|
|
323
|
+
1. Verify the database ID is correct
|
|
324
|
+
2. Share the database with your integration:
|
|
325
|
+
- Open the database in Notion
|
|
326
|
+
- Click "..." → "Add connections"
|
|
327
|
+
- Select your integration
|
|
328
|
+
|
|
329
|
+
### Error: "Validation failed"
|
|
330
|
+
|
|
331
|
+
**Cause**: Database schema doesn't match expected properties
|
|
332
|
+
|
|
333
|
+
**Solution**: Ensure your database has these properties:
|
|
334
|
+
|
|
335
|
+
- **Name** (Title type)
|
|
336
|
+
- **Date** (Date type)
|
|
337
|
+
- **Commit Range** (Text type) - if using `--from-ref` or `--to-ref`
|
|
338
|
+
- **Branch** (Text type) - if using `--branch`
|
|
339
|
+
|
|
340
|
+
### Rate Limiting
|
|
341
|
+
|
|
342
|
+
Notion API has rate limits (3 requests per second). If you're publishing multiple pages:
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
# Add delays between calls
|
|
346
|
+
notion-publisher --title "Release 1" --content "..." && \
|
|
347
|
+
sleep 1 && \
|
|
348
|
+
notion-publisher --title "Release 2" --content "..."
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Output
|
|
352
|
+
|
|
353
|
+
The tool outputs the created Notion page URL to stdout:
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
PAGE_URL=$(notion-publisher --title "..." --content "...")
|
|
357
|
+
echo "Published to: $PAGE_URL"
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
In GitHub Actions, capture it as an output:
|
|
361
|
+
|
|
362
|
+
```yaml
|
|
363
|
+
- name: Publish to Notion
|
|
364
|
+
id: publish
|
|
365
|
+
run: |
|
|
366
|
+
PAGE_URL=$(npx @uniswap/ai-toolkit-notion-publisher \
|
|
367
|
+
--title "..." \
|
|
368
|
+
--content "...")
|
|
369
|
+
echo "page_url=$PAGE_URL" >> $GITHUB_OUTPUT
|
|
370
|
+
|
|
371
|
+
- name: Comment on PR
|
|
372
|
+
run: |
|
|
373
|
+
echo "Published to Notion: ${{ steps.publish.outputs.page_url }}"
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Development
|
|
377
|
+
|
|
378
|
+
### Build
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
npx nx build @uniswap/ai-toolkit-notion-publisher
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Test Locally
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
# Build the package
|
|
388
|
+
npx nx build @uniswap/ai-toolkit-notion-publisher
|
|
389
|
+
|
|
390
|
+
# Test with tsx (no build required)
|
|
391
|
+
npx tsx packages/notion-publisher/src/cli.ts \
|
|
392
|
+
--title "Test" \
|
|
393
|
+
--content "# Test content"
|
|
394
|
+
|
|
395
|
+
# Test built version
|
|
396
|
+
node dist/packages/notion-publisher/cli.js \
|
|
397
|
+
--title "Test" \
|
|
398
|
+
--content "# Test content"
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Publishing
|
|
402
|
+
|
|
403
|
+
This package is automatically published via the repository's CI/CD workflow using Nx release.
|
|
404
|
+
|
|
405
|
+
## Why This Tool?
|
|
406
|
+
|
|
407
|
+
Existing GitHub Actions for Notion have limitations:
|
|
408
|
+
|
|
409
|
+
| Feature | @uniswap/ai-toolkit-notion-publisher | tryfabric/markdown-to-notion | push-markdown-to-notion |
|
|
410
|
+
| ---------------------- | ------------------------------------ | ---------------------------- | ----------------------- |
|
|
411
|
+
| **Create new pages** | ✅ Yes | ❌ No (updates only) | ❌ No (updates only) |
|
|
412
|
+
| **Write to databases** | ✅ Yes | ❌ No | ❌ No |
|
|
413
|
+
| **Custom properties** | ✅ Yes | ❌ No | ❌ No |
|
|
414
|
+
| **Maintenance** | 🆕 Active (2024) | ⚠️ Stale (2022) | ⚠️ Low activity |
|
|
415
|
+
| **CI agnostic** | ✅ Yes (CLI tool) | ❌ GitHub only | ❌ GitHub only |
|
|
416
|
+
|
|
417
|
+
This tool was created to fill the gap: **creating new Notion database entries with structured metadata**, which is essential for release notes and changelog tracking.
|
|
418
|
+
|
|
419
|
+
## License
|
|
420
|
+
|
|
421
|
+
See repository LICENSE file.
|
|
422
|
+
|
|
423
|
+
## Support
|
|
424
|
+
|
|
425
|
+
For issues, feature requests, or contributions, please visit the [GitHub repository](https://github.com/Uniswap/ai-toolkit).
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Client } from '@notionhq/client';
|
|
3
|
+
import { markdownToBlocks } from '@tryfabric/martian';
|
|
4
|
+
import minimist from 'minimist';
|
|
5
|
+
// Parse CLI arguments with flags using minimist
|
|
6
|
+
const args = minimist(process.argv.slice(2), {
|
|
7
|
+
string: ['api-key', 'database-id', 'title', 'content', 'from-ref', 'to-ref', 'branch'],
|
|
8
|
+
alias: {
|
|
9
|
+
'api-key': 'apiKey',
|
|
10
|
+
'database-id': 'databaseId',
|
|
11
|
+
'from-ref': 'fromRef',
|
|
12
|
+
'to-ref': 'toRef',
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
// Read from environment variables first, fall back to CLI arguments
|
|
16
|
+
// This prevents secrets from appearing in process listings
|
|
17
|
+
const apiKey = process.env.NOTION_API_KEY || args.apiKey;
|
|
18
|
+
const databaseId = process.env.RELEASE_NOTES_NOTION_DATABASE_ID || args.databaseId;
|
|
19
|
+
const { title, content, fromRef, toRef, branch } = args;
|
|
20
|
+
// Color codes for output
|
|
21
|
+
const RED = '\x1b[0;31m';
|
|
22
|
+
const GREEN = '\x1b[0;32m';
|
|
23
|
+
const NC = '\x1b[0m'; // No Color / Colorless
|
|
24
|
+
// Logging functions
|
|
25
|
+
const logInfo = (message) => {
|
|
26
|
+
console.error(`${GREEN}[INFO]${NC} ${message}`);
|
|
27
|
+
};
|
|
28
|
+
const logError = (message) => {
|
|
29
|
+
console.error(`${RED}[ERROR]${NC} ${message}`);
|
|
30
|
+
};
|
|
31
|
+
// Validate required arguments
|
|
32
|
+
if (!apiKey) {
|
|
33
|
+
logError('NOTION_API_KEY is required (via NOTION_API_KEY env var or --api-key flag)');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
if (!databaseId) {
|
|
37
|
+
logError('RELEASE_NOTES_NOTION_DATABASE_ID is required (via RELEASE_NOTES_NOTION_DATABASE_ID env var or --database-id flag)');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
if (!title) {
|
|
41
|
+
logError('TITLE is required');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
if (!content) {
|
|
45
|
+
logError('CONTENT is required');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
logInfo(`Preparing to publish to Notion database: ${databaseId}`);
|
|
49
|
+
logInfo(`Page title: ${title}`);
|
|
50
|
+
// Initialize Notion client
|
|
51
|
+
const notion = new Client({ auth: apiKey });
|
|
52
|
+
async function publishToNotion() {
|
|
53
|
+
try {
|
|
54
|
+
// Convert markdown content to Notion blocks using Martian
|
|
55
|
+
logInfo('Converting markdown to Notion blocks...');
|
|
56
|
+
const blocks = markdownToBlocks(content);
|
|
57
|
+
// Serialize and deserialize to strip TypeScript type metadata
|
|
58
|
+
// This is necessary because @tryfabric/martian and @notionhq/client have
|
|
59
|
+
// incompatible type definitions despite being structurally compatible at runtime
|
|
60
|
+
const notionBlocks = JSON.parse(JSON.stringify(blocks));
|
|
61
|
+
// Build properties object for the Notion page
|
|
62
|
+
const properties = {
|
|
63
|
+
Name: {
|
|
64
|
+
title: [{ text: { content: title } }],
|
|
65
|
+
},
|
|
66
|
+
Date: {
|
|
67
|
+
date: { start: new Date().toISOString() },
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
// Add optional properties if provided
|
|
71
|
+
if (fromRef && toRef) {
|
|
72
|
+
properties['Commit Range'] = {
|
|
73
|
+
rich_text: [{ text: { content: `${fromRef} → ${toRef}` } }],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
else if (fromRef) {
|
|
77
|
+
properties['Commit Range'] = {
|
|
78
|
+
rich_text: [{ text: { content: `From: ${fromRef}` } }],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
else if (toRef) {
|
|
82
|
+
properties['Commit Range'] = {
|
|
83
|
+
rich_text: [{ text: { content: `To: ${toRef}` } }],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (branch) {
|
|
87
|
+
properties.Branch = {
|
|
88
|
+
rich_text: [{ text: { content: branch } }],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// Create Notion page
|
|
92
|
+
logInfo('Creating Notion page...');
|
|
93
|
+
const response = await notion.pages.create({
|
|
94
|
+
parent: { database_id: databaseId },
|
|
95
|
+
properties,
|
|
96
|
+
children: notionBlocks,
|
|
97
|
+
});
|
|
98
|
+
logInfo('✅ Successfully created Notion page');
|
|
99
|
+
// Check if response has url property (full page response vs partial)
|
|
100
|
+
const pageUrl = 'url' in response ? response.url : 'https://notion.so';
|
|
101
|
+
logInfo(`Page URL: ${pageUrl}`);
|
|
102
|
+
// Output the page URL to stdout (for GitHub Actions to capture)
|
|
103
|
+
console.log(pageUrl);
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
logError('Failed to create Notion page');
|
|
108
|
+
if (error instanceof Error) {
|
|
109
|
+
logError(error.message);
|
|
110
|
+
// Log additional details if available
|
|
111
|
+
if ('body' in error) {
|
|
112
|
+
logError(`Details: ${JSON.stringify(error.body, null, 2)}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
logError(String(error));
|
|
117
|
+
}
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Run the main function
|
|
122
|
+
publishToNotion();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './lib/notion-publisher.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notion-publisher.d.ts","sourceRoot":"","sources":["../../src/lib/notion-publisher.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniswap/ai-toolkit-notion-publisher",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
"version": "0.0.2-next.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "CLI tool to publish release notes to Notion databases with markdown support",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"bin": {
|
|
11
|
+
"notion-publisher": "./dist/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
"./package.json": "./package.json",
|
|
15
|
+
".": {
|
|
16
|
+
"@ai-toolkit/source": "./src/index.ts",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"!**/*.tsbuildinfo"
|
|
25
|
+
],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "restricted"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@notionhq/client": "^2.2.15",
|
|
31
|
+
"@tryfabric/martian": "^1.2.4",
|
|
32
|
+
"minimist": "^1.2.8",
|
|
33
|
+
"tslib": "^2.3.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/minimist": "^1.2.5"
|
|
37
|
+
}
|
|
10
38
|
}
|