Skip to content

Commit 6c57666

Browse files
committed
getViaGit: get minimal flavor from ci-artifacts
As a result of recent changes, the Git SDK `ci-artifacts` are published as GitHub release assets now. This eliminates the need for us to clone and cache the artifacts in this GitHub action. Let's simply download the latest `.tar.gz` from the `ci-artifacts` and extract it. Ref: git-for-windows/git-sdk-64@fdb0cea Ref: git-for-windows/git-sdk-64#87 Signed-off-by: Dennis Ameling <dennis@dennisameling.com>
1 parent ade9582 commit 6c57666

File tree

1 file changed

+113
-35
lines changed

1 file changed

+113
-35
lines changed

src/git.ts

Lines changed: 113 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {ChildProcess, spawn} from 'child_process'
33
import {Octokit} from '@octokit/rest'
44
import {delimiter} from 'path'
55
import * as fs from 'fs'
6+
import os from 'os'
7+
import fetch, {RequestInit} from 'node-fetch'
68

79
// If present, do prefer the build agent's copy of Git
810
const externalsGitDir = `${process.env.AGENT_HOMEDIRECTORY}/externals/git`
@@ -109,54 +111,36 @@ async function updateHEAD(
109111
})
110112
}
111113

112-
export async function getViaGit(
113-
flavor: string,
114-
architecture: string,
115-
githubToken?: string
116-
): Promise<{
114+
type GetViaGitResult = {
117115
artifactName: string
118116
id: string
119117
download: (
120118
outputDirectory: string,
121119
verbose?: number | boolean
122120
) => Promise<void>
123-
}> {
121+
}
122+
123+
export async function getViaGit(
124+
flavor: string,
125+
architecture: string,
126+
githubToken?: string
127+
): Promise<GetViaGitResult> {
124128
const owner = 'git-for-windows'
125129

126130
const {repo, artifactName} = getArtifactMetadata(flavor, architecture)
127131

128132
const octokit = githubToken ? new Octokit({auth: githubToken}) : new Octokit()
129-
let head_sha: string
133+
130134
if (flavor === 'minimal') {
131-
const info = await octokit.actions.listWorkflowRuns({
132-
owner,
133-
repo,
134-
workflow_id: 938271,
135-
status: 'success',
136-
branch: 'main',
137-
event: 'push',
138-
per_page: 1
139-
})
140-
head_sha = info.data.workflow_runs[0].head_sha
141-
/*
142-
* There was a GCC upgrade to v14.1 that broke the build with `DEVELOPER=1`,
143-
* and `ci-artifacts` was not updated to test-build with `DEVELOPER=1` (this
144-
* was fixed in https://github.com/git-for-windows/git-sdk-64/pull/83).
145-
*
146-
* Work around that by forcing the incorrectly-passing revision back to the
147-
* last one before that GCC upgrade.
148-
*/
149-
if (head_sha === '5f6ba092f690c0bbf84c7201be97db59cdaeb891') {
150-
head_sha = 'e37e3f44c1934f0f263dabbf4ed50a3cfb6eaf71'
151-
}
152-
} else {
153-
const info = await octokit.repos.getBranch({
154-
owner,
155-
repo,
156-
branch: 'main'
157-
})
158-
head_sha = info.data.commit.sha
135+
return getMinimalFlavor(owner, repo, artifactName, octokit, githubToken)
159136
}
137+
138+
const info = await octokit.repos.getBranch({
139+
owner,
140+
repo,
141+
branch: 'main'
142+
})
143+
const head_sha = info.data.commit.sha
160144
const id = `${artifactName}-${head_sha}${head_sha === 'e37e3f44c1934f0f263dabbf4ed50a3cfb6eaf71' ? '-2' : ''}`
161145
core.info(`Got commit ${head_sha} for ${repo}`)
162146

@@ -239,3 +223,97 @@ export async function getViaGit(
239223
}
240224
}
241225
}
226+
227+
async function getMinimalFlavor(
228+
owner: string,
229+
repo: string,
230+
artifactName: string,
231+
octokit: Octokit,
232+
githubToken?: string
233+
): Promise<GetViaGitResult> {
234+
const ciArtifactsResponse = await octokit.repos.getReleaseByTag({
235+
owner,
236+
repo,
237+
tag: 'ci-artifacts'
238+
})
239+
240+
if (ciArtifactsResponse.status !== 200) {
241+
throw new Error(
242+
`Failed to get ci-artifacts release from the ${owner}/${repo} repo: ${ciArtifactsResponse.status}`
243+
)
244+
}
245+
246+
const tarGzArtifact = ciArtifactsResponse.data.assets.find(asset =>
247+
asset.name.endsWith('.tar.gz')
248+
)
249+
250+
if (!tarGzArtifact) {
251+
throw new Error(
252+
`Failed to find a tar.gz artifact in the ci-artifacts release of the ${owner}/${repo} repo`
253+
)
254+
}
255+
256+
return {
257+
artifactName,
258+
id: `ci-artifacts-${tarGzArtifact.updated_at}`,
259+
download: async (
260+
outputDirectory: string,
261+
verbose: number | boolean = false
262+
): Promise<void> => {
263+
const tmpFile = `${os.tmpdir()}/${tarGzArtifact.name}`
264+
core.info(
265+
`Downloading ${tarGzArtifact.browser_download_url} to ${tmpFile}...`
266+
)
267+
await downloadFile(
268+
tarGzArtifact.browser_download_url,
269+
{
270+
headers: {
271+
...(githubToken ? {Authorization: `Bearer ${githubToken}`} : {}),
272+
Accept: 'application/octet-stream'
273+
}
274+
},
275+
tmpFile
276+
)
277+
core.info(`Extracting ${tmpFile} to ${outputDirectory}...`)
278+
fs.mkdirSync(outputDirectory)
279+
const child = spawn('C:\\Windows\\system32\\tar.exe', [
280+
`-xz${verbose ? 'v' : ''}f`,
281+
tmpFile,
282+
'-C',
283+
outputDirectory
284+
], {
285+
stdio: [undefined, 'inherit', 'inherit']
286+
})
287+
return new Promise<void>((resolve, reject) => {
288+
child.on('close', code => {
289+
if (code === 0) {
290+
core.info('Finished extracting archive.')
291+
fs.rm(tmpFile, () => resolve())
292+
} else {
293+
reject(new Error(`tar -xzf process exited with code ${code}`))
294+
}
295+
})
296+
})
297+
}
298+
}
299+
}
300+
301+
async function downloadFile(
302+
url: string,
303+
options: RequestInit,
304+
destination: string
305+
): Promise<void> {
306+
const response = await fetch(url, options);
307+
308+
if (!response.ok) {
309+
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
310+
}
311+
312+
const fileStream = fs.createWriteStream(destination);
313+
response.body.pipe(fileStream);
314+
315+
return new Promise((resolve, reject) => {
316+
fileStream.on('finish', resolve);
317+
fileStream.on('error', reject);
318+
});
319+
}

0 commit comments

Comments
 (0)