core-test/src/core.next/Commands/Checkout.cs

105 lines
3.9 KiB
C#
Raw Normal View History

2026-02-12 21:18:29 +01:00
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
using System.CommandLine;
using System.Text;
namespace Geekeey.Actions.Core.Commands;
internal sealed class Checkout : Command
{
#pragma warning disable format // @formatter:off
private static readonly Option<Uri> Repository = new("--repository") { Required = true };
private static readonly Option<DirectoryInfo> Destination = new("--path") { Required = true };
private static readonly Option<string> Reference = new("--reference") { Required = true };
#pragma warning restore format // @formatter:on
internal Checkout() : base("checkout")
{
Add(Repository);
Add(Destination);
Add(Reference);
SetAction(HandleAsync);
}
private async Task<int> HandleAsync(ParseResult result, CancellationToken cancellationToken)
{
var server = result.GetRequiredValue(Program.Server);
var access = result.GetRequiredValue(Program.Token);
var workspace = result.GetRequiredValue(Destination);
await $"git init -q {workspace.FullName}";
await $"git -C {workspace.FullName} config set --local protocol.version 2";
await $"git -C {workspace.FullName} config set --local gc.auto 0";
var repository = result.GetRequiredValue(Repository);
if (!repository.IsAbsoluteUri)
{
// relative repository urls are resolved against the server url
repository = new Uri(server, repository);
await $"git -C {workspace.FullName} config set --local --append url.{repository}.insteadOf git@{repository.Host}";
await $"git -C {workspace.FullName} config set --local --append url.{repository}.insteadOf ssh://git@{repository.Host}";
await $"git -C {workspace.FullName} config set --local --append url.{repository}.insteadOf git://{repository.Host}";
var header = $"Authorization: Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"x-access-token::${access}"))}";
await $"git -C {workspace.FullName} config set --local http.{repository}.extraheader '{header}'";
}
var origin = "origin";
var reference = result.GetRequiredValue(Reference);
await $"git -C {workspace.FullName} remote add {origin} {repository}";
var list = (await $"git -C {workspace.FullName} ls-remote {origin} {reference}").Split('\t');
if (list.Length < 2)
{
throw new InvalidOperationException("git ls-remote resolved nothing");
}
var @sha = list[0].Trim();
var @ref = list[1].Trim();
if (@ref.TryCutPrefix("refs/heads/", out var name))
{
var remote = $"refs/remotes/{origin}/{name}";
var branch = name;
await $"git -C {workspace.FullName} fetch --no-tags --prune --no-recurse-submodules --depth=1 {origin} +{@sha}:{remote}";
await $"git -C {workspace.FullName} checkout --force -B {branch} {remote}";
}
else if (@ref.TryCutPrefix("refs/pull/", out name))
{
var remote = $"refs/remotes/pull/{name}";
// Best-effort parity with the Go code's env.BaseRef/env.HeadRef:
var baseRef = Environment.GetEnvironmentVariable("GITHUB_BASE_REF");
var headRef = Environment.GetEnvironmentVariable("GITHUB_HEAD_REF");
var branch =
!string.IsNullOrEmpty(baseRef) ? baseRef :
!string.IsNullOrEmpty(headRef) ? headRef :
throw new InvalidOperationException("pull request can not find base ref for branch");
await $"git -C {workspace.FullName} fetch --no-tags --prune --no-recurse-submodules --depth=1 {origin} +{@sha}:{remote}";
await $"git -C {workspace.FullName} checkout --force -B {branch} {branch}";
}
else if (@ref.TryCutPrefix("refs/tags/", out name))
{
var remote = $"refs/tags/{name}";
await $"git -C {workspace.FullName} fetch --no-tags --prune --no-recurse-submodules --depth=1 {origin} +{@sha}:{remote}";
await $"git -C {workspace.FullName} checkout --force {remote}";
}
else
{
await $"git -C {workspace.FullName} fetch --no-tags --prune --no-recurse-submodules --depth=1 {origin} {@ref}";
await $"git -C {workspace.FullName} checkout --force {@ref}";
}
return 0;
}
}