From 4eebd813f239267d659f3cbf4fa6cf5d47d99c26 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 17 May 2018 19:26:53 -0400 Subject: add beta for-developers download to smapi.io --- src/SMAPI.Internal/SemanticVersionImpl.cs | 2 +- src/SMAPI.Web/Controllers/IndexController.cs | 144 ++++++++++++++++----------- src/SMAPI.Web/Views/Index/Index.cshtml | 4 + 3 files changed, 90 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/SMAPI.Internal/SemanticVersionImpl.cs b/src/SMAPI.Internal/SemanticVersionImpl.cs index 6da16336..7ae34f07 100644 --- a/src/SMAPI.Internal/SemanticVersionImpl.cs +++ b/src/SMAPI.Internal/SemanticVersionImpl.cs @@ -5,7 +5,7 @@ namespace StardewModdingAPI.Internal { /// A low-level implementation of a semantic version with an optional release tag. /// The implementation is defined by Semantic Version 2.0 (http://semver.org/). - internal class SemanticVersionImpl + internal class SemanticVersionImpl : IComparable { /********* ** Accessors diff --git a/src/SMAPI.Web/Controllers/IndexController.cs b/src/SMAPI.Web/Controllers/IndexController.cs index 92b4f2c0..08b7363a 100644 --- a/src/SMAPI.Web/Controllers/IndexController.cs +++ b/src/SMAPI.Web/Controllers/IndexController.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; @@ -46,24 +48,23 @@ namespace StardewModdingAPI.Web.Controllers [HttpGet] public async Task Index() { - // fetch SMAPI releases - IndexVersionModel stableVersion = await this.Cache.GetOrCreateAsync("stable-version", async entry => - { - entry.AbsoluteExpiration = DateTimeOffset.UtcNow.Add(this.CacheTime); - GitRelease release = await this.GitHub.GetLatestReleaseAsync(this.RepositoryName, includePrerelease: false); - return new IndexVersionModel(release.Name, release.Body, this.GetMainDownloadUrl(release), this.GetDevDownloadUrl(release)); - }); - IndexVersionModel betaVersion = await this.Cache.GetOrCreateAsync("beta-version", async entry => - { - entry.AbsoluteExpiration = DateTimeOffset.UtcNow.Add(this.CacheTime); - GitRelease release = await this.GitHub.GetLatestReleaseAsync(this.RepositoryName, includePrerelease: true); - return release.IsPrerelease - ? this.GetBetaDownload(release) - : null; - }); + // choose versions + ReleaseVersion[] versions = await this.GetReleaseVersionsAsync(); + ReleaseVersion stableVersion = versions.LastOrDefault(version => !version.IsBeta && !version.IsForDevs); + ReleaseVersion stableVersionForDevs = versions.LastOrDefault(version => !version.IsBeta && version.IsForDevs); + ReleaseVersion betaVersion = versions.LastOrDefault(version => version.IsBeta && !version.IsForDevs); + ReleaseVersion betaVersionForDevs = versions.LastOrDefault(version => version.IsBeta && version.IsForDevs); // render view - var model = new IndexModel(stableVersion, betaVersion); + IndexVersionModel stableVersionModel = stableVersion != null + ? new IndexVersionModel(stableVersion.Version.ToString(), stableVersion.Release.Body, stableVersion.Asset.DownloadUrl, stableVersionForDevs?.Asset.DownloadUrl) + : new IndexVersionModel("unknown", "", "https://github.com/Pathoschild/SMAPI/releases", null); // just in case something goes wrong) + IndexVersionModel betaVersionModel = betaVersion != null + ? new IndexVersionModel(betaVersion.Version.ToString(), betaVersion.Release.Body, betaVersion.Asset.DownloadUrl, betaVersionForDevs?.Asset.DownloadUrl) + : null; + + // render view + var model = new IndexModel(stableVersionModel, betaVersionModel); return this.View(model); } @@ -71,62 +72,87 @@ namespace StardewModdingAPI.Web.Controllers /********* ** Private methods *********/ - /// Get the main download URL for a SMAPI release. - /// The SMAPI release. - private string GetMainDownloadUrl(GitRelease release) + /// Get a sorted, parsed list of SMAPI downloads for the latest releases. + private async Task GetReleaseVersionsAsync() { - // get main download URL - foreach (GitAsset asset in release.Assets ?? new GitAsset[0]) + return await this.Cache.GetOrCreateAsync("available-versions", async entry => { - if (Regex.IsMatch(asset.FileName, @"SMAPI-[\d\.]+-installer.zip")) - return asset.DownloadUrl; - } + entry.AbsoluteExpiration = DateTimeOffset.UtcNow.Add(this.CacheTime); - // fallback just in case - return "https://github.com/pathoschild/SMAPI/releases"; + // get releases + GitRelease stableRelease = await this.GitHub.GetLatestReleaseAsync(this.RepositoryName, includePrerelease: false); + GitRelease betaRelease = await this.GitHub.GetLatestReleaseAsync(this.RepositoryName, includePrerelease: true); + if (stableRelease.Tag == betaRelease.Tag) + betaRelease = null; + + // get versions + ReleaseVersion[] stableVersions = this.ParseReleaseVersions(stableRelease).ToArray(); + ReleaseVersion[] betaVersions = this.ParseReleaseVersions(betaRelease).ToArray(); + return stableVersions + .Concat(betaVersions) + .OrderBy(p => p.Version) + .ToArray(); + }); } - /// Get the for-developers download URL for a SMAPI release. - /// The SMAPI release. - private string GetDevDownloadUrl(GitRelease release) + /// Get a parsed list of SMAPI downloads for a release. + /// The GitHub release. + private IEnumerable ParseReleaseVersions(GitRelease release) { - // get dev download URL - foreach (GitAsset asset in release.Assets ?? new GitAsset[0]) + if (release?.Assets == null) + yield break; + + foreach (GitAsset asset in release.Assets) { - if (Regex.IsMatch(asset.FileName, @"SMAPI-[\d\.]+-installer-for-developers.zip")) - return asset.DownloadUrl; - } + Match match = Regex.Match(asset.FileName, @"SMAPI-(?[\d\.]+(?:-.+)?)-installer(?-for-developers)?.zip"); + if (!match.Success || !SemanticVersionImpl.TryParse(match.Groups["version"].Value, out SemanticVersionImpl version)) + continue; + bool isBeta = version.Tag != null; + bool isForDevs = match.Groups["forDevs"].Success; - // fallback just in case - return "https://github.com/pathoschild/SMAPI/releases"; + yield return new ReleaseVersion(release, asset, version, isBeta, isForDevs); + } } - /// Get the latest beta download for a SMAPI release. - /// The SMAPI release. - private IndexVersionModel GetBetaDownload(GitRelease release) + /// A parsed release download. + private class ReleaseVersion { - // get download with the latest version - SemanticVersionImpl latestVersion = null; - string latestUrl = null; - foreach (GitAsset asset in release.Assets ?? new GitAsset[0]) + /********* + ** Accessors + *********/ + /// The underlying GitHub release. + public GitRelease Release { get; } + + /// The underlying download asset. + public GitAsset Asset { get; } + + /// The SMAPI version. + public SemanticVersionImpl Version { get; } + + /// Whether this is a beta download. + public bool IsBeta { get; } + + /// Whether this is a 'for developers' download. + public bool IsForDevs { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The underlying GitHub release. + /// The underlying download asset. + /// The SMAPI version. + /// Whether this is a beta download. + /// Whether this is a 'for developers' download. + public ReleaseVersion(GitRelease release, GitAsset asset, SemanticVersionImpl version, bool isBeta, bool isForDevs) { - // parse version - Match versionMatch = Regex.Match(asset.FileName, @"SMAPI-([\d\.]+(?:-.+)?)-installer.zip"); - if (!versionMatch.Success || !SemanticVersionImpl.TryParse(versionMatch.Groups[1].Value, out SemanticVersionImpl version)) - continue; - - // save latest version - if (latestVersion == null || latestVersion.CompareTo(version) < 0) - { - latestVersion = version; - latestUrl = asset.DownloadUrl; - } + this.Release = release; + this.Asset = asset; + this.Version = version; + this.IsBeta = isBeta; + this.IsForDevs = isForDevs; } - - // return if prerelease - return latestVersion?.Tag != null - ? new IndexVersionModel(latestVersion.ToString(), release.Body, latestUrl, null) - : null; } } } diff --git a/src/SMAPI.Web/Views/Index/Index.cshtml b/src/SMAPI.Web/Views/Index/Index.cshtml index 347eebc7..91cdc793 100644 --- a/src/SMAPI.Web/Views/Index/Index.cshtml +++ b/src/SMAPI.Web/Views/Index/Index.cshtml @@ -86,6 +86,10 @@ else

For mod creators

-- cgit