Skip to content

Commit

Permalink
getViaGit: get minimal flavor from ci-artifacts
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
dennisameling committed Sep 22, 2024
1 parent ade9582 commit a6dc960
Showing 1 changed file with 129 additions and 35 deletions.
164 changes: 129 additions & 35 deletions src/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {ChildProcess, spawn} from 'child_process'
import {Octokit} from '@octokit/rest'
import {delimiter} from 'path'
import * as fs from 'fs'
import https from 'https'
import os from 'os'

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

export async function getViaGit(
flavor: string,
architecture: string,
githubToken?: string
): Promise<{
type GetViaGitResult = {
artifactName: string
id: string
download: (
outputDirectory: string,
verbose?: number | boolean
) => Promise<void>
}> {
}

export async function getViaGit(
flavor: string,
architecture: string,
githubToken?: string
): Promise<GetViaGitResult> {
const owner = 'git-for-windows'

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

const octokit = githubToken ? new Octokit({auth: githubToken}) : new Octokit()
let head_sha: string

if (flavor === 'minimal') {
const info = await octokit.actions.listWorkflowRuns({
owner,
repo,
workflow_id: 938271,
status: 'success',
branch: 'main',
event: 'push',
per_page: 1
})
head_sha = info.data.workflow_runs[0].head_sha
/*
* There was a GCC upgrade to v14.1 that broke the build with `DEVELOPER=1`,
* and `ci-artifacts` was not updated to test-build with `DEVELOPER=1` (this
* was fixed in https://github.com/git-for-windows/git-sdk-64/pull/83).
*
* Work around that by forcing the incorrectly-passing revision back to the
* last one before that GCC upgrade.
*/
if (head_sha === '5f6ba092f690c0bbf84c7201be97db59cdaeb891') {
head_sha = 'e37e3f44c1934f0f263dabbf4ed50a3cfb6eaf71'
}
} else {
const info = await octokit.repos.getBranch({
owner,
repo,
branch: 'main'
})
head_sha = info.data.commit.sha
return getMinimalFlavor(owner, repo, artifactName, octokit, githubToken)
}

const info = await octokit.repos.getBranch({
owner,
repo,
branch: 'main'
})
const head_sha = info.data.commit.sha
const id = `${artifactName}-${head_sha}${head_sha === 'e37e3f44c1934f0f263dabbf4ed50a3cfb6eaf71' ? '-2' : ''}`
core.info(`Got commit ${head_sha} for ${repo}`)

Expand Down Expand Up @@ -239,3 +223,113 @@ export async function getViaGit(
}
}
}

async function getMinimalFlavor(
owner: string,
repo: string,
artifactName: string,
octokit: Octokit,
githubToken?: string
): Promise<GetViaGitResult> {
const ciArtifactsResponse = await octokit.repos.getReleaseByTag({
owner,
repo,
tag: 'ci-artifacts'
})

if (ciArtifactsResponse.status !== 200) {
throw new Error(
`Failed to get ci-artifacts release from the ${owner}/${repo} repo: ${ciArtifactsResponse.status}`
)
}

const tarGzArtifact = ciArtifactsResponse.data.assets.find(asset =>
asset.name.endsWith('.tar.gz')
)

if (!tarGzArtifact) {
throw new Error(
`Failed to find a tar.gz artifact in the ci-artifacts release of the ${owner}/${repo} repo`
)
}

return {
artifactName,
id: `ci-artifacts-${tarGzArtifact.updated_at}`,
download: async (
outputDirectory: string,
verbose: number | boolean = false
): Promise<void> => {
const tmpFile = `${os.tmpdir()}/${tarGzArtifact.name}`
await downloadFile(
tarGzArtifact.browser_download_url,
{
headers: {
...(githubToken ? {Authorization: `Bearer ${githubToken}`} : {}),
Accept: 'application/octet-stream'
}
},
tmpFile
)
core.info(`Extracting ${tmpFile} to ${outputDirectory}...`)
const traceArg = verbose ? ['-v'] : []
const child = spawn('C:\\Windows\\system32\\tar.exe', [
'-xzf',
...traceArg,
tmpFile,
'-C',
outputDirectory
])
return new Promise<void>((resolve, reject) => {
child.on('close', code => {
core.endGroup()
if (code === 0) {
fs.rm(tmpFile, () => resolve())
} else {
reject(new Error(`tar -xzf process exited with code ${code}`))
}
})
})
}
}
}

async function downloadFile(
url: string,
options: https.RequestOptions,
destination: string
): Promise<void> {
return new Promise((resolve, reject) => {
core.info(`Downloading ${url} to ${destination}...`)
const file = fs.createWriteStream(destination)
https
.get(url, options, async response => {
if (response.statusCode === 301 || response.statusCode === 302) {
if (!response.headers.location) {
throw new Error(
`Got a 301 or 302 response code, but no location header was set. Cannot continue.`
)
}
return await downloadFile(
response.headers.location,
options,
destination
)
}
if (response.statusCode === 200) {
response.pipe(file)
file.on('finish', () => {
file.close(() => resolve())
})
} else {
file.close()
fs.unlink(destination, () =>
reject(new Error(`Failed to download file: ${response.statusCode}`))
)
}
})
.on('error', err => {
fs.unlink(destination, () => reject(err))
})
})
}

0 comments on commit a6dc960

Please sign in to comment.