notion_publish 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +36 -0
- data/LICENSE +21 -0
- data/README.md +221 -0
- data/docs/notion-publish-home-page.md +105 -0
- data/docs/usage.md +648 -0
- data/exe/notion-publish +6 -0
- data/lib/notion_publish/adopter.rb +77 -0
- data/lib/notion_publish/cli.rb +212 -0
- data/lib/notion_publish/client.rb +226 -0
- data/lib/notion_publish/commands/adopt.rb +114 -0
- data/lib/notion_publish/commands/command.rb +114 -0
- data/lib/notion_publish/commands/properties.rb +33 -0
- data/lib/notion_publish/commands/publish.rb +134 -0
- data/lib/notion_publish/commands/relink.rb +95 -0
- data/lib/notion_publish/commands/reporting.rb +57 -0
- data/lib/notion_publish/commands/republish.rb +156 -0
- data/lib/notion_publish/commands/status.rb +84 -0
- data/lib/notion_publish/commands/whoami.rb +27 -0
- data/lib/notion_publish/commands.rb +17 -0
- data/lib/notion_publish/decoration.rb +75 -0
- data/lib/notion_publish/document.rb +75 -0
- data/lib/notion_publish/errors.rb +62 -0
- data/lib/notion_publish/fixups.rb +139 -0
- data/lib/notion_publish/links.rb +65 -0
- data/lib/notion_publish/log.rb +49 -0
- data/lib/notion_publish/manifest.rb +224 -0
- data/lib/notion_publish/media.rb +90 -0
- data/lib/notion_publish/notion_digest.rb +23 -0
- data/lib/notion_publish/pool.rb +103 -0
- data/lib/notion_publish/progress.rb +103 -0
- data/lib/notion_publish/property_set.rb +116 -0
- data/lib/notion_publish/publisher.rb +475 -0
- data/lib/notion_publish/reference.rb +84 -0
- data/lib/notion_publish/resolver.rb +216 -0
- data/lib/notion_publish/schema.rb +206 -0
- data/lib/notion_publish/settings.rb +73 -0
- data/lib/notion_publish/sharing.rb +47 -0
- data/lib/notion_publish/status.rb +127 -0
- data/lib/notion_publish/target.rb +34 -0
- data/lib/notion_publish/uploader.rb +85 -0
- data/lib/notion_publish/users.rb +49 -0
- data/lib/notion_publish/version.rb +5 -0
- data/lib/notion_publish.rb +31 -0
- metadata +96 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5a9b4306daec96d259c074e2386d006468f5adc2500764b8559b1b65c169e1ba
|
|
4
|
+
data.tar.gz: 7015f9427836474584cb1665f81d509bda08e74329b653eda7b5692ce1daa740
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c78e9ab6ef5ad4c8e428208bf878c0c89fffd8fdbfdd896e326a7e640e31713c8beab0ad2683677a04b03e0f5db87052bd09dd66ddb525fc65a77e800abe009e
|
|
7
|
+
data.tar.gz: ee0afe9af082ac9dbc238146b2f8d12037d9b3f1ce6d247e1552a1ecc130d8b18e713d2374f1ca4050b3edc41bf5b0bf5a97cf24523a9e7b115ca61998f1c7f3
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are recorded here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-09-26
|
|
8
|
+
|
|
9
|
+
First public release.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Publish a Markdown file to a Notion page, database, or data source, named by ID, URL, or exact
|
|
14
|
+
database name. Notion does the Markdown conversion.
|
|
15
|
+
- Update the same page in place on later runs. `notion-publish-manifest.yml`, which you commit,
|
|
16
|
+
records which page each file became, so a tracked file needs no destination.
|
|
17
|
+
- `republish [DIR]` updates every page the manifest tracks, from each file's front matter plus the
|
|
18
|
+
`--title` and `--keep-h1` it was last published with. Properties set with flags are left alone.
|
|
19
|
+
- Set database properties from front matter, `--properties-json`, or `--property`, validated
|
|
20
|
+
against the live schema before anything is written. Properties the tool set before and no longer
|
|
21
|
+
sets are cleared; properties it never set are left alone.
|
|
22
|
+
- Detect edits made in Notion since the last publish, and pages moved to Notion's trash. An edited
|
|
23
|
+
page stops the publish with exit code 3 unless `--force` is given; a trashed page is published
|
|
24
|
+
afresh.
|
|
25
|
+
- Upload local images, including images under list items, and place them as image blocks.
|
|
26
|
+
- Join hard-wrapped lines before sending, since Notion makes a block of each line.
|
|
27
|
+
- Rewrite links between published documents to their Notion URLs, with `relink` for a second pass.
|
|
28
|
+
- Page icon and cover from an emoji, URL, or local file.
|
|
29
|
+
- `status`, `relink`, `adopt`, and `properties` subcommands.
|
|
30
|
+
- Check three pages at a time in `republish`, `status`, and `relink`; `-j`/`--jobs` changes the
|
|
31
|
+
number. A progress line appears when stderr is a terminal.
|
|
32
|
+
- Output lists only files where something happened. `-v` lists every file, `-vv` logs each API
|
|
33
|
+
request, and `-vvv` adds shortened bodies. The token is never logged.
|
|
34
|
+
- `--dry-run` and `--json` output for scripts and CI.
|
|
35
|
+
|
|
36
|
+
[0.1.0]: https://github.com/outsidecto/notion-publish/releases/tag/v0.1.0
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Outside CTO
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# notion-publish
|
|
2
|
+
|
|
3
|
+
[](https://github.com/outsidecto/notion-publish/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
Keep Notion pages in step with Markdown files in a Git repository.
|
|
6
|
+
|
|
7
|
+
Many teams write their documents in Git, where changes are reviewed and every version is kept. The
|
|
8
|
+
people who read those documents often work in Notion. `notion-publish` publishes each Markdown file
|
|
9
|
+
as a Notion page, and later runs update the same page in place. Git stays the source of truth, and
|
|
10
|
+
Notion shows a current copy.
|
|
11
|
+
|
|
12
|
+
```console
|
|
13
|
+
$ notion-publish policies/access-control.md --parent Policies --link
|
|
14
|
+
Published policies/access-control.md to database "Policies" (2efab123-...)
|
|
15
|
+
https://app.notion.com/p/Access-Control-Policy-3cfab123cd45818b9a72c2bd16e85a62
|
|
16
|
+
|
|
17
|
+
$ notion-publish policies/access-control.md
|
|
18
|
+
Unchanged policies/access-control.md
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## What it does
|
|
22
|
+
|
|
23
|
+
- **Updates pages in place.** A committed file, `notion-publish-manifest.yml`, records which page
|
|
24
|
+
each file became. Republishing replaces the page body and keeps its URL, so links to it keep
|
|
25
|
+
working.
|
|
26
|
+
- **Republishes everything it tracks** with one command, `notion-publish republish`, using what it
|
|
27
|
+
recorded about each file.
|
|
28
|
+
- **Protects edits made in Notion.** If someone edited the page in Notion since the last publish,
|
|
29
|
+
the tool stops and exits with code 3 rather than overwriting their work.
|
|
30
|
+
- **Sets database properties** from front matter or flags. Values are checked against the database
|
|
31
|
+
schema before anything is written, so a typo in a select option fails instead of creating a new
|
|
32
|
+
option.
|
|
33
|
+
- **Rewrites links between documents** to their Notion URLs.
|
|
34
|
+
- **Uploads local images** and places them in the page.
|
|
35
|
+
- **Fixes wrapped text.** Notion treats each line of a hard-wrapped paragraph as its own block. The
|
|
36
|
+
tool joins the lines first.
|
|
37
|
+
- **Reports drift.** `notion-publish status` lists files changed locally, pages changed in Notion
|
|
38
|
+
or moved to Notion's trash, and files that were never published.
|
|
39
|
+
|
|
40
|
+
Notion does the Markdown conversion itself, through its
|
|
41
|
+
[Markdown API](https://developers.notion.com/). The gem has no runtime dependencies beyond the Ruby
|
|
42
|
+
standard library.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
Requires Ruby 3.2 or later.
|
|
47
|
+
|
|
48
|
+
gem install notion_publish
|
|
49
|
+
|
|
50
|
+
Or add it to a Gemfile:
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
gem "notion_publish", require: false
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
1. **Create a connection.** Go to
|
|
59
|
+
[notion.so/profile/integrations](https://www.notion.so/profile/integrations), create an internal
|
|
60
|
+
connection, and give it the Read, Update, and Insert content capabilities. Copy the token.
|
|
61
|
+
|
|
62
|
+
2. **Share a destination with it.** In Notion, open the page or database you will publish into,
|
|
63
|
+
choose **••• → Connections**, and add your connection.
|
|
64
|
+
|
|
65
|
+
3. **Set the token.**
|
|
66
|
+
|
|
67
|
+
export NOTION_API_TOKEN=ntn_...
|
|
68
|
+
notion-publish --whoami
|
|
69
|
+
|
|
70
|
+
4. **Publish.** `--parent` takes a page or database ID, a Notion URL, or the exact name of a
|
|
71
|
+
database.
|
|
72
|
+
|
|
73
|
+
notion-publish docs/onboarding.md --link \
|
|
74
|
+
--parent 'https://app.notion.com/p/Team-Docs-2efab123...'
|
|
75
|
+
|
|
76
|
+
`--link` creates `notion-publish-manifest.yml` at the repository root. Commit it. Without it,
|
|
77
|
+
the next run cannot find the page and will create a second copy.
|
|
78
|
+
|
|
79
|
+
5. **Edit the file and publish again.** The page is updated in place.
|
|
80
|
+
|
|
81
|
+
## Keeping a repository in sync
|
|
82
|
+
|
|
83
|
+
Put the destination in a settings file, so it does not have to be typed each time. Settings apply
|
|
84
|
+
to the directory they are in and everything below it.
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
# policies/.notion-publish.yml
|
|
88
|
+
database: Policies
|
|
89
|
+
icon: 📘
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Set database properties in each file's front matter:
|
|
93
|
+
|
|
94
|
+
```markdown
|
|
95
|
+
---
|
|
96
|
+
properties:
|
|
97
|
+
Owner: Jane Doe
|
|
98
|
+
Status: Approved
|
|
99
|
+
Review Date: 2027-01-15
|
|
100
|
+
---
|
|
101
|
+
# Access Control Policy
|
|
102
|
+
...
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The first time, publish the directory with a loop. Then run `relink` to fix links to documents
|
|
106
|
+
that were published later in the loop:
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
for f in policies/*.md; do
|
|
110
|
+
notion-publish "$f" --link
|
|
111
|
+
done
|
|
112
|
+
notion-publish relink
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
After that, one command updates every page the manifest tracks:
|
|
116
|
+
|
|
117
|
+
```console
|
|
118
|
+
$ notion-publish republish
|
|
119
|
+
Updated policies/incident-response.md to database "Policies" (2efab123-...)
|
|
120
|
+
https://app.notion.com/p/Incident-Response-Policy-...
|
|
121
|
+
12 documents: 11 unchanged, 1 updated
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Only files where something happened are listed. `-v` lists every file. In a terminal, a progress
|
|
125
|
+
line shows which file is being checked while it runs.
|
|
126
|
+
|
|
127
|
+
`republish` needs no file names and no destination. Each page is updated where it already is, from
|
|
128
|
+
the file's current front matter plus any `--title` or `--keep-h1` it was last published with.
|
|
129
|
+
Properties that were set with `--property` are left as they are. A new file is not picked up until
|
|
130
|
+
you publish it once by name.
|
|
131
|
+
|
|
132
|
+
Check where things stand at any time:
|
|
133
|
+
|
|
134
|
+
```console
|
|
135
|
+
$ notion-publish status
|
|
136
|
+
/repo/notion-publish-manifest.yml -- 12 tracked
|
|
137
|
+
|
|
138
|
+
Changed locally (1)
|
|
139
|
+
policies/access-control.md
|
|
140
|
+
|
|
141
|
+
Changed in Notion (1)
|
|
142
|
+
policies/incident-response.md
|
|
143
|
+
https://app.notion.com/p/...
|
|
144
|
+
|
|
145
|
+
10 in sync, 1 changed locally, 1 changed in Notion
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`status -v` also lists the documents that are in sync.
|
|
149
|
+
|
|
150
|
+
### Publishing from GitHub Actions
|
|
151
|
+
|
|
152
|
+
This workflow republishes on every push to `main` and commits the updated manifest back.
|
|
153
|
+
Store the token as a repository secret named `NOTION_API_TOKEN`.
|
|
154
|
+
|
|
155
|
+
```yaml
|
|
156
|
+
name: Publish to Notion
|
|
157
|
+
|
|
158
|
+
on:
|
|
159
|
+
push:
|
|
160
|
+
branches: [main]
|
|
161
|
+
paths: ["policies/**.md"]
|
|
162
|
+
|
|
163
|
+
permissions:
|
|
164
|
+
contents: write
|
|
165
|
+
|
|
166
|
+
jobs:
|
|
167
|
+
publish:
|
|
168
|
+
runs-on: ubuntu-latest
|
|
169
|
+
steps:
|
|
170
|
+
- uses: actions/checkout@v5
|
|
171
|
+
- uses: ruby/setup-ruby@v1
|
|
172
|
+
with:
|
|
173
|
+
ruby-version: "3.4"
|
|
174
|
+
- run: gem install notion_publish
|
|
175
|
+
- name: Republish
|
|
176
|
+
env:
|
|
177
|
+
NOTION_API_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
|
178
|
+
run: notion-publish republish
|
|
179
|
+
- name: Commit notion-publish-manifest.yml
|
|
180
|
+
if: success() || failure()
|
|
181
|
+
run: |
|
|
182
|
+
git config user.name "github-actions[bot]"
|
|
183
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
184
|
+
git add notion-publish-manifest.yml
|
|
185
|
+
if ! git diff --cached --quiet; then
|
|
186
|
+
git commit -m "Record published Notion pages"
|
|
187
|
+
git push
|
|
188
|
+
fi
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
If a page was edited in Notion, `republish` leaves it alone and exits with code 3, which fails the
|
|
192
|
+
job. The other files still publish. Look at the page, move the change into the Markdown, and publish
|
|
193
|
+
that file with `--force`.
|
|
194
|
+
|
|
195
|
+
## Documentation
|
|
196
|
+
|
|
197
|
+
[docs/usage.md](docs/usage.md) is the full reference. It covers destinations, settings, every
|
|
198
|
+
property type, the manifest, adopting pages that already exist, images, exit codes, and JSON
|
|
199
|
+
output.
|
|
200
|
+
|
|
201
|
+
## Known limits
|
|
202
|
+
|
|
203
|
+
- A new file must be published once by name before `republish` includes it.
|
|
204
|
+
- Images inside a paragraph cannot be placed, since Notion has no inline images.
|
|
205
|
+
- Files over 20 MB are not uploaded, because Notion's multi-part upload is not implemented.
|
|
206
|
+
- H5 and H6 become heading 4 in Notion.
|
|
207
|
+
|
|
208
|
+
## Development
|
|
209
|
+
|
|
210
|
+
bundle install
|
|
211
|
+
bundle exec rake # tests and RuboCop
|
|
212
|
+
|
|
213
|
+
Tests use Minitest and WebMock and make no network calls. Bug reports and pull requests are welcome
|
|
214
|
+
at [github.com/outsidecto/notion-publish](https://github.com/outsidecto/notion-publish). To report a
|
|
215
|
+
security problem, see [SECURITY.md](SECURITY.md).
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT. See [LICENSE](LICENSE).
|
|
220
|
+
|
|
221
|
+
This project is not affiliated with or endorsed by Notion Labs, Inc.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# notion_publish
|
|
2
|
+
|
|
3
|
+
Many teams keep their important documents in Git, where changes get reviewed and every version is
|
|
4
|
+
kept. The people who read those documents often work in Notion instead. So somebody copies each
|
|
5
|
+
document over by hand, the two copies drift apart, and after a few months nobody can say which one
|
|
6
|
+
is current.
|
|
7
|
+
|
|
8
|
+
`notion_publish` is a command-line tool that publishes Markdown files from a Git repository into
|
|
9
|
+
Notion and then keeps those pages up to date. Git stays the authoritative copy. Notion shows a
|
|
10
|
+
current version of it.
|
|
11
|
+
|
|
12
|
+
It was built for a security and compliance corpus, where an auditor can reasonably ask which Notion
|
|
13
|
+
page corresponds to a given policy, and where "somebody pasted it in last spring" is not a good
|
|
14
|
+
answer.
|
|
15
|
+
|
|
16
|
+
## What it looks like
|
|
17
|
+
|
|
18
|
+
Publish a file. `--parent` takes a page ID, a Notion URL, or the exact name of a database:
|
|
19
|
+
|
|
20
|
+
$ notion-publish policies/access-control.md --parent 'Policies' --link
|
|
21
|
+
Published policies/access-control.md to database "Policies" (2efab123-...)
|
|
22
|
+
https://app.notion.com/p/Access-Control-Policy-3cfab123cd45818b9a72c2bd16e85a62
|
|
23
|
+
|
|
24
|
+
`--link` writes a file called `notion-publish-manifest.yml`, which records the page each document
|
|
25
|
+
became. You commit that file. From then on, one command brings every page up to date:
|
|
26
|
+
|
|
27
|
+
$ notion-publish republish
|
|
28
|
+
Updated policies/incident-response.md to database "Policies" (2efab123-...)
|
|
29
|
+
https://app.notion.com/p/Incident-Response-Policy-...
|
|
30
|
+
12 documents: 11 unchanged, 1 updated
|
|
31
|
+
|
|
32
|
+
Before publishing anything, you can ask what has moved apart:
|
|
33
|
+
|
|
34
|
+
$ notion-publish status
|
|
35
|
+
/repo/notion-publish-manifest.yml -- 12 tracked
|
|
36
|
+
|
|
37
|
+
Changed locally (1)
|
|
38
|
+
policies/access-control.md
|
|
39
|
+
|
|
40
|
+
Changed in Notion (1)
|
|
41
|
+
policies/incident-response.md
|
|
42
|
+
https://app.notion.com/p/...
|
|
43
|
+
|
|
44
|
+
10 in sync, 1 changed locally, 1 changed in Notion
|
|
45
|
+
|
|
46
|
+
`status` exits with code 3 when something needs a person to look at it, so it also works as a check
|
|
47
|
+
in continuous integration.
|
|
48
|
+
|
|
49
|
+
## The parts that are easy to get wrong
|
|
50
|
+
|
|
51
|
+
- **Updating instead of duplicating.** Because the manifest records which page each file became,
|
|
52
|
+
publishing again replaces that page's contents and keeps its URL. Links people have already
|
|
53
|
+
shared keep working.
|
|
54
|
+
- **Edits made in Notion.** The tool records what Notion returned after each publish and reads the
|
|
55
|
+
page again before the next one. If somebody edited the page, it stops and says so rather than
|
|
56
|
+
overwriting their work.
|
|
57
|
+
- **Pages deleted in Notion.** Deleting a page in Notion moves it to the trash, where the API still
|
|
58
|
+
returns it with all its content. The tool notices the difference and publishes a fresh page.
|
|
59
|
+
- **Database properties.** Values are checked against the live database schema before anything is
|
|
60
|
+
written, so a misspelled select option is an error instead of a brand-new option added to your
|
|
61
|
+
schema. Properties the tool set before and no longer sets are cleared; properties it never set are
|
|
62
|
+
left alone.
|
|
63
|
+
- **Links between documents.** A relative link to another Markdown file does not merely break in
|
|
64
|
+
Notion. Notion turns it into a link to a domain nobody owns. Links to published documents are
|
|
65
|
+
rewritten to their Notion URLs.
|
|
66
|
+
- **Local images.** Notion's Markdown import only understands images at public URLs, and a local
|
|
67
|
+
path produces an empty image block with no error at all. Local images are uploaded and placed as
|
|
68
|
+
real image blocks.
|
|
69
|
+
- **Hard-wrapped text.** Notion makes a separate block out of each line, so a file wrapped at a
|
|
70
|
+
column width arrives looking double-spaced. Wrapped paragraphs and list items are joined back
|
|
71
|
+
together first.
|
|
72
|
+
|
|
73
|
+
## Why another gem
|
|
74
|
+
|
|
75
|
+
Notion does not publish an official Ruby SDK. The client it maintains is for JavaScript.
|
|
76
|
+
|
|
77
|
+
Ruby has a dozen unofficial Notion gems, and they address two different problems. Most are API
|
|
78
|
+
clients that wrap the HTTP endpoints, and the widely used ones have not seen a release in some time:
|
|
79
|
+
`notion-ruby-client` last shipped in October 2023, `notion-sdk-ruby` in June 2022, and `notion` in
|
|
80
|
+
January 2021. Notion reorganized its data model in September 2025, when a database became a
|
|
81
|
+
container holding one or more data sources, and the schema and rows moved to the data source. A
|
|
82
|
+
client written before that models an API that no longer works the same way.
|
|
83
|
+
|
|
84
|
+
The gems that do handle Markdown run in the other direction. `notion_to_md` exports pages from
|
|
85
|
+
Notion into Markdown, and `notion_rails` renders Notion blocks as HTML inside a Rails application.
|
|
86
|
+
Both are useful. Neither publishes into Notion, and neither keeps a record of what was published,
|
|
87
|
+
which is the part that makes a second run safe instead of duplicating everything.
|
|
88
|
+
|
|
89
|
+
The conversion works differently here as well. Tools in this area usually build Notion's block JSON
|
|
90
|
+
themselves, which means carrying a Markdown parser and keeping it in step with Notion's block types.
|
|
91
|
+
`notion_publish` sends the Markdown and lets Notion parse it, using the Markdown parameter Notion's
|
|
92
|
+
own API accepts. Tables, nested lists, task lists, and fenced code arrive correctly because Notion
|
|
93
|
+
did that work. It is also why the gem has no runtime dependencies at all: the client is `Net::HTTP`
|
|
94
|
+
from the Ruby standard library.
|
|
95
|
+
|
|
96
|
+
## Getting it
|
|
97
|
+
|
|
98
|
+
Requires Ruby 3.2 or later.
|
|
99
|
+
|
|
100
|
+
gem install notion_publish
|
|
101
|
+
|
|
102
|
+
The source code, the full usage reference, and the issue tracker are on GitHub:
|
|
103
|
+
[github.com/outsidecto/notion-publish](https://github.com/outsidecto/notion-publish).
|
|
104
|
+
|
|
105
|
+
MIT licensed. This project is not affiliated with or endorsed by Notion Labs, Inc.
|