Skip to content

Commit 3a449a5

Browse files
authored
docs: add documentation versioning support (#674)
## Summary - Add Docusaurus versioning support. - Add manual snapshot for the latest stable version - `version-2.5`. - Update the release workflow and `pyproject.toml` to automate doc version creation on stable releases (minor and major, patch just overrides the latest one). ### Issues - apify/crawlee-python#1302 ## Test plan - [x] Manual local build - [x] CI passes
1 parent 5b57ff3 commit 3a449a5

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

+39455
-3
lines changed

.github/workflows/manual_release_stable.yaml

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,75 @@ 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+
MAJOR_MINOR="$(echo "$VERSION" | cut -d. -f1-2)"
150+
export MAJOR_MINOR
151+
rm -rf "versioned_docs/version-${MAJOR_MINOR}"
152+
rm -rf "versioned_sidebars/version-${MAJOR_MINOR}-sidebars.json"
153+
jq 'map(select(. != env.MAJOR_MINOR))' versions.json > tmp.json && mv tmp.json versions.json
154+
bash build_api_reference.sh
155+
npx docusaurus docs:version "$MAJOR_MINOR"
156+
npx docusaurus api:version "$MAJOR_MINOR"
157+
158+
- name: Commit and push the version snapshot
159+
uses: EndBug/add-and-commit@v9
160+
with:
161+
author_name: Apify Release Bot
162+
author_email: noreply@apify.com
163+
message: "docs: update versioned docs for ${{ needs.release_prepare.outputs.version_number }}"
164+
105165
doc_release:
106166
name: Doc release
107-
needs: [changelog_update, pypi_publish]
167+
needs: [changelog_update, pypi_publish, version_docs]
108168
permissions:
109169
contents: write
110170
pages: write
111171
id-token: write
112172
uses: ./.github/workflows/_release_docs.yaml
113173
with:
114-
# Use the ref from the changelog update to include the updated changelog.
115-
ref: ${{ needs.changelog_update.outputs.changelog_commitish }}
174+
# Use the default branch to include both the changelog update and the versioned docs snapshot.
175+
ref: ${{ github.event.repository.default_branch }}
116176
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)