/// <summary> /// Download assets from a previous release into the releases folder. /// </summary> /// <param name="release"></param> private static void getAssetsFromRelease(GitHubRelease release) { if (!canGitHub) { return; } //there's a previous release for this project. var assetReq = new JsonWebRequest <List <GitHubObject> >($"{GitHubApiEndpoint}/{release.Id}/assets"); assetReq.AuthenticatedBlockingPerform(); var assets = assetReq.ResponseObject; //make sure our RELEASES file is the same as the last build on the server. var releaseAsset = assets.FirstOrDefault(a => a.Name == "RELEASES"); //if we don't have a RELEASES asset then the previous release likely wasn't a Squirrel one. if (releaseAsset == null) { return; } bool requireDownload = false; if (!File.Exists(Path.Combine(releases_folder, $"{PackageName}-{release.Name}-full.nupkg"))) { write("Last version's package not found locally.", ConsoleColor.Red); requireDownload = true; } else { var lastReleases = new RawFileWebRequest($"{GitHubApiEndpoint}/assets/{releaseAsset.Id}"); lastReleases.AuthenticatedBlockingPerform(); if (File.ReadAllText(Path.Combine(releases_folder, "RELEASES")) != lastReleases.ResponseString) { write("Server's RELEASES differed from ours.", ConsoleColor.Red); requireDownload = true; } } if (!requireDownload) { return; } write("Refreshing local releases directory..."); refreshDirectory(releases_folder); foreach (var a in assets) { if (a.Name.EndsWith(".exe") || a.Name.EndsWith(".app.zip")) { continue; } write($"- Downloading {a.Name}...", ConsoleColor.Yellow); new FileWebRequest(Path.Combine(releases_folder, a.Name), $"{GitHubApiEndpoint}/assets/{a.Id}").AuthenticatedBlockingPerform(); } }
private static void uploadBuild(string version) { if (!canGitHub || string.IsNullOrEmpty(CodeSigningCertificate)) { return; } write("Publishing to GitHub..."); var req = new JsonWebRequest <GitHubRelease>($"{GitHubApiEndpoint}") { Method = HttpMethod.Post, }; GitHubRelease targetRelease = getLastGithubRelease(); if (targetRelease == null || targetRelease.TagName != version) { write($"- Creating release {version}...", ConsoleColor.Yellow); req.AddRaw(JsonConvert.SerializeObject(new GitHubRelease { Name = version, Draft = true, })); req.AuthenticatedBlockingPerform(); targetRelease = req.ResponseObject; } else { write($"- Adding to existing release {version}...", ConsoleColor.Yellow); } var assetUploadUrl = targetRelease.UploadUrl.Replace("{?name,label}", "?name={0}"); foreach (var a in Directory.GetFiles(releases_folder).Reverse()) //reverse to upload RELEASES first. { if (Path.GetFileName(a).StartsWith('.')) { continue; } write($"- Adding asset {a}...", ConsoleColor.Yellow); var upload = new WebRequest(assetUploadUrl, Path.GetFileName(a)) { Method = HttpMethod.Post, Timeout = 240000, ContentType = "application/octet-stream", }; upload.AddRaw(File.ReadAllBytes(a)); upload.AuthenticatedBlockingPerform(); } openGitHubReleasePage(); }
/// <summary> /// Download assets from a previous release into the releases folder. /// </summary> /// <param name="release"></param> private static void getAssetsFromRelease(GitHubRelease release) { }
public static void Main(string[] args) { interactive = args.Length == 0; displayHeader(); findSolutionPath(); if (!Directory.Exists(releases_folder)) { write("WARNING: No release directory found. Make sure you want this!", ConsoleColor.Yellow); Directory.CreateDirectory(releases_folder); } GitHubRelease lastRelease = null; if (canGitHub) { write("Checking GitHub releases..."); lastRelease = getLastGithubRelease(); if (lastRelease == null) { write("This is the first GitHub release"); } else { write($"Last GitHub release was {lastRelease.Name}."); if (lastRelease.Draft) { write("WARNING: This is a pending draft release! You might not want to push a build with this present.", ConsoleColor.Red); } } } //increment build number until we have a unique one. string verBase = DateTime.Now.ToString("yyyy.Mdd."); int increment = 0; if (lastRelease?.TagName.StartsWith(verBase) ?? false) { increment = int.Parse(lastRelease.TagName.Split('.')[2]) + (IncrementVersion ? 1 : 0); } string version = $"{verBase}{increment}"; if (args.Length > 1 && !string.IsNullOrEmpty(args[1])) { version = args[1]; } Console.ResetColor(); Console.WriteLine($"Increment Version: {IncrementVersion}"); Console.WriteLine($"Signing Certificate: {CodeSigningCertificate}"); Console.WriteLine($"Upload to GitHub: {GitHubUpload}"); Console.WriteLine(); Console.Write($"Ready to deploy {version}!"); pauseIfInteractive(); stopwatch.Start(); refreshDirectory(staging_folder); updateAppveyorVersion(version); write("Running build process..."); switch (RuntimeInfo.OS) { case RuntimeInfo.Platform.Windows: getAssetsFromRelease(lastRelease); runCommand("dotnet", $"publish -f netcoreapp2.2 -r win-x64 {ProjectName} -o {stagingPath} --configuration Release /p:Version={version}"); // change subsystem of dotnet stub to WINDOWS (defaults to console; no way to change this yet https://github.com/dotnet/core-setup/issues/196) runCommand("tools/editbin.exe", $"/SUBSYSTEM:WINDOWS {stagingPath}\\osu!.exe"); // add icon to dotnet stub runCommand("tools/rcedit-x64.exe", $"\"{stagingPath}\\osu!.exe\" --set-icon \"{iconPath}\""); write("Creating NuGet deployment package..."); runCommand(nugetPath, $"pack {NuSpecName} -Version {version} -Properties Configuration=Deploy -OutputDirectory {stagingPath} -BasePath {stagingPath}"); // prune once before checking for files so we can avoid erroring on files which aren't even needed for this build. pruneReleases(); checkReleaseFiles(); write("Running squirrel build..."); string codeSigningPassword = string.Empty; if (!string.IsNullOrEmpty(CodeSigningCertificate)) { if (args.Length > 0) { codeSigningPassword = args[0]; } else { Console.Write("Enter code signing password: "******"" : $"-n \"/a /f {codeSigningCertPath} /p {codeSigningPassword} /t http://timestamp.comodoca.com/authenticode\""; string nupkgFilename = $"{PackageName}.{version}.nupkg"; runCommand(squirrelPath, $"--releasify {stagingPath}\\{nupkgFilename} -r {releasesPath} --setupIcon {iconPath} --icon {iconPath} {codeSigningCmd} --no-msi"); // prune again to clean up before upload. pruneReleases(); // rename setup to install. File.Copy(Path.Combine(releases_folder, "Setup.exe"), Path.Combine(releases_folder, "install.exe"), true); File.Delete(Path.Combine(releases_folder, "Setup.exe")); break; case RuntimeInfo.Platform.MacOsx: // unzip the template app, with all structure existing except for dotnet published content. runCommand("unzip", $"\"osu!.app-template.zip\" -d {stagingPath}", false); runCommand("dotnet", $"publish -r osx-x64 {ProjectName} --configuration Release -o {stagingPath}/osu!.app/Contents/MacOS /p:Version={version}"); // correct permissions post-build. dotnet outputs 644 by default; we want 755. runCommand("chmod", $"-R 755 {stagingPath}/osu!.app"); // sign using apple codesign runCommand("codesign", $"--deep --force --verify --verbose --sign \"{CodeSigningCertificate}\" {stagingPath}/osu!.app"); // check codesign was successful runCommand("spctl", $"--assess -vvvv {stagingPath}/osu!.app"); // package for distribution runCommand("ditto", $"-ck --rsrc --keepParent --sequesterRsrc {stagingPath}/osu!.app {releasesPath}/osu!.app.zip"); break; case RuntimeInfo.Platform.Linux: //runCommand("rm",$"-rf {stagingPath}/osu.AppDir/"); //we clean this for next build (for example: changing dir structure). Delete if unneded // need to add --self-contained flag for AppImage distribution. runCommand("dotnet", $"publish -r linux-x64 {ProjectName} --self-contained --configuration Release -o {stagingPath}/osu.AppDir/ /p:Version={version}"); runCommand("chmod", $"-R 755 {stagingPath}/osu.AppDir/"); runCommand("rsync", $"-av --progress AppDir/ {stagingPath}/osu.AppDir/"); //TODO do we need to generate via code the appfiles? // uses the official AppImage Tools for creating AppImages. // see: https://github.com/AppImage/AppImageKit // make sure its in the same path as osu-deploy. runCommand("wget", "-nc https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"); runCommand("chmod", "-R 755 ./appimagetool-x86_64.AppImage"); Environment.SetEnvironmentVariable("ARCH", "x86_64"); //required for appimage runCommand("./appimagetool-x86_64.AppImage", $"--comp -s --sign-key {codeSigningCertPath} {stagingPath}/osu.AppDir"); //cannot test this... //runCommand("./appimagetool-x86_64.AppImage", $" {stagingPath}/osu.AppDir"); break; } if (GitHubUpload) { uploadBuild(version); } write("Done!"); pauseIfInteractive(); }
public static void Main(string[] args) { interactive = args.Length == 0; displayHeader(); findSolutionPath(); if (!Directory.Exists(releases_folder)) { write("WARNING: No release directory found. Make sure you want this!", ConsoleColor.Yellow); Directory.CreateDirectory(releases_folder); } GitHubRelease lastRelease = null; if (canGitHub) { write("Checking GitHub releases..."); lastRelease = getLastGithubRelease(); if (lastRelease == null) { write("This is the first GitHub release"); } else { write($"Last GitHub release was {lastRelease.Name}."); } } //increment build number until we have a unique one. string verBase = DateTime.Now.ToString("yyyy.Mdd."); int increment = 0; if (lastRelease?.TagName.StartsWith(verBase) ?? false) { increment = int.Parse(lastRelease.TagName.Split('.')[2]) + (IncrementVersion ? 1 : 0); } string version = $"{verBase}{increment}"; if (args.Length > 1 && !string.IsNullOrEmpty(args[1])) { version = args[1]; } Console.ResetColor(); Console.WriteLine($"Increment Version: {IncrementVersion}"); Console.WriteLine($"Signing Certificate: {CodeSigningCertificate}"); Console.WriteLine($"Upload to GitHub: {GitHubUpload}"); Console.WriteLine(); Console.Write($"Ready to deploy {version}!"); pauseIfInteractive(); stopwatch.Start(); refreshDirectory(staging_folder); updateAppveyorVersion(version); write("Running build process..."); switch (RuntimeInfo.OS) { case RuntimeInfo.Platform.Windows: getAssetsFromRelease(lastRelease); runCommand("dotnet", $"publish -f netcoreapp3.1 -r win-x64 {ProjectName} -o {stagingPath} --configuration Release /p:Version={version}"); // change subsystem of dotnet stub to WINDOWS (defaults to console; no way to change this yet https://github.com/dotnet/core-setup/issues/196) runCommand("tools/editbin.exe", $"/SUBSYSTEM:WINDOWS {stagingPath}\\osu!.exe"); // add icon to dotnet stub runCommand("tools/rcedit-x64.exe", $"\"{stagingPath}\\osu!.exe\" --set-icon \"{iconPath}\""); write("Creating NuGet deployment package..."); runCommand(nugetPath, $"pack {NuSpecName} -Version {version} -Properties Configuration=Deploy -OutputDirectory {stagingPath} -BasePath {stagingPath}"); // prune once before checking for files so we can avoid erroring on files which aren't even needed for this build. pruneReleases(); checkReleaseFiles(); write("Running squirrel build..."); string codeSigningPassword = string.Empty; if (!string.IsNullOrEmpty(CodeSigningCertificate)) { if (args.Length > 0) { codeSigningPassword = args[0]; } else { Console.Write("Enter code signing password: "******"" : $"-n \"/a /f {codeSigningCertPath} /p {codeSigningPassword} /t http://timestamp.comodoca.com/authenticode\""; string nupkgFilename = $"{PackageName}.{version}.nupkg"; runCommand(squirrelPath, $"--releasify {stagingPath}\\{nupkgFilename} -r {releasesPath} --setupIcon {iconPath} --icon {iconPath} {codeSigningCmd} --no-msi"); // prune again to clean up before upload. pruneReleases(); // rename setup to install. File.Copy(Path.Combine(releases_folder, "Setup.exe"), Path.Combine(releases_folder, "install.exe"), true); File.Delete(Path.Combine(releases_folder, "Setup.exe")); break; case RuntimeInfo.Platform.MacOsx: // unzip the template app, with all structure existing except for dotnet published content. runCommand("unzip", $"\"osu!.app-template.zip\" -d {stagingPath}", false); runCommand("dotnet", $"publish -r osx-x64 {ProjectName} --configuration Release -o {stagingPath}/osu!.app/Contents/MacOS /p:Version={version}"); string stagingApp = $"{stagingPath}/osu!.app"; string zippedApp = $"{releasesPath}/osu!.app.zip"; // correct permissions post-build. dotnet outputs 644 by default; we want 755. runCommand("chmod", $"-R 755 {stagingApp}"); // sign using apple codesign runCommand("codesign", $"--deep --force --verify --entitlements {Path.Combine(Environment.CurrentDirectory, "osu.entitlements")} -o runtime --verbose --sign \"{CodeSigningCertificate}\" {stagingApp}"); // check codesign was successful runCommand("spctl", $"--assess -vvvv {stagingApp}"); // package for distribution runCommand("ditto", $"-ck --rsrc --keepParent --sequesterRsrc {stagingApp} {zippedApp}"); // upload for notarisation runCommand("xcrun", $"altool --notarize-app --primary-bundle-id \"sh.ppy.osu.lazer\" --username \"{ConfigurationManager.AppSettings["AppleUsername"]}\" --password \"{ConfigurationManager.AppSettings["ApplePassword"]}\" --file {zippedApp}"); // TODO: make this actually wait properly write("Waiting for notarisation to complete.."); Thread.Sleep(60000 * 5); // staple notarisation result runCommand("xcrun", $"stapler staple {stagingApp}"); File.Delete(zippedApp); // repackage for distribution runCommand("ditto", $"-ck --rsrc --keepParent --sequesterRsrc {stagingApp} {zippedApp}"); break; case RuntimeInfo.Platform.Linux: // avoid use of unzip on Linux system, it is not preinstalled by default ZipFile.ExtractToDirectory("osu!.AppDir-template.zip", $"{stagingPath}"); // mark AppRun as executable, as zip does not contains executable information runCommand("chmod", $"+x {stagingPath}/osu!.AppDir/AppRun"); runCommand("dotnet", $"publish -f netcoreapp3.1 -r linux-x64 {ProjectName} -o {stagingPath}/osu!.AppDir/usr/bin/ --configuration Release /p:Version={version} --self-contained"); // mark output as executable runCommand("chmod", $"+x {stagingPath}/osu!.AppDir/usr/bin/osu!"); // copy png icon (for desktop file) File.Copy(Path.Combine(solutionPath, "assets/lazer.png"), $"{stagingPath}/osu!.AppDir/osu!.png"); // download appimagetool using (var client = new WebClient()) client.DownloadFile("https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage", $"{stagingPath}/appimagetool.AppImage"); // mark appimagetool as executable runCommand("chmod", $"a+x {stagingPath}/appimagetool.AppImage"); // create AppImage itself // gh-releases-zsync stands here for GitHub Releases ZSync, that is a way to check for updates // ppy|osu|latest stands for https://github.com/ppy/osu and get the latest release // osu.AppImage.zsync is AppImage update information file, that is generated by the tool // more information there https://docs.appimage.org/packaging-guide/optional/updates.html?highlight=update#using-appimagetool runCommand($"{stagingPath}/appimagetool.AppImage", $"\"{stagingPath}/osu!.AppDir\" -u \"gh-releases-zsync|ppy|osu|latest|osu.AppImage.zsync\" \"{Path.Combine(Environment.CurrentDirectory, "releases")}/osu.AppImage\" --sign", false); // mark finally the osu! AppImage as executable -> Don't compress it. runCommand("chmod", $"+x \"{Path.Combine(Environment.CurrentDirectory, "releases")}/osu.AppImage\""); // copy update information File.Move(Path.Combine(Environment.CurrentDirectory, "osu.AppImage.zsync"), $"{releases_folder}/osu.AppImage.zsync", true); break; } if (GitHubUpload) { uploadBuild(version); } write("Done!"); pauseIfInteractive(); }