From 0344c61e4cee9cb2e8ee3ce2292177cd2b0c4129 Mon Sep 17 00:00:00 2001 From: bo0tzz Date: Wed, 12 Aug 2026 13:36:33 +0200 Subject: [PATCH] feat: use version service for docs archive switcher (#30675) --- docs/src/components/version-switcher.tsx | 9 +- docs/static/_redirects | 1 + docs/static/archived-versions.json | 265 ------------------ packages/scripts/src/commands/release.spec.ts | 78 +----- packages/scripts/src/commands/release.ts | 52 ---- 5 files changed, 6 insertions(+), 399 deletions(-) delete mode 100644 docs/static/archived-versions.json diff --git a/docs/src/components/version-switcher.tsx b/docs/src/components/version-switcher.tsx index 739d7bd001..967c85c780 100644 --- a/docs/src/components/version-switcher.tsx +++ b/docs/src/components/version-switcher.tsx @@ -2,6 +2,8 @@ import { useWindowSize } from '@docusaurus/theme-common'; import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem'; import React, { useEffect, useState } from 'react'; +const ARCHIVED_VERSIONS_URL = 'https://version.immich.cloud/v1/docs/versions'; + export default function VersionSwitcher(): JSX.Element { const [versions, setVersions] = useState([]); const [activeLabel, setLabel] = useState('Versions'); @@ -11,12 +13,7 @@ export default function VersionSwitcher(): JSX.Element { useEffect(() => { async function getVersions() { try { - let baseUrl = 'https://docs.immich.app'; - if (window.location.origin === 'http://localhost:3005') { - baseUrl = window.location.origin; - } - - const response = await fetch(`${baseUrl}/archived-versions.json`); + const response = await fetch(ARCHIVED_VERSIONS_URL); const archiveVersions = await response.json(); diff --git a/docs/static/_redirects b/docs/static/_redirects index 633025ac17..e218124e59 100644 --- a/docs/static/_redirects +++ b/docs/static/_redirects @@ -1,3 +1,4 @@ +/archived-versions.json https://version.immich.cloud/v1/docs/versions 307 / /overview/quick-start 307 /mobile-app-beta-program /features/mobile-app 307 /contribution-guidelines /overview/support-the-project#contributing 307 diff --git a/docs/static/archived-versions.json b/docs/static/archived-versions.json deleted file mode 100644 index dbeed76b73..0000000000 --- a/docs/static/archived-versions.json +++ /dev/null @@ -1,265 +0,0 @@ -[ - { - "label": "v3.1.0", - "url": "https://docs.v3.1.0.archive.immich.app" - }, - { - "label": "v3.0.3", - "url": "https://docs.v3.0.3.archive.immich.app" - }, - { - "label": "v2.7.5", - "url": "https://docs.v2.7.5.archive.immich.app" - }, - { - "label": "v2.6.3", - "url": "https://docs.v2.6.3.archive.immich.app" - }, - { - "label": "v2.5.6", - "url": "https://docs.v2.5.6.archive.immich.app" - }, - { - "label": "v2.4.1", - "url": "https://docs.v2.4.1.archive.immich.app" - }, - { - "label": "v2.3.1", - "url": "https://docs.v2.3.1.archive.immich.app" - }, - { - "label": "v2.2.3", - "url": "https://docs.v2.2.3.archive.immich.app" - }, - { - "label": "v2.1.0", - "url": "https://docs.v2.1.0.archive.immich.app" - }, - { - "label": "v2.0.1", - "url": "https://docs.v2.0.1.archive.immich.app" - }, - { - "label": "v1.144.1", - "url": "https://docs.v1.144.1.archive.immich.app" - }, - { - "label": "v1.143.1", - "url": "https://docs.v1.143.1.archive.immich.app" - }, - { - "label": "v1.142.1", - "url": "https://v1.142.1.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.141.1", - "url": "https://v1.141.1.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.140.1", - "url": "https://v1.140.1.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.139.4", - "url": "https://v1.139.4.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.138.1", - "url": "https://v1.138.1.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.137.3", - "url": "https://v1.137.3.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.136.0", - "url": "https://v1.136.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.135.3", - "url": "https://v1.135.3.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.134.0", - "url": "https://v1.134.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.133.1", - "url": "https://v1.133.1.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.132.3", - "url": "https://v1.132.3.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.131.3", - "url": "https://v1.131.3.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.130.3", - "url": "https://v1.130.3.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.129.0", - "url": "https://v1.129.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.128.0", - "url": "https://v1.128.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.127.0", - "url": "https://v1.127.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.126.1", - "url": "https://v1.126.1.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.125.7", - "url": "https://v1.125.7.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.124.2", - "url": "https://v1.124.2.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.123.0", - "url": "https://v1.123.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.122.3", - "url": "https://v1.122.3.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.121.0", - "url": "https://v1.121.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.120.2", - "url": "https://v1.120.2.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.119.1", - "url": "https://v1.119.1.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.118.2", - "url": "https://v1.118.2.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.117.0", - "url": "https://v1.117.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.116.2", - "url": "https://v1.116.2.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.115.0", - "url": "https://v1.115.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.114.0", - "url": "https://v1.114.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.113.1", - "url": "https://v1.113.1.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.112.1", - "url": "https://v1.112.1.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.111.0", - "url": "https://v1.111.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.110.0", - "url": "https://v1.110.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.109.2", - "url": "https://v1.109.2.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.108.0", - "url": "https://v1.108.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.107.2", - "url": "https://v1.107.2.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.106.4", - "url": "https://v1.106.4.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.105.1", - "url": "https://v1.105.1.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.104.0", - "url": "https://v1.104.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.103.1", - "url": "https://v1.103.1.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.102.3", - "url": "https://v1.102.3.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.101.0", - "url": "https://v1.101.0.archive.immich.app", - "rootPath": "/docs" - }, - { - "label": "v1.100.0", - "url": "https://v1.100.0.archive.immich.app", - "rootPath": "/docs" - } -] diff --git a/packages/scripts/src/commands/release.spec.ts b/packages/scripts/src/commands/release.spec.ts index 0b1be22302..dc3f82517d 100644 --- a/packages/scripts/src/commands/release.spec.ts +++ b/packages/scripts/src/commands/release.spec.ts @@ -1,23 +1,10 @@ import semver from 'semver'; -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { - resolveArchivedVersions, - ArchivedVersion, - getMobileBuild, - getNewVersion, - ReleaseError, -} from './release'; +import { describe, expect, it } from 'vitest'; +import { getMobileBuild, getNewVersion, ReleaseError } from './release'; const mobileBuild = (version: string) => getMobileBuild(semver.parse(version) as semver.SemVer); -const archived = (label: string): ArchivedVersion => ({ - label, - url: `https://docs.${label}.archive.immich.app`, -}); - -const labels = (versions: ArchivedVersion[]) => versions.map((v) => v.label); - describe(getNewVersion.name, () => { describe('transitions', () => { const valid = [ @@ -82,67 +69,6 @@ describe(getNewVersion.name, () => { }); }); -describe(resolveArchivedVersions.name, () => { - beforeEach(() => { - // silence the "Removed ..." progress logging - vi.spyOn(console, 'log').mockImplementation(() => {}); - }); - - it('should prepend the new version to the front', () => { - const result = resolveArchivedVersions([archived('v2.9.0')], '3.0.0'); - - expect(result[0]).toEqual({ - label: 'v3.0.0', - url: 'https://docs.v3.0.0.archive.immich.app', - }); - expect(labels(result)).toEqual(['v3.0.0', 'v2.9.0']); - }); - - it('should handle an empty list', () => { - expect(labels(resolveArchivedVersions([], '3.0.0'))).toEqual(['v3.0.0']); - }); - - it('should drop older patch releases of the new version minor', () => { - const versions = ['v3.0.4', 'v3.0.3', 'v3.0.2'].map(archived); - - expect(labels(resolveArchivedVersions(versions, '3.0.5'))).toEqual([ - 'v3.0.5', - ]); - }); - - it('should keep the latest patch of each older minor', () => { - const versions = ['v3.1.2', 'v3.1.1', 'v3.0.9', 'v2.0.0'].map(archived); - - expect(labels(resolveArchivedVersions(versions, '3.2.0'))).toEqual([ - 'v3.2.0', - 'v3.1.2', - 'v3.0.9', - 'v2.0.0', - ]); - }); - - it('should keep an older minor when bumping a patch', () => { - const versions = ['v3.0.4', 'v3.0.3', 'v2.9.1', 'v2.9.0', 'v1.5.0'].map( - archived, - ); - - expect(labels(resolveArchivedVersions(versions, '3.0.5'))).toEqual([ - 'v3.0.5', - 'v2.9.1', - 'v1.5.0', - ]); - }); - - it('should replace a prerelease with its release', () => { - const versions = ['v3.0.0-rc.2', 'v3.0.0-rc.1', 'v2.9.0'].map(archived); - - expect(labels(resolveArchivedVersions(versions, '3.0.0'))).toEqual([ - 'v3.0.0', - 'v2.9.0', - ]); - }); -}); - describe(getMobileBuild.name, () => { it('should encode the version', () => { expect(mobileBuild('3.1.0')).toBe(3_010_099); diff --git a/packages/scripts/src/commands/release.ts b/packages/scripts/src/commands/release.ts index 307b66165a..2c0d82d5f6 100644 --- a/packages/scripts/src/commands/release.ts +++ b/packages/scripts/src/commands/release.ts @@ -26,7 +26,6 @@ const Files = { Docs: { Env: join(root, 'docs/docs/install/environment-variables.md'), Upgrading: join(root, 'docs/docs/install/upgrading.md'), - ArchivedVersions: join(root, 'docs/static/archived-versions.json'), }, Mobile: { Pubspec: join(root, 'mobile/pubspec.yaml'), @@ -92,13 +91,6 @@ export const handleRelease = ({ type }: ReleaseOptions) => { pump(Files.Docs.Upgrading, /:v\d+/, `:${major}`); } - // update archived versions list - const archivedFile = new JsonFile( - Files.Docs.ArchivedVersions, - ); - const versions = archivedFile.read(); - archivedFile.write(resolveArchivedVersions(versions, newVersionRaw)); - if (process.env.GITHUB_ENV) { // make available for following steps appendFileSync( @@ -222,50 +214,6 @@ const pump = (path: string, pattern: RegExp, replacement: string) => { file.write(update); }; -export interface ArchivedVersion { - label: string; - url: string; -} - -export const resolveArchivedVersions = ( - versions: ArchivedVersion[], - nextVersion: string, -): ArchivedVersion[] => { - const newVersion: ArchivedVersion = { - label: `v${nextVersion}`, - url: `https://docs.v${nextVersion}.archive.immich.app`, - }; - - let result = versions; - let lastVersion = asVersion(newVersion); - for (const item of versions) { - const version = asVersion(item); - // only keep the latest patch version for each minor release - if ( - lastVersion.major === version.major && - lastVersion.minor === version.minor && - lastVersion.patch >= version.patch - ) { - result = result.filter((item) => item.label !== version.label); - console.log( - `Removed ${version.label} (replaced with ${lastVersion.label})`, - ); - continue; - } - - lastVersion = version; - } - - return [newVersion, ...result]; -}; - -const asVersion = (item: ArchivedVersion) => { - const { label, url } = item; - const [version] = label.substring(1).split('-'); - const [major, minor, patch] = version.split('.').map(Number); - return { major, minor, patch, label, url }; -}; - const isPrerelease = (version: SemVer) => version.prerelease.length > 0; /**