191 lines
6.7 KiB
C#
191 lines
6.7 KiB
C#
#!/usr/bin/env -S dotnet run
|
|
|
|
#:package StudioWhy.Gitea.Net.API@1.25.0.2
|
|
|
|
using System.Net;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using Gitea.Net.Api;
|
|
using Gitea.Net.Client;
|
|
using Gitea.Net.Extensions;
|
|
using Gitea.Net.Model;
|
|
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
string jsonInput = Environment.GetEnvironmentVariable("INPUTS") ?? "{}";
|
|
const string name = "Download Previous Artifacts";
|
|
Console.WriteLine($"::group::{name} - Inputs");
|
|
Console.WriteLine(jsonInput);
|
|
Console.WriteLine("::endgroup::");
|
|
|
|
byte[] jsonBytes = Encoding.UTF8.GetBytes(jsonInput);
|
|
using MemoryStream memoryStream = new(jsonBytes);
|
|
|
|
string currentDir = Directory.GetCurrentDirectory();
|
|
IConfiguration configuration = new ConfigurationBuilder()
|
|
.SetBasePath(currentDir)
|
|
.AddJsonFile("appsettings.local.json", optional: true)
|
|
.AddJsonStream(memoryStream)
|
|
.AddEnvironmentVariables()
|
|
.Build();
|
|
|
|
string host = configuration["host"] ?? string.Empty;
|
|
string username = configuration["username"] ?? string.Empty;
|
|
string password = configuration["password"] ?? string.Empty;
|
|
|
|
string repoFullName = configuration["repoFullName"] ?? string.Empty;
|
|
|
|
string[] repoParts = repoFullName.Split('/');
|
|
if (repoParts.Length != 2)
|
|
{
|
|
throw new ArgumentException("Invalid repository full name format. Expected 'owner/repo'.");
|
|
}
|
|
string repoOwner = repoParts[0];
|
|
string repoName = repoParts[1];
|
|
|
|
string workflowPattern = configuration["workflowPattern"] ?? string.Empty;
|
|
Regex workflowRegex = WildcardToRegex(workflowPattern);
|
|
|
|
string artifactPattern = configuration["artifactPattern"] ?? "*";
|
|
Regex artifactRegex = WildcardToRegex(artifactPattern);
|
|
|
|
string unzipDir = configuration["unzipDir"] ?? string.Empty;
|
|
if (!string.IsNullOrEmpty(unzipDir) && !Path.IsPathFullyQualified(unzipDir))
|
|
{
|
|
unzipDir = Path.Combine(currentDir, unzipDir);
|
|
}
|
|
bool.TryParse(configuration["deleteAfterUnzip"], out bool deleteAfterUnzip);
|
|
|
|
// Configure services
|
|
ServiceCollection services = new();
|
|
services.AddApi(o =>
|
|
{
|
|
BasicToken basicToken = new(username, password);
|
|
o.AddTokens(basicToken);
|
|
});
|
|
|
|
UriBuilder hostUriBuilder = new(host);
|
|
hostUriBuilder.Path = "/api/v1";
|
|
|
|
HttpClientHandler httpClientHandler = new()
|
|
{
|
|
AllowAutoRedirect = false,
|
|
};
|
|
using HttpClient httpClient = new(httpClientHandler, true)
|
|
{
|
|
BaseAddress = hostUriBuilder.Uri,
|
|
};
|
|
|
|
services.AddLogging(configure => configure.AddConsole());
|
|
services.AddSingleton(httpClient);
|
|
services.AddSingleton<RepositoryApi>();
|
|
|
|
ServiceProvider serviceProvider = services.BuildServiceProvider();
|
|
RepositoryApi repositoryApi = serviceProvider.GetRequiredService<RepositoryApi>();
|
|
|
|
static Regex WildcardToRegex(string pattern, RegexOptions options = RegexOptions.IgnoreCase)
|
|
{
|
|
string regexString = "^" + Regex.Escape(pattern)
|
|
.Replace(@"\*", ".*")
|
|
.Replace(@"\?", ".") + "$";
|
|
return new(regexString, options);
|
|
}
|
|
|
|
Console.WriteLine($"Retrieving workflow runs for repository: {repoOwner}/{repoName} with pattern: {workflowPattern}");
|
|
IGetWorkflowRunsApiResponse getWorkflowRunsApiResponse = await repositoryApi.GetWorkflowRunsOrDefaultAsync(repoOwner, repoName, status: "success", page: 1, cancellationToken: CancellationToken.None);
|
|
if (!getWorkflowRunsApiResponse.TryOk(out ActionWorkflowRunsResponse workflowRunResponse))
|
|
{
|
|
Console.WriteLine("Failed to retrieve workflow runs.");
|
|
return 1;
|
|
}
|
|
|
|
ActionWorkflowRun? actionWorkflowRun = workflowRunResponse.WorkflowRuns.FirstOrDefault(w => workflowRegex.IsMatch(w.Path.Split('@')[0]));
|
|
if (actionWorkflowRun is null)
|
|
{
|
|
Console.WriteLine("No matching workflow run found.");
|
|
return 1;
|
|
}
|
|
|
|
IGetArtifactsOfRunApiResponse artifacts = await repositoryApi.GetArtifactsOfRunOrDefaultAsync(repoOwner, repoName, (int)actionWorkflowRun.Id!, string.Empty, CancellationToken.None);
|
|
if (!artifacts.TryOk(out ActionArtifactsResponse artifactsResponse))
|
|
{
|
|
Console.WriteLine("Failed to retrieve artifacts.");
|
|
return 1;
|
|
}
|
|
ActionArtifact[] artifactsToDownload = artifactsResponse.Artifacts.Where(a => artifactRegex.IsMatch(a.Name)).ToArray();
|
|
if (artifactsToDownload.Length is 0)
|
|
{
|
|
Console.WriteLine("No artifacts found for the specified workflow run.");
|
|
return 1;
|
|
}
|
|
|
|
StringBuilder namesBuilder = new();
|
|
namesBuilder.AppendLine("downloadedArtifactNames<<EOF");
|
|
|
|
StringBuilder artifactsBuilder = new();
|
|
artifactsBuilder.AppendLine("downloadedArtifactPaths<<EOF");
|
|
|
|
StringBuilder artifactsDirsBuilder = new();
|
|
artifactsDirsBuilder.AppendLine("downloadedArtifactDirs<<EOF");
|
|
|
|
Console.WriteLine("Downloading artifacts:");
|
|
foreach (ActionArtifact artifact in artifactsToDownload)
|
|
{
|
|
Console.WriteLine($"Artifact: {artifact.Name}, URL: {artifact.ArchiveDownloadUrl}");
|
|
|
|
IDownloadArtifactApiResponse downloadArtifactApiResponse = await repositoryApi.DownloadArtifactAsync(repoOwner, repoName, artifact.Id.ToString(), CancellationToken.None);
|
|
Uri? signedUrl = downloadArtifactApiResponse.Headers.Location;
|
|
if (downloadArtifactApiResponse.StatusCode is not HttpStatusCode.Found || signedUrl is null)
|
|
{
|
|
Console.WriteLine($"Failed to redirect to artifact: {artifact.Name}");
|
|
continue;
|
|
}
|
|
|
|
using HttpResponseMessage response = await httpClient.GetAsync(signedUrl, HttpCompletionOption.ResponseHeadersRead);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
string fileName = $"{artifact.Name}.zip";
|
|
await using FileStream fs = new(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
await using Stream stream = await response.Content.ReadAsStreamAsync();
|
|
await stream.CopyToAsync(fs);
|
|
fs.Close();
|
|
|
|
Console.WriteLine($"Downloaded: {fileName}");
|
|
namesBuilder.AppendLine(fileName);
|
|
artifactsBuilder.AppendLine(Path.GetFullPath(fileName));
|
|
|
|
if (string.IsNullOrEmpty(unzipDir)) continue;
|
|
string fullUnzipDir = Path.Combine(unzipDir, artifact.Name);
|
|
Directory.CreateDirectory(fullUnzipDir);
|
|
|
|
Console.WriteLine($"Unzipping: {fileName} to {fullUnzipDir}");
|
|
System.IO.Compression.ZipFile.ExtractToDirectory(fileName, fullUnzipDir, true);
|
|
artifactsDirsBuilder.AppendLine(fullUnzipDir);
|
|
if (deleteAfterUnzip)
|
|
{
|
|
File.Delete(fileName);
|
|
}
|
|
}
|
|
|
|
|
|
namesBuilder.AppendLine("EOF");
|
|
artifactsBuilder.AppendLine("EOF");
|
|
artifactsDirsBuilder.AppendLine("EOF");
|
|
|
|
string? githubOutput = configuration["GITHUB_OUTPUT"];
|
|
if (!string.IsNullOrEmpty(githubOutput))
|
|
{
|
|
await File.AppendAllTextAsync(githubOutput, namesBuilder.ToString());
|
|
await File.AppendAllTextAsync(githubOutput, artifactsBuilder.ToString());
|
|
await File.AppendAllTextAsync(githubOutput, artifactsDirsBuilder.ToString());
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine(namesBuilder.ToString());
|
|
Console.WriteLine(artifactsBuilder.ToString());
|
|
Console.WriteLine(artifactsDirsBuilder.ToString());
|
|
}
|
|
return 0;
|