protected override async Task <bool> DoFetchReleasesAsync() { if (ReleaseBranch == Branch.Unknown) { throw new ArgumentException("ReleaseBranch must not be unknown when fetching releases."); } var hasNewRelease = false; var releases = (await _gitHubClient.Repository.Release.GetAll("Radarr", "Radarr")).ToArray(); var validReleases = releases .Take(3) .Where(r => r.TagName.StartsWith("v") && VersionUtil.IsValid(r.TagName.Substring(1)) && r.Prerelease == (ReleaseBranch == Branch.Develop) ).Reverse(); foreach (var release in validReleases) { // Check if release has been published. if (!release.PublishedAt.HasValue) { continue; } var version = release.TagName.Substring(1); // Get an updateEntity var updateEntity = _database.UpdateEntities .Include(x => x.UpdateFiles) .FirstOrDefault(x => x.Version.Equals(version) && x.Branch.Equals(ReleaseBranch)); if (updateEntity == null) { // Create update object updateEntity = new UpdateEntity { Version = version, ReleaseDate = release.PublishedAt.Value.UtcDateTime, Branch = ReleaseBranch }; // Start tracking this object await _database.AddAsync(updateEntity); // Set new release to true. hasNewRelease = true; } // Parse changes var releaseBody = release.Body; var features = RegexUtil.ReleaseFeaturesGroup.Match(releaseBody); if (features.Success) { updateEntity.New.Clear(); foreach (Match match in RegexUtil.ReleaseChange.Matches(features.Groups["features"].Value)) { if (match.Success) { updateEntity.New.Add(match.Groups["text"].Value); } } } var fixes = RegexUtil.ReleaseFixesGroup.Match(releaseBody); if (fixes.Success) { updateEntity.Fixed.Clear(); foreach (Match match in RegexUtil.ReleaseChange.Matches(fixes.Groups["fixes"].Value)) { if (match.Success) { updateEntity.Fixed.Add(match.Groups["text"].Value); } } } // Process release files. foreach (var releaseAsset in release.Assets) { // Detect target operating system. OperatingSystem operatingSystem; if (releaseAsset.Name.Contains("windows.")) { operatingSystem = OperatingSystem.Windows; } else if (releaseAsset.Name.Contains("linux.")) { operatingSystem = OperatingSystem.Linux; } else if (releaseAsset.Name.Contains("osx.")) { operatingSystem = OperatingSystem.Osx; } else { continue; } // Check if exists in database. var updateFileEntity = _database.UpdateFileEntities .FirstOrDefault(x => x.UpdateEntityId == updateEntity.UpdateEntityId && x.OperatingSystem == operatingSystem); if (updateFileEntity != null) { continue; } // Calculate the hash of the zip file. var releaseZip = Path.Combine(_config.DataDirectory, ReleaseBranch.ToString(), releaseAsset.Name); string releaseHash; if (!File.Exists(releaseZip)) { Directory.CreateDirectory(Path.GetDirectoryName(releaseZip)); using (var fileStream = File.OpenWrite(releaseZip)) using (var artifactStream = await _httpClient.GetStreamAsync(releaseAsset.BrowserDownloadUrl)) { await artifactStream.CopyToAsync(fileStream); } } using (var stream = File.OpenRead(releaseZip)) { using (var sha = SHA256.Create()) { releaseHash = BitConverter.ToString(sha.ComputeHash(stream)).Replace("-", "").ToLower(); } } File.Delete(releaseZip); // Add to database. updateEntity.UpdateFiles.Add(new UpdateFileEntity { OperatingSystem = operatingSystem, Filename = releaseAsset.Name, Url = releaseAsset.BrowserDownloadUrl, Hash = releaseHash }); } // Save all changes to the database. await _database.SaveChangesAsync(); } return(hasNewRelease); }
protected override async Task <bool> DoFetchReleasesAsync() { LogManager.GetCurrentClassLogger().Warn("AppVeyorReleaseSource: DoFetchReleasesAsync"); if (ReleaseBranch == Branch.Unknown) { throw new ArgumentException("ReleaseBranch must not be unknown when fetching releases."); } var hasNewRelease = false; var historyUrl = $"https://ci.appveyor.com/api/projects/{AccountName}/{ProjectSlug}/history?recordsNumber=10&branch=develop"; var historyData = await _httpClient.GetStringAsync(historyUrl); var history = JsonConvert.DeserializeObject <AppVeyorProjectHistory>(historyData); // Store here temporarily so we don't break on not processed builds. var lastBuild = _lastBuildId; // Make sure we dont distribute; // - pull requests, // - unsuccesful builds, // - tagged builds (duplicate). foreach (var build in history.Builds.Where(x => !x.PullRequestId.HasValue && !x.IsTag).ToList()) { LogManager.GetCurrentClassLogger().Warn("AppVeyorReleaseSource: Build > " + build.Version); if (lastBuild.HasValue && lastBuild.Value >= build.BuildId) { break; } if (build.PullRequestId.HasValue || build.IsTag) { continue; } var buildExtendedData = await _httpClient.GetStringAsync($"https://ci.appveyor.com/api/projects/{AccountName}/{ProjectSlug}/build/{build.Version}"); var buildExtended = JsonConvert.DeserializeObject <AppVeyorProjectLastBuild>(buildExtendedData).Build; LogManager.GetCurrentClassLogger().Warn("AppVeyorReleaseSource: Got extended data"); // Filter out incomplete builds var buildJob = buildExtended.Jobs.FirstOrDefault(); if (buildJob == null || buildJob.ArtifactsCount == 0 || !buildExtended.Started.HasValue) { continue; } // Grab artifacts var artifactsPath = $"https://ci.appveyor.com/api/buildjobs/{buildJob.JobId}/artifacts"; var artifactsData = await _httpClient.GetStringAsync(artifactsPath); var artifacts = JsonConvert.DeserializeObject <AppVeyorArtifact[]>(artifactsData); LogManager.GetCurrentClassLogger().Warn("AppVeyorReleaseSource: Got artifacts"); // Get an updateEntity var updateEntity = await _database.UpdateEntities .Include(x => x.UpdateFiles) .FirstOrDefaultAsync(x => x.Version.Equals(buildExtended.Version) && x.Branch.Equals(ReleaseBranch)); if (updateEntity == null) { // Create update object updateEntity = new UpdateEntity { Version = buildExtended.Version, ReleaseDate = buildExtended.Started.Value.UtcDateTime, Branch = ReleaseBranch, New = new List <string> { build.Message } }; // Add extra message if (!string.IsNullOrWhiteSpace(build.MessageExtended)) { updateEntity.New.Add(build.MessageExtended); } // Start tracking this object await _database.AddAsync(updateEntity); // Set new release to true. hasNewRelease = true; } // Process artifacts foreach (var artifact in artifacts) { // Detect target operating system. OperatingSystem operatingSystem; if (artifact.FileName.Contains("windows.")) { operatingSystem = OperatingSystem.Windows; } else if (artifact.FileName.Contains("linux.")) { operatingSystem = OperatingSystem.Linux; } else if (artifact.FileName.Contains("osx.")) { operatingSystem = OperatingSystem.Osx; } else { continue; } // Check if exists in database. var updateFileEntity = _database.UpdateFileEntities .FirstOrDefault(x => x.UpdateEntityId == updateEntity.UpdateEntityId && x.OperatingSystem == operatingSystem); if (updateFileEntity != null) { continue; } // Calculate the hash of the zip file. var releaseDownloadUrl = $"{artifactsPath}/{artifact.FileName}"; var releaseFileName = artifact.FileName.Split('/').Last(); var releaseZip = Path.Combine(_config.DataDirectory, ReleaseBranch.ToString(), releaseFileName); string releaseHash; LogManager.GetCurrentClassLogger().Warn("AppVeyorReleaseSource: Dest " + releaseZip); if (!File.Exists(releaseZip)) { Directory.CreateDirectory(Path.GetDirectoryName(releaseZip)); LogManager.GetCurrentClassLogger().Warn("AppVeyorReleaseSource: Created dir"); await File.WriteAllBytesAsync(releaseZip, await _httpClient.GetByteArrayAsync(releaseDownloadUrl)); LogManager.GetCurrentClassLogger().Warn("AppVeyorReleaseSource: Wrote all bytes"); } using (var stream = File.OpenRead(releaseZip)) { using (var sha = SHA256.Create()) { releaseHash = BitConverter.ToString(sha.ComputeHash(stream)).Replace("-", "").ToLower(); } } File.Delete(releaseZip); // Add to database. updateEntity.UpdateFiles.Add(new UpdateFileEntity { OperatingSystem = operatingSystem, Filename = releaseFileName, Url = releaseDownloadUrl, Hash = releaseHash }); } // Save all changes to the database. await _database.SaveChangesAsync(); // Make sure we atleast skip this build next time. if (_lastBuildId == null || _lastBuildId.Value < build.BuildId) { _lastBuildId = build.BuildId; } } return(hasNewRelease); }
protected override async Task <bool> DoFetchReleasesAsync() { if (ReleaseBranch == Branch.Unknown) { throw new ArgumentException("ReleaseBranch must not be unknown when fetching releases."); } var hasNewRelease = false; var historyUrl = $"https://dev.azure.com/{AccountName}/{ProjectSlug}/_apis/build/builds?api-version=5.1&branchName=refs/heads/{BranchName}&reasonFilter=individualCI&statusFilter=completed&resultFilter=succeeded&queryOrder=startTimeDescending&$top=5"; var historyData = await _httpClient.GetStringAsync(historyUrl); var history = JsonConvert.DeserializeObject <AzureList <AzureProjectBuild> >(historyData).Value; // Store here temporarily so we don't break on not processed builds. var lastBuild = _lastBuildId; // URL query has filtered to most recent 5 successful, completed builds foreach (var build in history) { if (lastBuild.HasValue && lastBuild.Value >= build.BuildId) { break; } // Found a build that hasn't started yet..? if (!build.Started.HasValue) { break; } // Get build changes var changesPath = $"https://dev.azure.com/{AccountName}/{ProjectSlug}/_apis/build/builds/{build.BuildId}/changes?api-version=5.1"; var changesData = await _httpClient.GetStringAsync(changesPath); var changes = JsonConvert.DeserializeObject <AzureList <AzureChange> >(changesData).Value; // Grab artifacts var artifactsPath = $"https://dev.azure.com/{AccountName}/{ProjectSlug}/_apis/build/builds/{build.BuildId}/artifacts?api-version=5.1"; var artifactsData = await _httpClient.GetStringAsync(artifactsPath); var artifacts = JsonConvert.DeserializeObject <AzureList <AzureArtifact> >(artifactsData).Value; // there should be a single artifact called 'Packages' we parse for packages var artifact = artifacts.FirstOrDefault(x => x.Name == PackageArtifactName); if (artifact == null) { continue; } // Download the manifest var manifestPath = $"https://dev.azure.com/{AccountName}/{ProjectSlug}/_apis/build/builds/{build.BuildId}/artifacts?artifactName={artifact.Name}&fileId={artifact.Resource.Data}&fileName=manifest&api-version=5.1"; var manifestData = await _httpClient.GetStringAsync(manifestPath); var files = JsonConvert.DeserializeObject <AzureManifest>(manifestData).Files; // Get an updateEntity var updateEntity = _database.UpdateEntities .Include(x => x.UpdateFiles) .FirstOrDefault(x => x.Version.Equals(build.Version) && x.Branch.Equals(ReleaseBranch)); if (updateEntity == null) { // Create update object updateEntity = new UpdateEntity { Version = build.Version, ReleaseDate = build.Started.Value.UtcDateTime, Branch = ReleaseBranch, New = changes.Select(x => x.Message).ToList() }; // Start tracking this object await _database.AddAsync(updateEntity); // Set new release to true. hasNewRelease = true; } // Process artifacts foreach (var file in files) { // Detect target operating system. OperatingSystem operatingSystem; if (file.Path.Contains("windows.") && file.Path.ToLower().Contains(".zip")) { operatingSystem = OperatingSystem.Windows; } else if (file.Path.Contains("linux.")) { operatingSystem = OperatingSystem.Linux; } else if (file.Path.Contains("osx.")) { operatingSystem = OperatingSystem.Osx; } else { continue; } // Check if exists in database. var updateFileEntity = _database.UpdateFileEntities .FirstOrDefault(x => x.UpdateEntityId == updateEntity.UpdateEntityId && x.OperatingSystem == operatingSystem); if (updateFileEntity != null) { continue; } // Calculate the hash of the zip file. var releaseFileName = Path.GetFileName(file.Path); var releaseDownloadUrl = $"https://dev.azure.com/{AccountName}/{ProjectSlug}/_apis/build/builds/{build.BuildId}/artifacts?artifactName={artifact.Name}&fileId={file.Blob.Id}&fileName={releaseFileName}&api-version=5.1"; var releaseZip = Path.Combine(_config.DataDirectory, ReleaseBranch.ToString(), releaseFileName); string releaseHash; if (!File.Exists(releaseZip)) { Directory.CreateDirectory(Path.GetDirectoryName(releaseZip)); using (var fileStream = File.OpenWrite(releaseZip)) using (var artifactStream = await _httpClient.GetStreamAsync(releaseDownloadUrl)) { await artifactStream.CopyToAsync(fileStream); } } using (var stream = File.OpenRead(releaseZip)) { using (var sha = SHA256.Create()) { releaseHash = BitConverter.ToString(sha.ComputeHash(stream)).Replace("-", "").ToLower(); } } File.Delete(releaseZip); // Add to database. updateEntity.UpdateFiles.Add(new UpdateFileEntity { OperatingSystem = operatingSystem, Filename = releaseFileName, Url = releaseDownloadUrl, Hash = releaseHash }); } // Save all changes to the database. await _database.SaveChangesAsync(); // Make sure we atleast skip this build next time. if (_lastBuildId == null || _lastBuildId.Value < build.BuildId) { _lastBuildId = build.BuildId; } } return(hasNewRelease); }