Skip to content

Commit

Permalink
SCANNPM-2 Use axios instance to re-use fetching logic (#120)
Browse files Browse the repository at this point in the history
  • Loading branch information
7PH authored Apr 23, 2024
1 parent f8b76dd commit 6bad249
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 161 deletions.
33 changes: 0 additions & 33 deletions src/http-agent.ts

This file was deleted.

57 changes: 23 additions & 34 deletions src/java.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,10 @@ import {
SONARQUBE_JRE_PROVISIONING_MIN_VERSION,
UNARCHIVE_SUFFIX,
} from './constants';
import { getHttpAgents } from './http-agent';
import { extractArchive, getCachedFileLocation } from './file';
import { log, LogLevel } from './logging';
import { getProxyUrl } from './proxy';
import { fetch } from './request';
import { JREFullData, PlatformInfo, ScannerProperties, ScannerProperty } from './types';
import { extractArchive, getCachedFileLocation } from './file';

const finished = promisify(stream.finished);

Expand All @@ -52,24 +50,29 @@ export async function serverSupportsJREProvisioning(
log(LogLevel.DEBUG, 'Detecting SonarQube server version');
const SQServerInfo =
semver.coerce(parameters[ScannerProperty.SonarScannerInternalSqVersion]) ??
(await fetchServerVersion(parameters[ScannerProperty.SonarHostUrl], parameters));
(await fetchServerVersion());
log(LogLevel.INFO, 'SonarQube server version: ', SQServerInfo.version);

const supports = semver.satisfies(SQServerInfo, `>=${SONARQUBE_JRE_PROVISIONING_MIN_VERSION}`);
log(LogLevel.DEBUG, `SonarQube Server v${SQServerInfo} supports JRE provisioning: ${supports}`);
return supports;
}

async function fetchLatestSupportedJRE(properties: ScannerProperties, platformInfo: PlatformInfo) {
const serverUrl = properties[ScannerProperty.SonarHostUrl];
const token = properties[ScannerProperty.SonarToken];

const jreInfoUrl = `${serverUrl}/api/v2/analysis/jres?os=${platformInfo.os}&arch=${platformInfo.arch}`;
log(LogLevel.DEBUG, `Downloading JRE from: ${jreInfoUrl}`);
async function fetchLatestSupportedJRE(platformInfo: PlatformInfo) {
log(
LogLevel.DEBUG,
`Downloading JRE for ${platformInfo.os} ${platformInfo.arch} from ${API_V2_JRE_ENDPOINT}`,
);

const { data } = await fetch(token, { url: jreInfoUrl });
const { data } = await fetch({
url: API_V2_JRE_ENDPOINT,
params: {
os: platformInfo.os,
arch: platformInfo.arch,
},
});

log(LogLevel.DEBUG, 'file info: ', data);
log(LogLevel.DEBUG, 'JRE information: ', data);

return data;
}
Expand All @@ -78,11 +81,8 @@ export async function handleJREProvisioning(
properties: ScannerProperties,
platformInfo: PlatformInfo,
): Promise<JREFullData | undefined> {
const serverUrl = properties[ScannerProperty.SonarHostUrl];
const token = properties[ScannerProperty.SonarToken];

log(LogLevel.DEBUG, 'Detecting latest version of JRE');
const latestJREData = await fetchLatestSupportedJRE(properties, platformInfo);
const latestJREData = await fetchLatestSupportedJRE(platformInfo);
log(LogLevel.INFO, 'Latest Supported JRE: ', latestJREData);

log(LogLevel.DEBUG, 'Looking for Cached JRE');
Expand All @@ -91,8 +91,6 @@ export async function handleJREProvisioning(
latestJREData.filename + UNARCHIVE_SUFFIX,
);

const proxyUrl = getProxyUrl(properties);

if (cachedJRE) {
log(LogLevel.INFO, 'Using Cached JRE');
properties[ScannerProperty.SonarScannerWasJRECacheHit] = 'true';
Expand Down Expand Up @@ -120,14 +118,12 @@ export async function handleJREProvisioning(
}
const writer = fs.createWriteStream(archivePath);

const url = serverUrl + API_V2_JRE_ENDPOINT + `/${latestJREData.filename}`;
const url = `${API_V2_JRE_ENDPOINT}/${latestJREData.filename}`;
log(LogLevel.DEBUG, `Downloading ${url} to ${archivePath}`);

const response = await fetch(token, {
const response = await fetch({
url,
method: 'GET',
responseType: 'stream',
...getHttpAgents(proxyUrl),
});

const totalLength = response.headers['content-length'];
Expand Down Expand Up @@ -193,19 +189,13 @@ async function validateChecksum(filePath: string, expectedChecksum: string) {
}
}

export async function fetchServerVersion(
sonarHostUrl: string,
parameters: ScannerProperties,
): Promise<SemVer> {
const token = parameters[ScannerProperty.SonarToken];
const proxyUrl = getProxyUrl(parameters);
export async function fetchServerVersion(): Promise<SemVer> {
let version: SemVer | null = null;
try {
// Try and fetch the new version endpoint first
log(LogLevel.DEBUG, `Fetching API V2 ${API_V2_VERSION_ENDPOINT}`);
const response = await fetch(token, {
url: sonarHostUrl + API_V2_VERSION_ENDPOINT,
...getHttpAgents(proxyUrl),
const response = await fetch({
url: API_V2_VERSION_ENDPOINT,
});
version = semver.coerce(response.data);
} catch (error: unknown) {
Expand All @@ -215,9 +205,8 @@ export async function fetchServerVersion(
LogLevel.DEBUG,
`Unable to fetch API V2 ${API_V2_VERSION_ENDPOINT}: ${error}. Falling back on ${API_OLD_VERSION_ENDPOINT}`,
);
const response = await fetch(token, {
url: sonarHostUrl + API_OLD_VERSION_ENDPOINT,
...getHttpAgents(proxyUrl),
const response = await fetch({
url: API_OLD_VERSION_ENDPOINT,
});
version = semver.coerce(response.data);
} catch (error: unknown) {
Expand Down
50 changes: 42 additions & 8 deletions src/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,47 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import axios, { AxiosRequestConfig } from 'axios';
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
import { getProxyUrl } from './proxy';
import { ScannerProperties, ScannerProperty } from './types';

export function fetch(token: string, config: AxiosRequestConfig) {
return axios({
headers: {
Authorization: `Bearer ${token}`,
},
...config,
});
// The axios instance is private to this module
let _axiosInstance: AxiosInstance | null = null;

export function getHttpAgents(
properties: ScannerProperties,
): Pick<AxiosRequestConfig, 'httpAgent' | 'httpsAgent'> {
const agents: Pick<AxiosRequestConfig, 'httpAgent' | 'httpsAgent'> = {};
const proxyUrl = getProxyUrl(properties);

if (proxyUrl) {
agents.httpsAgent = new HttpsProxyAgent({ proxy: proxyUrl.toString() });
agents.httpAgent = new HttpProxyAgent({ proxy: proxyUrl.toString() });
}
return agents;
}

export function initializeAxios(properties: ScannerProperties) {
const token = properties[ScannerProperty.SonarToken];
const baseURL = properties[ScannerProperty.SonarHostUrl];
const agents = getHttpAgents(properties);

if (!_axiosInstance) {
_axiosInstance = axios.create({
baseURL,
headers: {
Authorization: `Bearer ${token}`,
},
...agents,
});
}
}

export function fetch(config: AxiosRequestConfig) {
if (!_axiosInstance) {
throw new Error('Axios instance is not initialized');
}

return _axiosInstance.request(config);
}
15 changes: 9 additions & 6 deletions src/scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,18 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import { version } from '../package.json';
import { handleJREProvisioning, serverSupportsJREProvisioning } from './java';
import { log, LogLevel, setLogLevel } from './logging';
import { LogLevel, log, setLogLevel } from './logging';
import { getPlatformInfo } from './platform';
import { getProperties } from './properties';
import { ScannerProperty, JreMetaData, ScanOptions } from './types';
import { version } from '../package.json';
import { initializeAxios } from './request';
import { JreMetaData, ScanOptions, ScannerProperty } from './types';

export async function scan(scanOptions: ScanOptions, cliArgs?: string[]) {
const startTimestampMs = Date.now();
const properties = getProperties(scanOptions, startTimestampMs, cliArgs);

const serverUrl = properties[ScannerProperty.SonarHostUrl];
const explicitJREPathOverride = properties[ScannerProperty.SonarScannerJavaExePath];

if (properties[ScannerProperty.SonarVerbose] === 'true') {
setLogLevel(LogLevel.DEBUG);
log(LogLevel.DEBUG, 'Setting the log level to DEBUG due to verbose mode');
Expand All @@ -42,6 +40,11 @@ export async function scan(scanOptions: ScanOptions, cliArgs?: string[]) {
log(LogLevel.DEBUG, `Overriding the log level to ${properties[ScannerProperty.SonarLogLevel]}`);
}

initializeAxios(properties);

const serverUrl = properties[ScannerProperty.SonarHostUrl];
const explicitJREPathOverride = properties[ScannerProperty.SonarScannerJavaExePath];

log(LogLevel.INFO, 'Version: ', version);

log(LogLevel.DEBUG, 'Finding platform info');
Expand Down
41 changes: 0 additions & 41 deletions test/unit/http-agent.test.ts

This file was deleted.

Loading

0 comments on commit 6bad249

Please sign in to comment.