Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions docs/operator-manual/ui-customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ Would result in:

## CLI Download Links

The **Help** page (linked from the bottom of the sidebar) always shows a download button for the Linux CLI binary that is embedded in the Argo CD server, so users can fetch a working CLI without any configuration.
The **Help** page (linked from the bottom of the sidebar) links to the GitHub releases page for the running Argo CD version, where the CLI is available for all supported operating systems and architectures.

To offer the CLI for additional operating systems and architectures, set `help.download.<os>-<arch>` keys in the [argocd-cm](argocd-cm-yaml.md) ConfigMap. Each configured key adds a download button on the Help page pointing at the URL you provide:
To offer direct download buttons instead (for example an internal mirror, or air-gapped environments where GitHub is not reachable), set `help.download.<os>-<arch>` keys in the [argocd-cm](argocd-cm-yaml.md) ConfigMap. Each configured key adds a download button on the Help page pointing at the URL you provide. The Argo CD server also serves its own embedded Linux CLI binary at `download/argocd-linux-<arch>`, which can be used as a target for these keys:

```yaml
apiVersion: v1
Expand All @@ -48,6 +48,3 @@ The following `<os>-<arch>` keys are recognized; any other key is ignored:
- `darwin-amd64`
- `darwin-arm64`
- `windows-amd64`

> [!NOTE]
> The default Linux button is always shown in addition to any configured links, so configuring `help.download.linux-<arch>` for the server's own architecture results in two Linux buttons.
13 changes: 13 additions & 0 deletions ui/src/app/help/components/help.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {cliDownloadURL, RELEASES_URL} from './help';

test('links released versions to their GitHub release tag', () => {
expect(cliDownloadURL('v3.4.1')).toBe(`${RELEASES_URL}/tag/v3.4.1`);
expect(cliDownloadURL('v3.4.0-rc1')).toBe(`${RELEASES_URL}/tag/v3.4.0-rc1`);
});

test('falls back to the releases list for dev builds and unknown versions', () => {
expect(cliDownloadURL('v3.5.0+0dc5b3f')).toBe(RELEASES_URL);
expect(cliDownloadURL('')).toBe(RELEASES_URL);
expect(cliDownloadURL(undefined as unknown as string)).toBe(RELEASES_URL);
expect(cliDownloadURL('latest')).toBe(RELEASES_URL);
});
29 changes: 16 additions & 13 deletions ui/src/app/help/components/help.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ import classNames from 'classnames';

require('./help.scss');

export const RELEASES_URL = 'https://github.com/argoproj/argo-cd/releases';

// Released versions ("v3.4.1", "v3.4.0-rc1") link to their release tag; dev builds
// ("v3.5.0+0dc5b3f") and unknown versions fall back to the releases list.
export const cliDownloadURL = (version: string): string => {
const tag = (version || '').trim();
return /^v\d+\.\d+\.\d+(-[0-9A-Za-z.]+)?$/.test(tag) ? `${RELEASES_URL}/tag/${tag}` : RELEASES_URL;
};

export const Help = () => {
return (
<DataLoader
Expand All @@ -16,19 +25,17 @@ export const Help = () => {
// with `undefined` when every source completes (as these promise-backed ones do).
const [settings, version] = await Promise.all([
services.authService.settings(),
// Best-effort, informative only: the download link below is arch-agnostic, so the
// arch is just label text.
services.version.version().catch(() => ({Platform: ''}) as VersionMessage)
// Best-effort: an unknown version just links to the releases list.
services.version.version().catch(() => ({Version: ''}) as VersionMessage)
]);
return {
binaryUrls: settings.help.binaryUrls || {},
// Platform is "<os>/<arch>" (e.g. "linux/amd64"); may be empty.
hostArch: (version.Platform || '').split('/')[1] || ''
downloadURL: cliDownloadURL(version.Version)
};
}}>
{(settings?: {binaryUrls: Record<string, string>; hostArch: string}) => {
{(settings?: {binaryUrls: Record<string, string>; downloadURL: string}) => {
const binaryUrls = settings?.binaryUrls || {};
const hostArch = settings?.hostArch || '';
const downloadURL = settings?.downloadURL || RELEASES_URL;
return (
<Consumer>
{() => (
Expand All @@ -45,12 +52,8 @@ export const Help = () => {
<div className='columns large-4 small-6'>
<div className='help-box'>
<p>Want to download the CLI tool?</p>
{/* Arch-agnostic link: targets the suffix-less /argocd-linux route, which every
server serves from its own embedded binary regardless of the server's architecture.
This keeps the UI bundle architecture-independent (no arch baked in) and avoids
404s on mixed-arch clusters. The arch label is informational only, shown when known. */}
<a href='download/argocd-linux' className='user-info-panel-buttons argo-button argo-button--base'>
<i className='fab fa-linux' /> Linux{hostArch && ` (${hostArch})`}
<a href={downloadURL} target='_blank' rel='noopener noreferrer' className='user-info-panel-buttons argo-button argo-button--base'>
<i className='fab fa-github' /> GitHub releases
</a>
&nbsp;
{Object.keys(binaryUrls || {}).map(binaryName => {
Expand Down
Loading