diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ca1e0f1d0..3b922cf30 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,13 +3,13 @@ name: Build job on: workflow_dispatch: inputs: {} - push: - branches: [ master ] - paths-ignore: - - '.github/*' - - '.github/ISSUE_TEMPLATE/**' - - '*.yml' - - 'README.md' + #push: + # branches: [ master ] + # paths-ignore: + # - '.github/*' + # - '.github/ISSUE_TEMPLATE/**' + # - '*.yml' + # - 'README.md' pull_request: branches: [ master ] paths-ignore: @@ -59,14 +59,14 @@ jobs: - name: Clear run: dotnet clean && dotnet nuget locals all --clear - name: Build - run: dotnet build -c "${{ matrix.configuration }}" /p:Version="1.0.0" /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER + run: dotnet build -c "${{ matrix.configuration }}" /p:Version="1.1.0" /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER - name: Test run: dotnet test -c "${{ matrix.configuration }}" - name: Publish Ryujinx - run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish /p:Version="1.0.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained + run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish /p:Version="1.1.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained if: github.event_name == 'pull_request' - name: Publish Ryujinx.Headless.SDL2 - run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless /p:Version="1.0.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained + run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless /p:Version="1.1.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained if: github.event_name == 'pull_request' - name: Upload Ryujinx artifact uses: actions/upload-artifact@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..189a17cd9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,95 @@ +name: Release job + +on: + workflow_dispatch: + inputs: {} + push: + branches: [ master ] + paths-ignore: + - '.github/*' + - '.github/ISSUE_TEMPLATE/**' + - '*.yml' + - 'README.md' + + +jobs: + release: + runs-on: windows-latest + + env: + POWERSHELL_TELEMETRY_OPTOUT: 1 + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + RYUJINX_BASE_VERSION: "1.1" + RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master" + RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryujinx" + RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master" + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-dotnet@v1 + with: + dotnet-version: 6.0.x + - name: Ensure NuGet Source + uses: fabriciomurta/ensure-nuget-source@v1 + - name: Clear + run: dotnet clean && dotnet nuget locals all --clear + - name: Get version info + id: version_info + run: | + echo "::set-output name=build_version::${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} + 7181))" + echo "::set-output name=git_short_hash::$(git rev-parse --short "${{ github.sha }}")" + shell: bash + - name: Configure for release + run: | + sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/ReleaseInformations.cs + sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformations.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformations.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformations.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformations.cs + shell: bash + - name: Create output dir + run: "mkdir release_output" + - name: Publish Windows + run: | + dotnet publish -c Release -r win-x64 -o ./publish_windows/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained + dotnet publish -c Release -r win-x64 -o ./publish_windows_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained + - name: Packing Windows builds + run: | + pushd publish_windows + 7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish + popd + + pushd publish_windows_sdl2_headless + 7z a ../release_output/ryujinx-headless-sdl2-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish + popd + shell: bash + + - name: Publish Linux + run: | + dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained + dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained + + - name: Packing Linux builds + run: | + pushd publish_linux + tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish + popd + + pushd publish_linux_sdl2_headless + tar -czvf ../release_output/ryujinx-headless-sdl2-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish + popd + shell: bash + + - name: Pushing new release + uses: ncipollo/release-action@v1 + with: + name: ${{ steps.version_info.outputs.build_version }} + artifacts: "release_output/*.tar.gz,release_output/*.zip" + tag: ${{ steps.version_info.outputs.build_version }} + body: "For more informations about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)." + allowUpdates: true + removeArtifacts: true + replacesArtifacts: true + owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }} + repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }} + token: ${{ secrets.RELEASE_TOKEN }} diff --git a/Ryujinx.Common/Logging/Targets/FileLogTarget.cs b/Ryujinx.Common/Logging/Targets/FileLogTarget.cs index 5591c60b4..e83b26cdb 100644 --- a/Ryujinx.Common/Logging/Targets/FileLogTarget.cs +++ b/Ryujinx.Common/Logging/Targets/FileLogTarget.cs @@ -30,7 +30,7 @@ namespace Ryujinx.Common.Logging files[i].Delete(); } - string version = Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion; + string version = ReleaseInformations.GetVersion(); // Get path for the current time path = Path.Combine(logDir.FullName, $"Ryujinx_{version}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.log"); diff --git a/Ryujinx.Common/ReleaseInformations.cs b/Ryujinx.Common/ReleaseInformations.cs new file mode 100644 index 000000000..1dcb4bf30 --- /dev/null +++ b/Ryujinx.Common/ReleaseInformations.cs @@ -0,0 +1,32 @@ +namespace Ryujinx.Common +{ + // DO NOT EDIT, filled by CI + public static class ReleaseInformations + { + public static string BuildVersion = "%%RYUJINX_BUILD_VERSION%%"; + public static string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%"; + public static string ReleaseChannelName = "%%RYUJINX_TARGET_RELEASE_CHANNEL_NAME%%"; + public static string ReleaseChannelOwner = "%%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER%%"; + public static string ReleaseChannelRepo = "%%RYUJINX_TARGET_RELEASE_CHANNEL_REPO%%"; + + public static bool IsValid() + { + return !BuildGitHash.StartsWith("%%") && + !ReleaseChannelName.StartsWith("%%") && + !ReleaseChannelOwner.StartsWith("%%") && + !ReleaseChannelRepo.StartsWith("%%"); + } + + public static string GetVersion() + { + if (IsValid()) + { + return BuildVersion; + } + else + { + return "1.0.0-dirty"; + } + } + } +} diff --git a/Ryujinx.Headless.SDL2/Program.cs b/Ryujinx.Headless.SDL2/Program.cs index 71487a099..14c723603 100644 --- a/Ryujinx.Headless.SDL2/Program.cs +++ b/Ryujinx.Headless.SDL2/Program.cs @@ -3,6 +3,7 @@ using ARMeilleure.Translation.PTC; using CommandLine; using LibHac.Tools.FsSystem; using Ryujinx.Audio.Backends.SDL2; +using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Controller; @@ -57,7 +58,7 @@ namespace Ryujinx.Headless.SDL2 static void Main(string[] args) { - Version = Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion; + Version = ReleaseInformations.GetVersion(); Console.Title = $"Ryujinx Console {Version} (Headless SDL2)"; diff --git a/Ryujinx/Modules/Updater/Updater.cs b/Ryujinx/Modules/Updater/Updater.cs index 5ce896e5e..4a96208fa 100644 --- a/Ryujinx/Modules/Updater/Updater.cs +++ b/Ryujinx/Modules/Updater/Updater.cs @@ -3,6 +3,7 @@ using ICSharpCode.SharpZipLib.GZip; using ICSharpCode.SharpZipLib.Tar; using ICSharpCode.SharpZipLib.Zip; using Newtonsoft.Json.Linq; +using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.Ui; using Ryujinx.Ui.Widgets; @@ -29,17 +30,26 @@ namespace Ryujinx.Modules private static readonly string UpdatePublishDir = Path.Combine(UpdateDir, "publish"); private static readonly int ConnectionCount = 4; - private static string _jobId; private static string _buildVer; private static string _platformExt; private static string _buildUrl; private static long _buildSize; - - private const string AppveyorApiUrl = "https://ci.appveyor.com/api"; + + private const string GitHubApiURL = "https://api.github.com"; // On Windows, GtkSharp.Dependencies adds these extra dirs that must be cleaned during updates. private static readonly string[] WindowsDependencyDirs = new string[] { "bin", "etc", "lib", "share" }; + private static HttpClient ConstructHttpClient() + { + HttpClient result = new HttpClient(); + + // Required by GitHub to interract with APIs. + result.DefaultRequestHeaders.Add("User-Agent", "Ryujinx-Updater/1.0.0"); + + return result; + } + public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate) { if (Running) return; @@ -88,22 +98,45 @@ namespace Ryujinx.Modules return; } - // Get latest version number from Appveyor + // Get latest version number from GitHub API try { - using (HttpClient jsonClient = new HttpClient()) + using (HttpClient jsonClient = ConstructHttpClient()) { + string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformations.ReleaseChannelOwner}/{ReleaseInformations.ReleaseChannelRepo}/releases/latest"; + // Fetch latest build information - string fetchedJson = await jsonClient.GetStringAsync($"{AppveyorApiUrl}/projects/gdkchan/ryujinx/branch/master"); + string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL); JObject jsonRoot = JObject.Parse(fetchedJson); - JToken buildToken = jsonRoot["build"]; + JToken assets = jsonRoot["assets"]; - _jobId = (string)buildToken["jobs"][0]["jobId"]; - _buildVer = (string)buildToken["version"]; - _buildUrl = $"{AppveyorApiUrl}/buildjobs/{_jobId}/artifacts/ryujinx-{_buildVer}-{_platformExt}"; + _buildVer = (string)jsonRoot["name"]; - // If build not done, assume no new update are availaible. - if ((string)buildToken["jobs"][0]["status"] != "success") + foreach (JToken asset in assets) + { + string assetName = (string)asset["name"]; + string assetState = (string)asset["state"]; + string downloadURL = (string)asset["browser_download_url"]; + + if (!assetName.StartsWith("ryujinx-headless-sdl2") && assetName.EndsWith(_platformExt)) + { + _buildUrl = downloadURL; + + if (assetState != "uploaded") + { + if (showVersionUpToDate) + { + GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", ""); + } + + return; + } + + break; + } + } + + if (_buildUrl == null) { if (showVersionUpToDate) { @@ -117,7 +150,7 @@ namespace Ryujinx.Modules catch (Exception exception) { Logger.Error?.Print(LogClass.Application, exception.Message); - GtkDialog.CreateErrorDialog("An error occurred when trying to get release information from AppVeyor. This can be caused if a new release is being compiled by AppVeyor. Try again in a few minutes."); + GtkDialog.CreateErrorDialog("An error occurred when trying to get release information from GitHub Release. This can be caused if a new release is being compiled by GitHub Actions. Try again in a few minutes."); return; } @@ -128,8 +161,8 @@ namespace Ryujinx.Modules } catch { - GtkDialog.CreateWarningDialog("Failed to convert the received Ryujinx version from AppVeyor.", "Cancelling Update!"); - Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from AppVeyor!"); + GtkDialog.CreateWarningDialog("Failed to convert the received Ryujinx version from GitHub Release.", "Cancelling Update!"); + Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from GitHub Release!"); return; } @@ -148,7 +181,7 @@ namespace Ryujinx.Modules } // Fetch build size information to learn chunk sizes. - using (HttpClient buildSizeClient = new HttpClient()) + using (HttpClient buildSizeClient = ConstructHttpClient()) { try { @@ -520,7 +553,7 @@ namespace Ryujinx.Modules return false; } - if (Program.Version.Contains("dirty")) + if (Program.Version.Contains("dirty") || !ReleaseInformations.IsValid()) { if (showWarnings) { diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs index 1e0fdd3af..8cd5a9969 100644 --- a/Ryujinx/Program.cs +++ b/Ryujinx/Program.cs @@ -1,5 +1,6 @@ using ARMeilleure.Translation.PTC; using Gtk; +using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.GraphicsDriver; using Ryujinx.Common.Logging; @@ -68,7 +69,7 @@ namespace Ryujinx // Delete backup files after updating. Task.Run(Updater.CleanupUpdate); - Version = Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion; + Version = ReleaseInformations.GetVersion(); Console.Title = $"Ryujinx Console {Version}";