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
6 changes: 4 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ jobs:
SONARQUBE_CLI_DISTRIBUTION="$distribution" SONARQUBE_CLI_TARGET="$target" SONARQUBE_CLI_OUTFILE="dist/${filename}" bun build-scripts/build-binary.ts
}

for distribution in standalone homebrew; do
distributions=(standalone)

for distribution in "${distributions[@]}"; do
build_binary "$distribution" bun-linux-x64 linux-x86-64 bin
build_binary "$distribution" bun-linux-arm64 linux-arm64 bin
build_binary "$distribution" bun-darwin-arm64 macos-arm64 bin
Expand Down Expand Up @@ -279,7 +281,7 @@ jobs:
ARTIFACTORY_DEPLOY_REPO: sonarsource-public-qa
PROJECT: ${{ github.event.repository.name }}
BUILD_NUMBER: ${{ needs.prepare.outputs.BUILD_NUMBER }}
ARTIFACTS_TO_PUBLISH: 'org.sonarsource.cli:sonarqube-cli:bin:linux-x86-64,org.sonarsource.cli:sonarqube-cli:bin:linux-arm64,org.sonarsource.cli:sonarqube-cli:bin:macos-arm64,org.sonarsource.cli:sonarqube-cli:exe:windows-x86-64,org.sonarsource.cli:sonarqube-cli:bin:homebrew-linux-x86-64,org.sonarsource.cli:sonarqube-cli:bin:homebrew-linux-arm64,org.sonarsource.cli:sonarqube-cli:bin:homebrew-macos-arm64,org.sonarsource.cli:sonarqube-cli:exe:homebrew-windows-x86-64'
ARTIFACTS_TO_PUBLISH: 'org.sonarsource.cli:sonarqube-cli:bin:linux-x86-64,org.sonarsource.cli:sonarqube-cli:bin:linux-arm64,org.sonarsource.cli:sonarqube-cli:bin:macos-arm64,org.sonarsource.cli:sonarqube-cli:exe:windows-x86-64'
run: |
jf config add repox \
--artifactory-url="${ARTIFACTORY_URL}" \
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
A CLI tool (`sonar`) that integrates SonarQube Server and Cloud into developer workflows.

Release builds publish standalone executables for `linux-x86-64`, `linux-arm64`, `macos-arm64`, and `windows-x86-64`. binaries.sonarsource.com artifacts use the `.bin` suffix on Linux/macOS and `.exe` on Windows (e.g. `sonarqube-cli-{version}-linux-x86-64.bin`); versions published before that convention remain `.exe` on the CDN. Dependency binaries (sonar-secrets, sca-scanner-cli) still use `.exe` in download URLs. The stable installers (`user-scripts/install.sh`, `user-scripts/install.ps1`) resolve the real release version from `Distribution/sonarqube-cli/stable.version`; the shell installers select the Linux artifact using `uname -m` (`aarch64` / `arm64` → `linux-arm64`, `x86_64` / `amd64` → `linux-x86-64`) and try `.bin` then `.exe` when downloading. They also keep a literal compatibility version marker for older `sonar self-update` clients, and `full-release.yml` updates that marker to the latest released version during the post-release bump PR.
Compiled binaries are produced via `build-scripts/build-binary.ts`, which injects `SONARQUBE_CLI_DISTRIBUTION` at compile time. The only supported value is `standalone`, and standalone-only flows such as `self-update` key off that distribution marker.

# Running checks

Expand Down
4 changes: 2 additions & 2 deletions src/cli/command-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import { type Command, Help, InvalidArgumentError, Option } from 'commander';

import { version as VERSION } from '../../package.json';
import { IS_STANDALONE_DISTRIBUTION } from '../lib/distribution';
import { CURRENT_DISTRIBUTION } from '../lib/distribution';
import { loadState } from '../lib/repository/state-repository';
import { initSentry } from '../lib/sentry';
import { maybeNotifyUpdateAvailable } from '../lib/update-notification';
Expand Down Expand Up @@ -574,7 +574,7 @@ system
.anonymousAction((options: SystemResetOptions) => systemReset(options));

// Update the CLI to the latest version
if (IS_STANDALONE_DISTRIBUTION) {
if (CURRENT_DISTRIBUTION.enableSelfUpdate) {
COMMAND_TREE.command('self-update')
.description('Update SonarQube CLI to the latest version')
.rootHelp({
Expand Down
4 changes: 2 additions & 2 deletions src/cli/commands/system/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import type {
ProxyGroup,
ResolvedNetworkConfig,
} from '../../../lib/connectivity/types';
import { IS_STANDALONE_DISTRIBUTION } from '../../../lib/distribution';
import { CURRENT_DISTRIBUTION } from '../../../lib/distribution';
import {
CONTEXT_AUGMENTATION_BINARY_NAME,
SCA_SCANNER_BINARY_NAME,
Expand Down Expand Up @@ -362,7 +362,7 @@ function integrationConfigStatusLine(status: IntegrationConfigStatus): string {
}

async function getCliUpdateInfo(): Promise<CliUpdateInfo | null> {
if (!IS_STANDALONE_DISTRIBUTION) {
if (!CURRENT_DISTRIBUTION.enableSelfUpdate) {
return null;
}

Expand Down
25 changes: 19 additions & 6 deletions src/lib/distribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,23 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

export const DISTRIBUTIONS = ['standalone', 'homebrew'] as const;
export const DISTRIBUTIONS = ['standalone'] as const;
const DEFAULT_DISTRIBUTION = 'standalone';

export type Distribution = (typeof DISTRIBUTIONS)[number];

export interface DistributionConfig {
id: Distribution;
enableSelfUpdate: boolean;
}

const DISTRIBUTION_CONFIGS: Record<Distribution, DistributionConfig> = {
standalone: {
id: 'standalone',
enableSelfUpdate: true,
},
};

function invalidDistributionError(rawDistribution: string): Error {
return new Error(
`Unknown distribution '${rawDistribution}'. Expected one of: ${DISTRIBUTIONS.join(', ')}.`,
Expand All @@ -44,11 +56,12 @@ export function resolveDistribution(rawDistribution: string | undefined): Distri
return rawDistribution;
}

const rawDistribution = process.env.SONARQUBE_CLI_DISTRIBUTION;
if (rawDistribution !== undefined) {
assertDistribution(rawDistribution);
export function resolveDistributionConfig(rawDistribution: string | undefined): DistributionConfig {
return DISTRIBUTION_CONFIGS[resolveDistribution(rawDistribution)];
}

// Channel builds inject this env access at compile time via Bun's `define`.
export const DISTRIBUTION: Distribution = rawDistribution ?? DEFAULT_DISTRIBUTION;
export const IS_STANDALONE_DISTRIBUTION = DISTRIBUTION === 'standalone';
export const CURRENT_DISTRIBUTION = resolveDistributionConfig(
process.env.SONARQUBE_CLI_DISTRIBUTION,
);
export const DISTRIBUTION = CURRENT_DISTRIBUTION.id;
13 changes: 10 additions & 3 deletions tests/unit/lib/distribution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,27 @@

import { describe, expect, it } from 'bun:test';

import { resolveDistribution } from '../../../src/lib/distribution';
import { resolveDistribution, resolveDistributionConfig } from '../../../src/lib/distribution';

describe('distribution', () => {
it('defaults to standalone when no distribution is provided', () => {
expect(resolveDistribution(undefined)).toBe('standalone');
});

it('returns the configured distribution for known values', () => {
expect(resolveDistribution('homebrew')).toBe('homebrew');
expect(resolveDistribution('standalone')).toBe('standalone');
});

it('resolves centralized feature flags for the distribution', () => {
expect(resolveDistributionConfig(undefined)).toEqual({
id: 'standalone',
enableSelfUpdate: true,
});
});

it('throws for unknown values', () => {
expect(() => resolveDistribution('custom-channel')).toThrow(
"Unknown distribution 'custom-channel'. Expected one of: standalone, homebrew.",
"Unknown distribution 'custom-channel'. Expected one of: standalone.",
);
});
});