Skip to content

Commit 1703dd6

Browse files
committed
chore(dep): replace axios with native fetch (phase 1)
1 parent d8e3f68 commit 1703dd6

File tree

145 files changed

+4624
-3344
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+4624
-3344
lines changed

.buildkite/pipeline-utils/buildkite/client.ts

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
* License v3.0 only", or the "Server Side Public License, v 1".
88
*/
99

10-
import type { AxiosInstance } from 'axios';
11-
import axios from 'axios';
1210
import type { ExecSyncOptions } from 'child_process';
1311
import { execFileSync, execSync } from 'child_process';
1412

@@ -162,35 +160,53 @@ export interface BuildkiteWaitStep {
162160
}
163161

164162
export class BuildkiteClient {
165-
http: AxiosInstance;
166163
exec: ExecType;
167164
baseUrl: string;
165+
private defaultHeaders: Record<string, string>;
168166

169167
constructor(config: BuildkiteClientConfig = {}) {
170168
const BUILDKITE_TOKEN = config.token ?? process.env.BUILDKITE_TOKEN;
171169

172170
this.baseUrl = config.baseUrl ?? process.env.BUILDKITE_BASE_URL ?? 'https://api.buildkite.com';
173171

174-
// const BUILDKITE_AGENT_BASE_URL =
175-
// process.env.BUILDKITE_AGENT_BASE_URL || 'https://agent.buildkite.com/v3';
176-
// const BUILDKITE_AGENT_TOKEN = process.env.BUILDKITE_AGENT_TOKEN;
172+
this.defaultHeaders = {
173+
Authorization: `Bearer ${BUILDKITE_TOKEN}`,
174+
};
175+
176+
this.exec = config.exec ?? execSync;
177+
}
178+
179+
private async httpGet<T = unknown>(path: string): Promise<{ data: T; headers: Headers }> {
180+
const url = `${this.baseUrl}/${path.replace(/^\//, '')}`;
181+
const resp = await fetch(url, {
182+
headers: this.defaultHeaders,
183+
});
177184

178-
this.http = axios.create({
179-
baseURL: this.baseUrl,
185+
if (!resp.ok) {
186+
throw new Error(`Buildkite API request failed: ${resp.status} ${resp.statusText}`);
187+
}
188+
189+
const data = (await resp.json()) as T;
190+
return { data, headers: resp.headers };
191+
}
192+
193+
private async httpPost<T = unknown>(path: string, body?: unknown): Promise<{ data: T }> {
194+
const url = `${this.baseUrl}/${path.replace(/^\//, '')}`;
195+
const resp = await fetch(url, {
196+
method: 'POST',
180197
headers: {
181-
Authorization: `Bearer ${BUILDKITE_TOKEN}`,
198+
'Content-Type': 'application/json',
199+
...this.defaultHeaders,
182200
},
183-
allowAbsoluteUrls: false,
201+
body: body ? JSON.stringify(body) : undefined,
184202
});
185203

186-
this.exec = config.exec ?? execSync;
204+
if (!resp.ok) {
205+
throw new Error(`Buildkite API request failed: ${resp.status} ${resp.statusText}`);
206+
}
187207

188-
// this.agentHttp = axios.create({
189-
// baseURL: BUILDKITE_AGENT_BASE_URL,
190-
// headers: {
191-
// Authorization: `Token ${BUILDKITE_AGENT_TOKEN}`,
192-
// },
193-
// });
208+
const data = (await resp.json()) as T;
209+
return { data };
194210
}
195211

196212
getBuild = async (
@@ -200,30 +216,30 @@ export class BuildkiteClient {
200216
): Promise<Build> => {
201217
// TODO properly assemble URL
202218
const link = `v2/organizations/elastic/pipelines/${pipelineSlug}/builds/${buildNumber}?include_retried_jobs=${includeRetriedJobs.toString()}`;
203-
const resp = await this.http.get(link);
204-
return resp.data as Build;
219+
const resp = await this.httpGet<Build>(link);
220+
return resp.data;
205221
};
206222

207223
getBuildsAfterDate = async (
208224
pipelineSlug: string,
209225
date: string,
210226
numberOfBuilds: number
211227
): Promise<Build[]> => {
212-
const response = await this.http.get(
228+
const response = await this.httpGet<Build[]>(
213229
`v2/organizations/elastic/pipelines/${pipelineSlug}/builds?created_from=${date}&per_page=${numberOfBuilds}`
214230
);
215-
return response.data as Build[];
231+
return response.data;
216232
};
217233

218234
getBuildForCommit = async (pipelineSlug: string, commit: string): Promise<Build | null> => {
219235
if (commit.length !== 40) {
220236
throw new Error(`Invalid commit hash: ${commit}, this endpoint works with full SHAs only`);
221237
}
222238

223-
const response = await this.http.get(
239+
const response = await this.httpGet<Build[]>(
224240
`v2/organizations/elastic/pipelines/${pipelineSlug}/builds?commit=${commit}`
225241
);
226-
const builds = response.data as Build[];
242+
const builds = response.data;
227243
if (builds.length === 0) {
228244
return null;
229245
}
@@ -328,13 +344,14 @@ export class BuildkiteClient {
328344
break;
329345
}
330346

331-
const resp = await this.http.get(link);
347+
const resp = await this.httpGet<Artifact[]>(link);
332348
link = '';
333349

334350
artifacts.push(resp.data);
335351

336-
if (resp.headers.link) {
337-
const result = parseLinkHeader(resp.headers.link as string, this.baseUrl);
352+
const linkHeader = resp.headers.get('link');
353+
if (linkHeader) {
354+
const result = parseLinkHeader(linkHeader, this.baseUrl);
338355
if (result?.next) {
339356
link = result.next;
340357
}
@@ -364,7 +381,7 @@ export class BuildkiteClient {
364381
): Promise<Build> => {
365382
const url = `v2/organizations/elastic/pipelines/${pipelineSlug}/builds`;
366383

367-
return (await this.http.post(url, options)).data;
384+
return (await this.httpPost<Build>(url, options)).data;
368385
};
369386

370387
cancelStep = (stepIdOrKey: string): void => {

.buildkite/pipeline-utils/ci-stats/client.ts

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
* License v3.0 only", or the "Server Side Public License, v 1".
88
*/
99

10-
import type { Method, AxiosRequestConfig } from 'axios';
11-
import axios from 'axios';
10+
// native fetch - no axios dependency
1211

1312
export interface CiStatsClientConfig {
1413
baseUrl?: string;
@@ -58,9 +57,9 @@ export interface TestGroupRunOrderResponse {
5857

5958
interface RequestOptions {
6059
path: string;
61-
method?: Method;
62-
params?: AxiosRequestConfig['params'];
63-
body?: AxiosRequestConfig['data'];
60+
method?: string;
61+
params?: Record<string, string>;
62+
body?: unknown;
6463
maxAttempts?: number;
6564
}
6665

@@ -79,7 +78,7 @@ export class CiStatsClient {
7978
}
8079

8180
createBuild = async () => {
82-
const resp = await this.request<CiStatsBuild>({
81+
return await this.request<CiStatsBuild>({
8382
method: 'POST',
8483
path: '/v1/build',
8584
body: {
@@ -92,8 +91,6 @@ export class CiStatsClient {
9291
: [],
9392
},
9493
});
95-
96-
return resp.data;
9794
};
9895

9996
addGitInfo = async (buildId: string) => {
@@ -139,15 +136,13 @@ export class CiStatsClient {
139136
};
140137

141138
getPrReport = async (buildId: string) => {
142-
const resp = await this.request<CiStatsPrReport>({
139+
return await this.request<CiStatsPrReport>({
143140
method: 'GET',
144141
path: `v2/pr_report`,
145142
params: {
146143
buildId,
147144
},
148145
});
149-
150-
return resp.data;
151146
};
152147

153148
pickTestGroupRunOrder = async (body: {
@@ -182,33 +177,67 @@ export class CiStatsClient {
182177
console.log('requesting test group run order from ci-stats:');
183178
console.log(JSON.stringify(body, null, 2));
184179

185-
const resp = await axios.request<TestGroupRunOrderResponse>({
180+
const url = `${this.baseUrl}/v2/_pick_test_group_run_order`;
181+
const resp = await fetch(url, {
186182
method: 'POST',
187-
baseURL: this.baseUrl,
188-
headers: this.defaultHeaders,
189-
url: '/v2/_pick_test_group_run_order',
190-
data: body,
183+
headers: {
184+
'Content-Type': 'application/json',
185+
...this.defaultHeaders,
186+
},
187+
body: JSON.stringify(body),
191188
});
192189

193-
return resp.data;
190+
if (!resp.ok) {
191+
throw new Error(`CI Stats request failed with status ${resp.status}`);
192+
}
193+
194+
return (await resp.json()) as TestGroupRunOrderResponse;
194195
};
195196

196-
private async request<T>({ method, path, params, body, maxAttempts = 3 }: RequestOptions) {
197+
private async request<T>({
198+
method,
199+
path,
200+
params,
201+
body,
202+
maxAttempts = 3,
203+
}: RequestOptions): Promise<T> {
197204
let attempt = 0;
198205

199206
while (true) {
200207
attempt += 1;
201208
try {
202-
return await axios.request<T>({
203-
method,
204-
baseURL: this.baseUrl,
205-
url: path,
206-
params,
207-
data: body,
208-
headers: this.defaultHeaders,
209-
});
209+
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
210+
const url = `${this.baseUrl}/${path.replace(/^\//, '')}${queryString}`;
211+
212+
const fetchOptions: RequestInit = {
213+
method: method ?? 'GET',
214+
headers: {
215+
...this.defaultHeaders,
216+
...(body ? { 'Content-Type': 'application/json' } : {}),
217+
},
218+
};
219+
220+
if (body) {
221+
fetchOptions.body = JSON.stringify(body);
222+
}
223+
224+
const resp = await fetch(url, fetchOptions);
225+
226+
if (!resp.ok) {
227+
const errorBody = await resp.text();
228+
let errorMessage: string | undefined;
229+
try {
230+
errorMessage = JSON.parse(errorBody)?.message;
231+
} catch {
232+
// ignore parse error
233+
}
234+
throw new Error(errorMessage ?? `Request failed with status ${resp.status}`);
235+
}
236+
237+
const text = await resp.text();
238+
return (text ? JSON.parse(text) : undefined) as T;
210239
} catch (error) {
211-
console.error('CI Stats request error:', error?.response?.data?.message);
240+
console.error('CI Stats request error:', (error as Error).message);
212241

213242
if (attempt < maxAttempts) {
214243
const sec = attempt * 3;

.buildkite/scripts/pipelines/chromium_linux_build/issue_feedback/entry.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const { readFileSync, createWriteStream } = require('fs');
1212
const assert = require('assert');
1313
const { execFile } = require('child_process');
1414
const { finished } = require('stream').promises;
15-
const axios = require('axios');
15+
const { Readable } = require('stream');
1616
const fg = require('fast-glob');
1717
const AdmZip = require('adm-zip');
1818

@@ -158,18 +158,24 @@ const getSha256Hash = async (filePath) => {
158158

159159
process.chdir('chromium');
160160

161-
const response = await axios.get(
161+
const response = await fetch(
162162
'https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json'
163163
);
164164

165+
if (!response.ok) {
166+
throw new Error(
167+
`Failed to fetch known good versions: ${response.status} ${response.statusText}`
168+
);
169+
}
170+
165171
/**
166172
* @description list of known good versions of chromium provided by google
167173
* @type {{
168174
* timestamp: string
169175
* versions: VersionDefinition[]
170176
* }}
171177
*/
172-
const { versions } = response.data;
178+
const { versions } = await response.json();
173179

174180
const chromiumVersion = await $('buildkite-agent', ['meta-data', 'get', 'chromium_version'], {
175181
printToScreen: true,
@@ -204,13 +210,20 @@ const getSha256Hash = async (filePath) => {
204210

205211
const url = new URL(download.url);
206212

207-
const downloadResponse = await axios.get(url.toString(), { responseType: 'stream' });
213+
const downloadResponse = await fetch(url.toString());
214+
215+
if (!downloadResponse.ok) {
216+
throw new Error(
217+
`Failed to download ${url}: ${downloadResponse.status} ${downloadResponse.statusText}`
218+
);
219+
}
208220

209221
const downloadFileName = parse(url.pathname).base;
210222

211-
downloadResponse.data.pipe(createWriteStream(downloadFileName));
223+
const nodeStream = Readable.fromWeb(downloadResponse.body);
224+
nodeStream.pipe(createWriteStream(downloadFileName));
212225

213-
await finished(downloadResponse.data);
226+
await finished(nodeStream);
214227

215228
console.log(`---Extracting and computing checksum for ${downloadFileName}\n`);
216229

.buildkite/scripts/serverless/create_deploy_tag/shared.ts

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
* License v3.0 only", or the "Server Side Public License, v 1".
88
*/
99

10-
import axios from 'axios';
11-
1210
import { getExec } from './mock_exec';
1311
import type { GitCommitExtract } from './info_sections/commit_info';
1412
import type { BuildkiteBuildExtract } from './info_sections/build_info';
@@ -93,22 +91,19 @@ export function sendSlackMessage(payload: any) {
9391
console.log('No SLACK_WEBHOOK_URL set, not sending slack message');
9492
return Promise.resolve();
9593
} else {
96-
return axios
97-
.post(
98-
process.env.DEPLOY_TAGGER_SLACK_WEBHOOK_URL,
99-
typeof payload === 'string' ? payload : JSON.stringify(payload)
100-
)
101-
.catch((error) => {
102-
if (axios.isAxiosError(error) && error.response) {
103-
console.error(
104-
"Couldn't send slack message.",
105-
error.response.status,
106-
error.response.statusText,
107-
error.message
108-
);
109-
} else {
110-
console.error("Couldn't send slack message.", error.message);
94+
const body = typeof payload === 'string' ? payload : JSON.stringify(payload);
95+
return fetch(process.env.DEPLOY_TAGGER_SLACK_WEBHOOK_URL, {
96+
method: 'POST',
97+
headers: { 'Content-Type': 'application/json' },
98+
body,
99+
})
100+
.then((response) => {
101+
if (!response.ok) {
102+
console.error("Couldn't send slack message.", response.status, response.statusText);
111103
}
104+
})
105+
.catch((error) => {
106+
console.error("Couldn't send slack message.", (error as Error).message);
112107
});
113108
}
114109
}

0 commit comments

Comments
 (0)