Skip to content

Commit 0f87802

Browse files
committed
Switch from fetch() to curl
1 parent 16ec82e commit 0f87802

File tree

1 file changed

+113
-89
lines changed

1 file changed

+113
-89
lines changed

scripts/releases/upload-release-assets-for-dotslash.js

Lines changed: 113 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ const {Octokit} = require('@octokit/rest');
2121
const {
2222
FIRST_PARTY_DOTSLASH_FILES,
2323
} = require('./write-dotslash-release-asset-urls');
24+
const os = require('os');
25+
const {promises: fs} = require('fs');
26+
const {spawnSync} = require('child_process');
2427

2528
const config = {
2629
allowPositionals: true,
@@ -93,112 +96,133 @@ async function uploadReleaseAssetsForDotSlash(
9396
const existingAssetsByName = new Map(
9497
existingAssets.data.map(asset => [asset.name, asset]),
9598
);
96-
for (const filename of FIRST_PARTY_DOTSLASH_FILES) {
97-
const fullPath = path.join(REPO_ROOT, filename);
98-
console.log(`Uploading assets for ${filename}...`);
99-
const uploadPromises = [];
100-
await processDotSlashFileInPlace(
101-
fullPath,
102-
(
103-
providers,
104-
// NOTE: We mostly ignore suggestedFilename in favour of reading the actual asset URLs
105-
suggestedFilename,
106-
) => {
107-
let upstreamUrl, targetReleaseAssetInfo;
108-
for (const provider of providers) {
109-
if (provider.type != null && provider.type !== 'http') {
99+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'dotslash-uploads-'));
100+
try {
101+
for (const filename of FIRST_PARTY_DOTSLASH_FILES) {
102+
const fullPath = path.join(REPO_ROOT, filename);
103+
console.log(`Uploading assets for ${filename}...`);
104+
const uploadPromises = [];
105+
await processDotSlashFileInPlace(
106+
fullPath,
107+
(
108+
providers,
109+
// NOTE: We mostly ignore suggestedFilename in favour of reading the actual asset URLs
110+
suggestedFilename,
111+
) => {
112+
let upstreamUrl, targetReleaseAssetInfo;
113+
for (const provider of providers) {
114+
if (provider.type != null && provider.type !== 'http') {
115+
console.log(
116+
'Skipping non-HTTP provider: ' + JSON.stringify(provider),
117+
);
118+
continue;
119+
}
120+
const url = provider.url;
121+
if (url.startsWith(releaseAssetPrefix)) {
122+
const name = decodeURIComponent(
123+
url.slice(releaseAssetPrefix.length),
124+
);
125+
targetReleaseAssetInfo = {name, url};
126+
} else {
127+
upstreamUrl = url;
128+
}
129+
if (upstreamUrl != null && targetReleaseAssetInfo != null) {
130+
break;
131+
}
132+
}
133+
if (targetReleaseAssetInfo == null) {
134+
// This DotSlash providers array does not reference any relevant release asset URLs, so we can ignore it.
110135
console.log(
111-
'Skipping non-HTTP provider: ' + JSON.stringify(provider),
136+
`[${suggestedFilename} (suggested)] No provider URLs matched release asset prefix: ${releaseAssetPrefix}`,
112137
);
113-
continue;
138+
return;
114139
}
115-
const url = provider.url;
116-
if (url.startsWith(releaseAssetPrefix)) {
117-
const name = decodeURIComponent(
118-
url.slice(releaseAssetPrefix.length),
140+
if (upstreamUrl == null) {
141+
throw new Error(
142+
`No upstream URL found for release asset ${targetReleaseAssetInfo.name}`,
119143
);
120-
targetReleaseAssetInfo = {name, url};
121-
} else {
122-
upstreamUrl = url;
123144
}
124-
if (upstreamUrl != null && targetReleaseAssetInfo != null) {
125-
break;
126-
}
127-
}
128-
if (targetReleaseAssetInfo == null) {
129-
// This DotSlash providers array does not reference any relevant release asset URLs, so we can ignore it.
130-
console.log(
131-
`[${suggestedFilename} (suggested)] No provider URLs matched release asset prefix: ${releaseAssetPrefix}`,
132-
);
133-
return;
134-
}
135-
if (upstreamUrl == null) {
136-
throw new Error(
137-
`No upstream URL found for release asset ${targetReleaseAssetInfo.name}`,
138-
);
139-
}
140-
uploadPromises.push(
141-
(async () => {
142-
if (existingAssetsByName.has(targetReleaseAssetInfo.name)) {
143-
if (!force) {
144-
console.log(
145-
`[${targetReleaseAssetInfo.name}] Skipping existing release asset...`,
145+
uploadPromises.push(
146+
(async () => {
147+
if (existingAssetsByName.has(targetReleaseAssetInfo.name)) {
148+
if (!force) {
149+
console.log(
150+
`[${targetReleaseAssetInfo.name}] Skipping existing release asset...`,
151+
);
152+
return;
153+
}
154+
if (dryRun) {
155+
console.log(
156+
`[${targetReleaseAssetInfo.name}] Dry run: Not deleting existing release asset.`,
157+
);
158+
} else {
159+
console.log(
160+
`[${targetReleaseAssetInfo.name}] Deleting existing release asset...`,
161+
);
162+
await octokit.repos.deleteReleaseAsset({
163+
owner: 'facebook',
164+
repo: 'react-native',
165+
asset_id: existingAssetsByName.get(
166+
targetReleaseAssetInfo.name,
167+
).id,
168+
});
169+
}
170+
}
171+
console.log(
172+
`[${targetReleaseAssetInfo.name}] Downloading from ${upstreamUrl}...`,
173+
);
174+
const tempFile = path.join(tempDir, targetReleaseAssetInfo.name);
175+
const curlOutput = spawnSync(
176+
// use long form of options for clarity, e.g. --silent instead of -s
177+
'curl',
178+
[
179+
'--silent',
180+
'--location',
181+
'--output',
182+
tempFile,
183+
upstreamUrl,
184+
// get the content-type header
185+
'--write-out',
186+
'%{header_json}',
187+
],
188+
{encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe']},
189+
);
190+
if (curlOutput.status !== 0) {
191+
throw new Error(
192+
`Failed to download ${upstreamUrl}: ${curlOutput.stderr}`,
146193
);
147-
return;
148194
}
195+
const data = await fs.readFile(tempFile);
196+
const headers = JSON.parse(curlOutput.stdout);
149197
if (dryRun) {
150198
console.log(
151-
`[${targetReleaseAssetInfo.name}] Dry run: Not deleting existing release asset.`,
199+
`[${targetReleaseAssetInfo.name}] Dry run: Not uploading to release.`,
152200
);
201+
return;
153202
} else {
154203
console.log(
155-
`[${targetReleaseAssetInfo.name}] Deleting existing release asset...`,
204+
`[${targetReleaseAssetInfo.name}] Uploading to release...`,
156205
);
157-
await octokit.repos.deleteReleaseAsset({
206+
await octokit.repos.uploadReleaseAsset({
158207
owner: 'facebook',
159208
repo: 'react-native',
160-
asset_id: existingAssetsByName.get(
161-
targetReleaseAssetInfo.name,
162-
).id,
209+
release_id: releaseId,
210+
name: targetReleaseAssetInfo.name,
211+
data,
212+
headers: {
213+
'content-type':
214+
headers['content-type'] ?? 'application/octet-stream',
215+
},
163216
});
164217
}
165-
}
166-
console.log(
167-
`[${targetReleaseAssetInfo.name}] Downloading from ${upstreamUrl}...`,
168-
);
169-
const response = await fetch(upstreamUrl);
170-
if (!response.ok) {
171-
throw new Error(
172-
`Failed to download ${upstreamUrl}: ${response.status} ${response.statusText}`,
173-
);
174-
}
175-
const data = await response.arrayBuffer();
176-
const contentType = response.headers.get('content-type');
177-
if (dryRun) {
178-
console.log(
179-
`[${targetReleaseAssetInfo.name}] Dry run: Not uploading to release.`,
180-
);
181-
return;
182-
} else {
183-
console.log(
184-
`[${targetReleaseAssetInfo.name}] Uploading to release...`,
185-
);
186-
await octokit.repos.uploadReleaseAsset({
187-
owner: 'facebook',
188-
repo: 'react-native',
189-
release_id: releaseId,
190-
name: targetReleaseAssetInfo.name,
191-
data,
192-
headers: {
193-
'content-type': contentType,
194-
},
195-
});
196-
}
197-
})(),
198-
);
199-
},
200-
);
201-
await Promise.all(uploadPromises);
218+
})(),
219+
);
220+
},
221+
);
222+
await Promise.all(uploadPromises);
223+
}
224+
} finally {
225+
await fs.rm(tempDir, {recursive: true, force: true});
202226
}
203227
}
204228

0 commit comments

Comments
 (0)