Updated download previous artifacts script.
This commit is contained in:
70
gitea/download-previous-artifacts/action.yaml
Normal file
70
gitea/download-previous-artifacts/action.yaml
Normal file
@@ -0,0 +1,70 @@
|
||||
name: github-download-previous-artifacts
|
||||
description: "Download artifacts from a previous Workflow run."
|
||||
inputs:
|
||||
host:
|
||||
description: "Gitea host to query."
|
||||
required: true
|
||||
default: "${{ github.server_url }}"
|
||||
username:
|
||||
description: "Gitea user to query with."
|
||||
required: true
|
||||
default: "${{ github.actor }}"
|
||||
password:
|
||||
description: "Credentials to use for Gitea. If not specified, the GitHub/Gitea token will be used."
|
||||
required: true
|
||||
default: "${{ github.token }}"
|
||||
repoFullName:
|
||||
description: "The full name of the repository that ran the workflow to download from. Default: ${{ github.repository }}"
|
||||
required: true
|
||||
default: "${{ github.repository }}"
|
||||
workflowPattern:
|
||||
description: "Pattern of the workflow name to match. Supports wildcard or RegEx. Default: ${{ github.event.repository.workflow }}"
|
||||
required: true
|
||||
default: "${{ github.event.repository.workflow }}"
|
||||
artifactPattern:
|
||||
description: "Pattern of the artifacts to match. Supports wildcard or RegEx. Default: *"
|
||||
required: true
|
||||
default: "*"
|
||||
artifactName:
|
||||
description: "Name of the artifact when it is downloaded. If not specified, the artifact will be named what the artifact is named."
|
||||
required: false
|
||||
default: ""
|
||||
unzipDir:
|
||||
description: "Directory to unzip the artifacts into. If not specified, the artifacts will not be unzipped."
|
||||
required: false
|
||||
default: ""
|
||||
deleteAfterUnzip:
|
||||
description: "Whether to delete the artifacts after unzipping. Default: false"
|
||||
required: false
|
||||
default: "false"
|
||||
nugetSources:
|
||||
description: "List of additional NuGet sources to use."
|
||||
required: false
|
||||
default: "${{ github.api_url }}/packages/FORK/nuget/index.json"
|
||||
nugetUsernames:
|
||||
description: "List of additional NuGet usernames to use."
|
||||
required: false
|
||||
default: "${{ github.actor }}"
|
||||
nugetPasswords:
|
||||
description: "List of additional NuGet passwords to use."
|
||||
required: false
|
||||
default: "${{ github.token }}"
|
||||
# outputs:
|
||||
# query:
|
||||
# description: "The query result."
|
||||
# value: ${{ steps.query.outputs.console }}
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: |
|
||||
ls -al "${{ github.action_path }}"
|
||||
shell: bash
|
||||
- name: "Download artifacts."
|
||||
uses: act/common/dotnet/dotnet-10@master
|
||||
env:
|
||||
INPUTS: ${{ toJSON(inputs) }}
|
||||
with:
|
||||
command: run "${{ github.action_path }}/download-previous-artifacts.cs"
|
||||
nugetSources: ${{ inputs.nugetSources }}
|
||||
nugetUsernames: ${{ inputs.nugetUsernames }}
|
||||
nugetPasswords: ${{ inputs.nugetPasswords }}
|
||||
9
gitea/download-previous-artifacts/appsettings.json
Normal file
9
gitea/download-previous-artifacts/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"host": "https://gitea.studiowhy.net",
|
||||
"username": "your-username",
|
||||
"password": "your-password",
|
||||
"repoFullName": "owner/repo",
|
||||
"workflowPattern": "deployments/itchio.yaml",
|
||||
"artifactPattern": "*Windows",
|
||||
"unzipDir": ""
|
||||
}
|
||||
151
gitea/download-previous-artifacts/download-previous-artifacts.cs
Normal file
151
gitea/download-previous-artifacts/download-previous-artifacts.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
#!/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.Write(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;
|
||||
|
||||
foreach (string key in configuration.AsEnumerable().Select(kvp => kvp.Key))
|
||||
{
|
||||
Console.WriteLine($"::set-output name={key}::{configuration[key]}");
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ActionWorkflowRun? actionWorkflowRun = workflowRunResponse.WorkflowRuns.FirstOrDefault(w => workflowRegex.IsMatch(w.Path.Split('@')[0]));
|
||||
if (actionWorkflowRun is null)
|
||||
{
|
||||
Console.WriteLine("No matching workflow run found.");
|
||||
return;
|
||||
}
|
||||
|
||||
IGetArtifactsOfRunApiResponse artifacts = await repositoryApi.GetArtifactsOfRunOrDefaultAsync(repoOwner, repoName, (int)actionWorkflowRun.Id!, string.Empty, CancellationToken.None);
|
||||
if (!artifacts.TryOk(out ActionArtifactsResponse artifactsResponse) || artifactsResponse.TotalCount is 0)
|
||||
{
|
||||
Console.WriteLine("Failed to retrieve artifacts.");
|
||||
return;
|
||||
}
|
||||
|
||||
IEnumerable<ActionArtifact> artifactsToDownload = artifactsResponse.Artifacts.Where(a => artifactRegex.IsMatch(a.Name));
|
||||
|
||||
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}");
|
||||
|
||||
if (string.IsNullOrEmpty(unzipDir)) continue;
|
||||
|
||||
Console.WriteLine($"Unzipping: {fileName} to {unzipDir}");
|
||||
System.IO.Compression.ZipFile.ExtractToDirectory(fileName, unzipDir, true);
|
||||
if (deleteAfterUnzip)
|
||||
{
|
||||
File.Delete(fileName);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user