Skip to content

Commit 375efaa

Browse files
vdusekclaude
andcommitted
docs: add documentation versioning support
Add Docusaurus documentation versioning to store the last stable version docs (v2.5) alongside "next" for unreleased features. This includes the version dropdown in the navbar, versioned docs/sidebars/API reference snapshots, a CI workflow step to automatically version docs on release, and extended ty/ruff overrides for versioned doc code samples. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5b57ff3 commit 375efaa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+39454
-3
lines changed

.github/workflows/manual_release_stable.yaml

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,74 @@ jobs:
102102
- name: Publish package to PyPI
103103
uses: pypa/gh-action-pypi-publish@release/v1
104104

105+
version_docs:
106+
name: Version docs
107+
needs: [release_prepare, changelog_update, pypi_publish]
108+
runs-on: ubuntu-latest
109+
permissions:
110+
contents: write
111+
env:
112+
NODE_VERSION: 22
113+
PYTHON_VERSION: 3.14
114+
115+
steps:
116+
- name: Checkout repository
117+
uses: actions/checkout@v6
118+
with:
119+
ref: ${{ github.event.repository.default_branch }}
120+
token: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
121+
122+
- name: Set up Node
123+
uses: actions/setup-node@v6
124+
with:
125+
node-version: ${{ env.NODE_VERSION }}
126+
127+
- name: Set up Python
128+
uses: actions/setup-python@v6
129+
with:
130+
python-version: ${{ env.PYTHON_VERSION }}
131+
132+
- name: Set up uv package manager
133+
uses: astral-sh/setup-uv@v7
134+
with:
135+
python-version: ${{ env.PYTHON_VERSION }}
136+
137+
- name: Install Python dependencies
138+
run: uv run poe install-dev
139+
140+
- name: Install website dependencies
141+
run: |
142+
cd website
143+
yarn install
144+
145+
- name: Snapshot the current version
146+
run: |
147+
cd website
148+
VERSION=$(python -c "import tomllib, pathlib; print(tomllib.loads(pathlib.Path('../pyproject.toml').read_text())['project']['version'])")
149+
export MAJOR_MINOR=$(echo $VERSION | cut -d. -f1-2)
150+
rm -rf versioned_docs/version-$MAJOR_MINOR
151+
rm -rf versioned_sidebars/version-$MAJOR_MINOR-sidebars.json
152+
jq 'map(select(. != env.MAJOR_MINOR))' versions.json > tmp.json && mv tmp.json versions.json
153+
bash build_api_reference.sh
154+
npx docusaurus docs:version $MAJOR_MINOR
155+
npx docusaurus api:version $MAJOR_MINOR
156+
157+
- name: Commit and push the version snapshot
158+
uses: EndBug/add-and-commit@v9
159+
with:
160+
author_name: Apify Release Bot
161+
author_email: noreply@apify.com
162+
message: "docs: update versioned docs for ${{ needs.release_prepare.outputs.version_number }}"
163+
105164
doc_release:
106165
name: Doc release
107-
needs: [changelog_update, pypi_publish]
166+
needs: [changelog_update, pypi_publish, version_docs]
108167
permissions:
109168
contents: write
110169
pages: write
111170
id-token: write
112171
uses: ./.github/workflows/_release_docs.yaml
113172
with:
114-
# Use the ref from the changelog update to include the updated changelog.
115-
ref: ${{ needs.changelog_update.outputs.changelog_commitish }}
173+
# Use the default branch to include both the changelog update and the versioned docs snapshot.
174+
ref: ${{ github.event.repository.default_branch }}
116175
secrets: inherit

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ include = [
7878
"docs/**/*.py",
7979
"website/**/*.py",
8080
]
81+
exclude = [
82+
"website/versioned_docs/**",
83+
]
8184

8285
[tool.ruff.lint]
8386
select = ["ALL"]
@@ -181,6 +184,7 @@ python-version = "3.11"
181184

182185
[tool.ty.src]
183186
include = ["src", "tests", "scripts", "docs", "website"]
187+
exclude = ["website/versioned_docs"]
184188

185189
[[tool.ty.overrides]]
186190
include = ["docs/**/*.py", "website/**/*.py"]

website/docusaurus.config.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { config } = require('@apify/docs-theme');
44

55
const { externalLinkProcessor } = require('./tools/utils/externalLink');
66
const { groupSort } = require('./transformDocs.js');
7+
const versions = require('./versions.json');
78

89
const { absoluteUrl } = config;
910

@@ -67,6 +68,17 @@ module.exports = {
6768
label: 'GitHub',
6869
position: 'left',
6970
},
71+
{
72+
type: 'docsVersionDropdown',
73+
position: 'left',
74+
className: 'navbar__item',
75+
'data-api-links': JSON.stringify([
76+
'reference/next',
77+
...versions.map((version, i) => (i === 0 ? 'reference' : `reference/${version}`)),
78+
]),
79+
dropdownItemsBefore: [],
80+
dropdownItemsAfter: [],
81+
},
7082
],
7183
},
7284
},
@@ -124,13 +136,20 @@ module.exports = {
124136
includeGeneratedIndex: false,
125137
includePages: true,
126138
relativePaths: false,
139+
excludeRoutes: [
140+
'/api/client/python/reference/[0-9]*/**',
141+
'/api/client/python/reference/[0-9]*',
142+
'/api/client/python/reference/next/**',
143+
'/api/client/python/reference/next',
144+
],
127145
},
128146
},
129147
],
130148
...config.plugins,
131149
],
132150
themeConfig: {
133151
...config.themeConfig,
152+
versions,
134153
tableOfContents: {
135154
...config.themeConfig.tableOfContents,
136155
maxHeadingLevel: 5,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
changelog.md
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from apify_client import ApifyClientAsync
2+
3+
# You can find your API token at https://console.apify.com/settings/integrations.
4+
TOKEN = 'MY-APIFY-TOKEN'
5+
6+
7+
async def main() -> None:
8+
apify_client = ApifyClientAsync(TOKEN)
9+
10+
# Start an Actor and wait for it to finish.
11+
actor_client = apify_client.actor('john-doe/my-cool-actor')
12+
call_result = await actor_client.call()
13+
14+
if call_result is None:
15+
print('Actor run failed.')
16+
return
17+
18+
# Fetch results from the Actor run's default dataset.
19+
dataset_client = apify_client.dataset(call_result.default_dataset_id)
20+
list_items_result = await dataset_client.list_items()
21+
print(f'Dataset: {list_items_result}')
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from apify_client import ApifyClient
2+
3+
# You can find your API token at https://console.apify.com/settings/integrations.
4+
TOKEN = 'MY-APIFY-TOKEN'
5+
6+
7+
def main() -> None:
8+
apify_client = ApifyClient(TOKEN)
9+
10+
# Start an Actor and wait for it to finish.
11+
actor_client = apify_client.actor('john-doe/my-cool-actor')
12+
call_result = actor_client.call()
13+
14+
if call_result is None:
15+
print('Actor run failed.')
16+
return
17+
18+
# Fetch results from the Actor run's default dataset.
19+
dataset_client = apify_client.dataset(call_result.default_dataset_id)
20+
list_items_result = dataset_client.list_items()
21+
print(f'Dataset: {list_items_result}')
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from apify_client import ApifyClientAsync
2+
3+
TOKEN = 'MY-APIFY-TOKEN'
4+
5+
6+
async def main() -> None:
7+
# Client initialization with the API token.
8+
apify_client = ApifyClientAsync(TOKEN)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from apify_client import ApifyClient
2+
3+
TOKEN = 'MY-APIFY-TOKEN'
4+
5+
6+
def main() -> None:
7+
# Client initialization with the API token.
8+
apify_client = ApifyClient(TOKEN)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from apify_client import ApifyClientAsync
2+
3+
TOKEN = 'MY-APIFY-TOKEN'
4+
5+
6+
async def main() -> None:
7+
apify_client = ApifyClientAsync(TOKEN)
8+
dataset_client = apify_client.dataset('dataset-id')
9+
10+
# Lists items from the Actor's dataset.
11+
dataset_items = (await dataset_client.list_items()).items
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from apify_client import ApifyClient
2+
3+
TOKEN = 'MY-APIFY-TOKEN'
4+
5+
6+
def main() -> None:
7+
apify_client = ApifyClient(TOKEN)
8+
dataset_client = apify_client.dataset('dataset-id')
9+
10+
# Lists items from the Actor's dataset.
11+
dataset_items = dataset_client.list_items().items

0 commit comments

Comments
 (0)