Read-only mirror — the public repositories of the Forgejo instance, refreshed every 10 minutes. The live instance (fg.dieschoenewolke.de) is reachable only over the VPN; clone here with https://git.dieschoenewolke.de/git/<owner>/<repo>.git.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/git-command-manager.ts78
-rw-r--r--src/git-source-provider.ts32
-rw-r--r--src/git-source-settings.ts10
-rw-r--r--src/input-helper.ts11
4 files changed, 116 insertions, 15 deletions
diff --git a/src/git-command-manager.ts b/src/git-command-manager.ts
index ab07524..e684dba 100644
--- a/src/git-command-manager.ts
+++ b/src/git-command-manager.ts
@@ -1,5 +1,6 @@
import * as core from '@actions/core'
import * as exec from '@actions/exec'
+import * as fs from 'fs'
import * as fshelper from './fs-helper'
import * as io from '@actions/io'
import * as path from 'path'
@@ -16,6 +17,8 @@ export interface IGitCommandManager {
branchDelete(remote: boolean, branch: string): Promise<void>
branchExists(remote: boolean, pattern: string): Promise<boolean>
branchList(remote: boolean): Promise<string[]>
+ sparseCheckout(sparseCheckout: string[]): Promise<void>
+ sparseCheckoutNonConeMode(sparseCheckout: string[]): Promise<void>
checkout(ref: string, startPoint: string): Promise<void>
checkoutDetach(): Promise<void>
config(
@@ -25,7 +28,13 @@ export interface IGitCommandManager {
add?: boolean
): Promise<void>
configExists(configKey: string, globalConfig?: boolean): Promise<boolean>
- fetch(refSpec: string[], fetchDepth?: number): Promise<void>
+ fetch(
+ refSpec: string[],
+ options: {
+ filter?: string
+ fetchDepth?: number
+ }
+ ): Promise<void>
getDefaultBranch(repositoryUrl: string): Promise<string>
getWorkingDirectory(): string
init(): Promise<void>
@@ -52,9 +61,14 @@ export interface IGitCommandManager {
export async function createCommandManager(
workingDirectory: string,
- lfs: boolean
+ lfs: boolean,
+ doSparseCheckout: boolean
): Promise<IGitCommandManager> {
- return await GitCommandManager.createCommandManager(workingDirectory, lfs)
+ return await GitCommandManager.createCommandManager(
+ workingDirectory,
+ lfs,
+ doSparseCheckout
+ )
}
class GitCommandManager {
@@ -64,6 +78,7 @@ class GitCommandManager {
}
private gitPath = ''
private lfs = false
+ private doSparseCheckout = false
private workingDirectory = ''
// Private constructor; use createCommandManager()
@@ -154,6 +169,27 @@ class GitCommandManager {
return result
}
+ async sparseCheckout(sparseCheckout: string[]): Promise<void> {
+ await this.execGit(['sparse-checkout', 'set', ...sparseCheckout])
+ }
+
+ async sparseCheckoutNonConeMode(sparseCheckout: string[]): Promise<void> {
+ await this.execGit(['config', 'core.sparseCheckout', 'true'])
+ const output = await this.execGit([
+ 'rev-parse',
+ '--git-path',
+ 'info/sparse-checkout'
+ ])
+ const sparseCheckoutPath = path.join(
+ this.workingDirectory,
+ output.stdout.trimRight()
+ )
+ await fs.promises.appendFile(
+ sparseCheckoutPath,
+ `\n${sparseCheckout.join('\n')}\n`
+ )
+ }
+
async checkout(ref: string, startPoint: string): Promise<void> {
const args = ['checkout', '--progress', '--force']
if (startPoint) {
@@ -202,15 +238,23 @@ class GitCommandManager {
return output.exitCode === 0
}
- async fetch(refSpec: string[], fetchDepth?: number): Promise<void> {
+ async fetch(
+ refSpec: string[],
+ options: {filter?: string; fetchDepth?: number}
+ ): Promise<void> {
const args = ['-c', 'protocol.version=2', 'fetch']
if (!refSpec.some(x => x === refHelper.tagsRefSpec)) {
args.push('--no-tags')
}
args.push('--prune', '--progress', '--no-recurse-submodules')
- if (fetchDepth && fetchDepth > 0) {
- args.push(`--depth=${fetchDepth}`)
+
+ if (options.filter) {
+ args.push(`--filter=${options.filter}`)
+ }
+
+ if (options.fetchDepth && options.fetchDepth > 0) {
+ args.push(`--depth=${options.fetchDepth}`)
} else if (
fshelper.fileExistsSync(
path.join(this.workingDirectory, '.git', 'shallow')
@@ -423,10 +467,15 @@ class GitCommandManager {
static async createCommandManager(
workingDirectory: string,
- lfs: boolean
+ lfs: boolean,
+ doSparseCheckout: boolean
): Promise<GitCommandManager> {
const result = new GitCommandManager()
- await result.initializeCommandManager(workingDirectory, lfs)
+ await result.initializeCommandManager(
+ workingDirectory,
+ lfs,
+ doSparseCheckout
+ )
return result
}
@@ -476,7 +525,8 @@ class GitCommandManager {
private async initializeCommandManager(
workingDirectory: string,
- lfs: boolean
+ lfs: boolean,
+ doSparseCheckout: boolean
): Promise<void> {
this.workingDirectory = workingDirectory
@@ -539,6 +589,16 @@ class GitCommandManager {
}
}
+ this.doSparseCheckout = doSparseCheckout
+ if (this.doSparseCheckout) {
+ // The `git sparse-checkout` command was introduced in Git v2.25.0
+ const minimumGitSparseCheckoutVersion = new GitVersion('2.25')
+ if (!gitVersion.checkMinimum(minimumGitSparseCheckoutVersion)) {
+ throw new Error(
+ `Minimum Git version required for sparse checkout is ${minimumGitSparseCheckoutVersion}. Your git ('${this.gitPath}') is ${gitVersion}`
+ )
+ }
+ }
// Set the user agent
const gitHttpUserAgent = `git/${gitVersion} (github-actions-checkout)`
core.debug(`Set git useragent to: ${gitHttpUserAgent}`)
diff --git a/src/git-source-provider.ts b/src/git-source-provider.ts
index 48f20da..8f9d63f 100644
--- a/src/git-source-provider.ts
+++ b/src/git-source-provider.ts
@@ -153,23 +153,26 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
// Fetch
core.startGroup('Fetching the repository')
+ const fetchOptions: {filter?: string; fetchDepth?: number} = {}
+ if (settings.sparseCheckout) fetchOptions.filter = 'blob:none'
if (settings.fetchDepth <= 0) {
// Fetch all branches and tags
let refSpec = refHelper.getRefSpecForAllHistory(
settings.ref,
settings.commit
)
- await git.fetch(refSpec)
+ await git.fetch(refSpec, fetchOptions)
// When all history is fetched, the ref we're interested in may have moved to a different
// commit (push or force push). If so, fetch again with a targeted refspec.
if (!(await refHelper.testRef(git, settings.ref, settings.commit))) {
refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
- await git.fetch(refSpec)
+ await git.fetch(refSpec, fetchOptions)
}
} else {
+ fetchOptions.fetchDepth = settings.fetchDepth
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
- await git.fetch(refSpec, settings.fetchDepth)
+ await git.fetch(refSpec, fetchOptions)
}
core.endGroup()
@@ -185,12 +188,24 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
// LFS fetch
// Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
// Explicit lfs fetch will fetch lfs objects in parallel.
- if (settings.lfs) {
+ // For sparse checkouts, let `checkout` fetch the needed objects lazily.
+ if (settings.lfs && !settings.sparseCheckout) {
core.startGroup('Fetching LFS objects')
await git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref)
core.endGroup()
}
+ // Sparse checkout
+ if (settings.sparseCheckout) {
+ core.startGroup('Setting up sparse checkout')
+ if (settings.sparseCheckoutConeMode) {
+ await git.sparseCheckout(settings.sparseCheckout)
+ } else {
+ await git.sparseCheckoutNonConeMode(settings.sparseCheckout)
+ }
+ core.endGroup()
+ }
+
// Checkout
core.startGroup('Checking out the ref')
await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
@@ -261,7 +276,11 @@ export async function cleanup(repositoryPath: string): Promise<void> {
let git: IGitCommandManager
try {
- git = await gitCommandManager.createCommandManager(repositoryPath, false)
+ git = await gitCommandManager.createCommandManager(
+ repositoryPath,
+ false,
+ false
+ )
} catch {
return
}
@@ -297,7 +316,8 @@ async function getGitCommandManager(
try {
return await gitCommandManager.createCommandManager(
settings.repositoryPath,
- settings.lfs
+ settings.lfs,
+ settings.sparseCheckout != null
)
} catch (err) {
// Git is required for LFS
diff --git a/src/git-source-settings.ts b/src/git-source-settings.ts
index 2da5622..3272e63 100644
--- a/src/git-source-settings.ts
+++ b/src/git-source-settings.ts
@@ -30,6 +30,16 @@ export interface IGitSourceSettings {
clean: boolean
/**
+ * The array of folders to make the sparse checkout
+ */
+ sparseCheckout: string[]
+
+ /**
+ * Indicates whether to use cone mode in the sparse checkout (if any)
+ */
+ sparseCheckoutConeMode: boolean
+
+ /**
* The depth when fetching
*/
fetchDepth: number
diff --git a/src/input-helper.ts b/src/input-helper.ts
index 237b06a..410e480 100644
--- a/src/input-helper.ts
+++ b/src/input-helper.ts
@@ -82,6 +82,17 @@ export async function getInputs(): Promise<IGitSourceSettings> {
result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE'
core.debug(`clean = ${result.clean}`)
+ // Sparse checkout
+ const sparseCheckout = core.getMultilineInput('sparse-checkout')
+ if (sparseCheckout.length) {
+ result.sparseCheckout = sparseCheckout
+ core.debug(`sparse checkout = ${result.sparseCheckout}`)
+ }
+
+ result.sparseCheckoutConeMode =
+ (core.getInput('sparse-checkout-cone-mode') || 'true').toUpperCase() ===
+ 'TRUE'
+
// Fetch depth
result.fetchDepth = Math.floor(Number(core.getInput('fetch-depth') || '1'))
if (isNaN(result.fetchDepth) || result.fetchDepth < 0) {