feat: use version service for docs archive switcher (#30675)

This commit is contained in:
bo0tzz 2026-08-12 13:36:33 +02:00 committed by GitHub
parent 199723261c
commit 0344c61e4c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 6 additions and 399 deletions

View file

@ -2,6 +2,8 @@ import { useWindowSize } from '@docusaurus/theme-common';
import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem'; import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
const ARCHIVED_VERSIONS_URL = 'https://version.immich.cloud/v1/docs/versions';
export default function VersionSwitcher(): JSX.Element { export default function VersionSwitcher(): JSX.Element {
const [versions, setVersions] = useState([]); const [versions, setVersions] = useState([]);
const [activeLabel, setLabel] = useState('Versions'); const [activeLabel, setLabel] = useState('Versions');
@ -11,12 +13,7 @@ export default function VersionSwitcher(): JSX.Element {
useEffect(() => { useEffect(() => {
async function getVersions() { async function getVersions() {
try { try {
let baseUrl = 'https://docs.immich.app'; const response = await fetch(ARCHIVED_VERSIONS_URL);
if (window.location.origin === 'http://localhost:3005') {
baseUrl = window.location.origin;
}
const response = await fetch(`${baseUrl}/archived-versions.json`);
const archiveVersions = await response.json(); const archiveVersions = await response.json();

View file

@ -1,3 +1,4 @@
/archived-versions.json https://version.immich.cloud/v1/docs/versions 307
/ /overview/quick-start 307 / /overview/quick-start 307
/mobile-app-beta-program /features/mobile-app 307 /mobile-app-beta-program /features/mobile-app 307
/contribution-guidelines /overview/support-the-project#contributing 307 /contribution-guidelines /overview/support-the-project#contributing 307

View file

@ -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"
}
]

View file

@ -1,23 +1,10 @@
import semver from 'semver'; import semver from 'semver';
import { beforeEach, describe, expect, it, vi } from 'vitest'; import { describe, expect, it } from 'vitest';
import { import { getMobileBuild, getNewVersion, ReleaseError } from './release';
resolveArchivedVersions,
ArchivedVersion,
getMobileBuild,
getNewVersion,
ReleaseError,
} from './release';
const mobileBuild = (version: string) => const mobileBuild = (version: string) =>
getMobileBuild(semver.parse(version) as semver.SemVer); 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(getNewVersion.name, () => {
describe('transitions', () => { describe('transitions', () => {
const valid = [ 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, () => { describe(getMobileBuild.name, () => {
it('should encode the version', () => { it('should encode the version', () => {
expect(mobileBuild('3.1.0')).toBe(3_010_099); expect(mobileBuild('3.1.0')).toBe(3_010_099);

View file

@ -26,7 +26,6 @@ const Files = {
Docs: { Docs: {
Env: join(root, 'docs/docs/install/environment-variables.md'), Env: join(root, 'docs/docs/install/environment-variables.md'),
Upgrading: join(root, 'docs/docs/install/upgrading.md'), Upgrading: join(root, 'docs/docs/install/upgrading.md'),
ArchivedVersions: join(root, 'docs/static/archived-versions.json'),
}, },
Mobile: { Mobile: {
Pubspec: join(root, 'mobile/pubspec.yaml'), Pubspec: join(root, 'mobile/pubspec.yaml'),
@ -92,13 +91,6 @@ export const handleRelease = ({ type }: ReleaseOptions) => {
pump(Files.Docs.Upgrading, /:v\d+/, `:${major}`); pump(Files.Docs.Upgrading, /:v\d+/, `:${major}`);
} }
// update archived versions list
const archivedFile = new JsonFile<ArchivedVersion[]>(
Files.Docs.ArchivedVersions,
);
const versions = archivedFile.read();
archivedFile.write(resolveArchivedVersions(versions, newVersionRaw));
if (process.env.GITHUB_ENV) { if (process.env.GITHUB_ENV) {
// make available for following steps // make available for following steps
appendFileSync( appendFileSync(
@ -222,50 +214,6 @@ const pump = (path: string, pattern: RegExp, replacement: string) => {
file.write(update); 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; const isPrerelease = (version: SemVer) => version.prerelease.length > 0;
/** /**