add support for preview GitHub releases (#457)
This commit is contained in:
parent
9e052ae916
commit
436c071ba4
|
@ -9,9 +9,12 @@ namespace StardewModdingAPI.Common.Models
|
|||
/// <summary>The mod name.</summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>The mod's semantic version number.</summary>
|
||||
/// <summary>The semantic version for the mod's latest release.</summary>
|
||||
public string Version { get; set; }
|
||||
|
||||
/// <summary>The semantic version for the mod's latest preview release, if available and different from <see cref="Version"/>.</summary>
|
||||
public string PreviewVersion { get; set; }
|
||||
|
||||
/// <summary>The mod's web URL.</summary>
|
||||
public string Url { get; set; }
|
||||
|
||||
|
@ -28,16 +31,17 @@ namespace StardewModdingAPI.Common.Models
|
|||
// needed for JSON deserialising
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="name">The mod name.</param>
|
||||
/// <param name="version">The mod's semantic version number.</param>
|
||||
/// <param name="version">The semantic version for the mod's latest release.</param>
|
||||
/// <param name="previewVersion">The semantic version for the mod's latest preview release, if available and different from <see cref="Version"/>.</param>
|
||||
/// <param name="url">The mod's web URL.</param>
|
||||
/// <param name="error">The error message indicating why the mod is invalid (if applicable).</param>
|
||||
public ModInfoModel(string name, string version, string url, string error = null)
|
||||
public ModInfoModel(string name, string version, string url, string previewVersion = null, string error = null)
|
||||
{
|
||||
this.Name = name;
|
||||
this.Version = version;
|
||||
this.PreviewVersion = previewVersion;
|
||||
this.Url = url;
|
||||
this.Error = error; // mainly initialised here for the JSON deserialiser
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Pathoschild.Http.Client;
|
||||
|
@ -11,8 +12,11 @@ namespace StardewModdingAPI.Web.Framework.Clients.GitHub
|
|||
/*********
|
||||
** Properties
|
||||
*********/
|
||||
/// <summary>The URL for a GitHub releases API query excluding the base URL, where {0} is the repository owner and name.</summary>
|
||||
private readonly string ReleaseUrlFormat;
|
||||
/// <summary>The URL for a GitHub API query for the latest stable release, excluding the base URL, where {0} is the organisation and project name.</summary>
|
||||
private readonly string StableReleaseUrlFormat;
|
||||
|
||||
/// <summary>The URL for a GitHub API query for the latest release (including prerelease), excluding the base URL, where {0} is the organisation and project name.</summary>
|
||||
private readonly string AnyReleaseUrlFormat;
|
||||
|
||||
/// <summary>The underlying HTTP client.</summary>
|
||||
private readonly IClient Client;
|
||||
|
@ -23,14 +27,16 @@ namespace StardewModdingAPI.Web.Framework.Clients.GitHub
|
|||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="baseUrl">The base URL for the GitHub API.</param>
|
||||
/// <param name="releaseUrlFormat">The URL for a GitHub releases API query excluding the <paramref name="baseUrl"/>, where {0} is the repository owner and name.</param>
|
||||
/// <param name="stableReleaseUrlFormat">The URL for a GitHub API query for the latest stable release, excluding the <paramref name="baseUrl"/>, where {0} is the organisation and project name.</param>
|
||||
/// <param name="anyReleaseUrlFormat">The URL for a GitHub API query for the latest release (including prerelease), excluding the <paramref name="baseUrl"/>, where {0} is the organisation and project name.</param>
|
||||
/// <param name="userAgent">The user agent for the API client.</param>
|
||||
/// <param name="acceptHeader">The Accept header value expected by the GitHub API.</param>
|
||||
/// <param name="username">The username with which to authenticate to the GitHub API.</param>
|
||||
/// <param name="password">The password with which to authenticate to the GitHub API.</param>
|
||||
public GitHubClient(string baseUrl, string releaseUrlFormat, string userAgent, string acceptHeader, string username, string password)
|
||||
public GitHubClient(string baseUrl, string stableReleaseUrlFormat, string anyReleaseUrlFormat, string userAgent, string acceptHeader, string username, string password)
|
||||
{
|
||||
this.ReleaseUrlFormat = releaseUrlFormat;
|
||||
this.StableReleaseUrlFormat = stableReleaseUrlFormat;
|
||||
this.AnyReleaseUrlFormat = anyReleaseUrlFormat;
|
||||
|
||||
this.Client = new FluentClient(baseUrl)
|
||||
.SetUserAgent(userAgent)
|
||||
|
@ -41,18 +47,23 @@ namespace StardewModdingAPI.Web.Framework.Clients.GitHub
|
|||
|
||||
/// <summary>Get the latest release for a GitHub repository.</summary>
|
||||
/// <param name="repo">The repository key (like <c>Pathoschild/SMAPI</c>).</param>
|
||||
/// <returns>Returns the latest release if found, else <c>null</c>.</returns>
|
||||
public async Task<GitRelease> GetLatestReleaseAsync(string repo)
|
||||
/// <param name="includePrerelease">Whether to return a prerelease version if it's latest.</param>
|
||||
/// <returns>Returns the release if found, else <c>null</c>.</returns>
|
||||
public async Task<GitRelease> GetLatestReleaseAsync(string repo, bool includePrerelease = false)
|
||||
{
|
||||
// validate key format
|
||||
if (!repo.Contains("/") || repo.IndexOf("/", StringComparison.InvariantCultureIgnoreCase) != repo.LastIndexOf("/", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new ArgumentException($"The value '{repo}' isn't a valid GitHub repository key, must be a username and project name like 'Pathoschild/SMAPI'.", nameof(repo));
|
||||
|
||||
// fetch info
|
||||
this.AssetKeyFormat(repo);
|
||||
try
|
||||
{
|
||||
if (includePrerelease)
|
||||
{
|
||||
GitRelease[] results = await this.Client
|
||||
.GetAsync(string.Format(this.AnyReleaseUrlFormat, repo))
|
||||
.AsArray<GitRelease>();
|
||||
return results.FirstOrDefault();
|
||||
}
|
||||
|
||||
return await this.Client
|
||||
.GetAsync(string.Format(this.ReleaseUrlFormat, repo))
|
||||
.GetAsync(string.Format(this.StableReleaseUrlFormat, repo))
|
||||
.As<GitRelease>();
|
||||
}
|
||||
catch (ApiException ex) when (ex.Status == HttpStatusCode.NotFound)
|
||||
|
@ -66,5 +77,18 @@ namespace StardewModdingAPI.Web.Framework.Clients.GitHub
|
|||
{
|
||||
this.Client?.Dispose();
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** Private methods
|
||||
*********/
|
||||
/// <summary>Assert that a repository key is formatted correctly.</summary>
|
||||
/// <param name="repo">The repository key (like <c>Pathoschild/SMAPI</c>).</param>
|
||||
/// <exception cref="ArgumentException">The repository key is invalid.</exception>
|
||||
private void AssetKeyFormat(string repo)
|
||||
{
|
||||
if (repo == null || !repo.Contains("/") || repo.IndexOf("/", StringComparison.InvariantCultureIgnoreCase) != repo.LastIndexOf("/", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new ArgumentException($"The value '{repo}' isn't a valid GitHub repository key, must be a username and project name like 'Pathoschild/SMAPI'.", nameof(repo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@ namespace StardewModdingAPI.Web.Framework.Clients.GitHub
|
|||
/// <summary>The Markdown description for the release.</summary>
|
||||
public string Body { get; set; }
|
||||
|
||||
/// <summary>Whether this is a prerelease version.</summary>
|
||||
[JsonProperty("prerelease")]
|
||||
public bool IsPrerelease { get; set; }
|
||||
|
||||
/// <summary>The attached files.</summary>
|
||||
public GitAsset[] Assets { get; set; }
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ namespace StardewModdingAPI.Web.Framework.Clients.GitHub
|
|||
*********/
|
||||
/// <summary>Get the latest release for a GitHub repository.</summary>
|
||||
/// <param name="repo">The repository key (like <c>Pathoschild/SMAPI</c>).</param>
|
||||
/// <returns>Returns the latest release if found, else <c>null</c>.</returns>
|
||||
Task<GitRelease> GetLatestReleaseAsync(string repo);
|
||||
/// <param name="includePrerelease">Whether to return a prerelease version if it's latest.</param>
|
||||
/// <returns>Returns the release if found, else <c>null</c>.</returns>
|
||||
Task<GitRelease> GetLatestReleaseAsync(string repo, bool includePrerelease = false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,11 @@ namespace StardewModdingAPI.Web.Framework.ConfigModels
|
|||
/// <summary>The base URL for the GitHub API.</summary>
|
||||
public string GitHubBaseUrl { get; set; }
|
||||
|
||||
/// <summary>The URL for a GitHub API latest-release query excluding the <see cref="GitHubBaseUrl"/>, where {0} is the organisation and project name.</summary>
|
||||
public string GitHubReleaseUrlFormat { get; set; }
|
||||
/// <summary>The URL for a GitHub API query for the latest stable release, excluding the <see cref="GitHubBaseUrl"/>, where {0} is the organisation and project name.</summary>
|
||||
public string GitHubStableReleaseUrlFormat { get; set; }
|
||||
|
||||
/// <summary>The URL for a GitHub API query for the latest release (including prerelease), excluding the <see cref="GitHubBaseUrl"/>, where {0} is the organisation and project name.</summary>
|
||||
public string GitHubAnyReleaseUrlFormat { get; set; }
|
||||
|
||||
/// <summary>The Accept header value expected by the GitHub API.</summary>
|
||||
public string GitHubAcceptHeader { get; set; }
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories
|
|||
return new ModInfoModel("Found no mod with this ID.");
|
||||
|
||||
// create model
|
||||
return new ModInfoModel(mod.Name, this.NormaliseVersion(mod.Version), mod.Url);
|
||||
return new ModInfoModel(name: mod.Name, version: this.NormaliseVersion(mod.Version), url: mod.Url);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -38,10 +38,21 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories
|
|||
// fetch info
|
||||
try
|
||||
{
|
||||
GitRelease release = await this.Client.GetLatestReleaseAsync(id);
|
||||
return release != null
|
||||
? new ModInfoModel(id, this.NormaliseVersion(release.Tag), $"https://github.com/{id}/releases")
|
||||
: new ModInfoModel("Found no mod with this ID.");
|
||||
// get latest release
|
||||
GitRelease latest = await this.Client.GetLatestReleaseAsync(id, includePrerelease: true);
|
||||
GitRelease preview = null;
|
||||
if (latest == null)
|
||||
return new ModInfoModel("Found no mod with this ID.");
|
||||
|
||||
// get latest stable release (if not latest)
|
||||
if (latest.IsPrerelease)
|
||||
{
|
||||
preview = latest;
|
||||
latest = await this.Client.GetLatestReleaseAsync(id, includePrerelease: false);
|
||||
}
|
||||
|
||||
// return data
|
||||
return new ModInfoModel(name: id, version: this.NormaliseVersion(latest?.Tag), previewVersion: this.NormaliseVersion(preview?.Tag), url: $"https://github.com/{id}/releases");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories
|
|||
return new ModInfoModel("Found no mod with this ID.");
|
||||
if (mod.Error != null)
|
||||
return new ModInfoModel(mod.Error);
|
||||
return new ModInfoModel(mod.Name, this.NormaliseVersion(mod.Version), mod.Url);
|
||||
return new ModInfoModel(name: mod.Name, version: this.NormaliseVersion(mod.Version), url: mod.Url);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -74,7 +74,8 @@ namespace StardewModdingAPI.Web
|
|||
|
||||
services.AddSingleton<IGitHubClient>(new GitHubClient(
|
||||
baseUrl: api.GitHubBaseUrl,
|
||||
releaseUrlFormat: api.GitHubReleaseUrlFormat,
|
||||
stableReleaseUrlFormat: api.GitHubStableReleaseUrlFormat,
|
||||
anyReleaseUrlFormat: api.GitHubAnyReleaseUrlFormat,
|
||||
userAgent: userAgent,
|
||||
acceptHeader: api.GitHubAcceptHeader,
|
||||
username: api.GitHubUsername,
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
"ChucklefishModPageUrlFormat": "resources/{0}",
|
||||
|
||||
"GitHubBaseUrl": "https://api.github.com",
|
||||
"GitHubReleaseUrlFormat": "repos/{0}/releases/latest",
|
||||
"GitHubStableReleaseUrlFormat": "repos/{0}/releases/latest",
|
||||
"GitHubAnyReleaseUrlFormat": "repos/{0}/releases?per_page=1",
|
||||
"GitHubAcceptHeader": "application/vnd.github.v3+json",
|
||||
"GitHubUsername": null, // see top note
|
||||
"GitHubPassword": null, // see top note
|
||||
|
|
Loading…
Reference in New Issue