public async Task <CreateReleaseResult> Handle(CreateReleaseCommand request, CancellationToken cancellationToken) { if (!_versionParser.TryParse(request.Version, out var version)) { throw new ValidationException("Invalid version format"); } var app = await _db.Apps.SingleOrDefaultAsync(e => e.Uuid == request.AppId); if (app == null) { throw new AppException(AppErrorCode.NotFound, "Application was not found"); } var release = new Release { Uuid = Uuid.NewUuid(), CreatedAt = _clock.UtcNowMilliseconds, Version = request.Version, SortableVersion = _sortableVersionPrinter.Print(version), UniqueSortableVersionHack = version.IsPrerelease ? null : string.Empty, Title = request.Title, Description = request.Description, Commit = request.Commit, Prerelease = version.IsPrerelease, Published = false }; app.Releases.Add(release); return(new CreateReleaseResult { Id = release.Uuid }); }
public async Task <IEnumerable <GetReleasesListResultItem> > Handle(GetReleasesListQuery request, CancellationToken cancellationToken) { var app = await _db.Apps.SingleOrDefaultAsync(e => e.Name == request.App); if (app == null) { throw new AppException(AppErrorCode.NotFound, "Application was not found"); } bool includeAssets = false; foreach (var include in request.Include) { if (string.IsNullOrEmpty(include)) { continue; } switch (include) { case "assets": includeAssets = true; break; default: throw new ValidationException("Invalid include identifier"); } } var releasesDbQuery = _db.Releases.Where(e => e.AppId == app.Id && e.Published); if (includeAssets) { releasesDbQuery = releasesDbQuery.Include(e => e.Assets); } Domain.Versioning.Version sinceVersion = null; if (!string.IsNullOrEmpty(request.Filter.SinceRelease)) { if (!_versionParser.TryParse(request.Filter.SinceRelease, out sinceVersion, false)) { throw new ValidationException("Invalid version format"); } } bool hasPrereleaseBuildMetadata = request.Filter.Prerelease && sinceVersion != null && sinceVersion.BuildIdentifiers.Any(); if (sinceVersion != null) { var sortableVersion = _sortableVersionPrinter.Print(sinceVersion); // If build identifiers were included in the version then we need to do some more investigation to find it in the database if (hasPrereleaseBuildMetadata) { releasesDbQuery = releasesDbQuery.Where(e => e.SortableVersion.CompareTo(sortableVersion) >= 0); } else { releasesDbQuery = releasesDbQuery.Where(e => e.SortableVersion.CompareTo(sortableVersion) > 0); } } if (!request.Filter.Prerelease) { releasesDbQuery = releasesDbQuery.Where(e => !e.Prerelease); } releasesDbQuery = releasesDbQuery .OrderByDescending(e => e.SortableVersion) .ThenByDescending(e => e.CreatedAt); // We cannot limit here with prereleases since we need to check the returned releases more thoroughly and then limit if (!request.Filter.Prerelease) { if (request.Filter.Limit > 0) { releasesDbQuery = releasesDbQuery.Take(request.Filter.Limit); } } var releases = await releasesDbQuery.ToArrayAsync(); // When searching for a version that contains build metadata, we have a special case because prereleases can have the same sortable version, // varying only by build metadata, which may return multiple results from the database query with the same sortable version. // This can make it hard or even impossible to know exactly where in the history the version being searched for is located. // Without any more information to go on than the version itself, we need to look for an exact match and assume that any version after the matched // version's created time is newer. // If we can't find an exact match then there is currently no way to know which versions are newer so we just return the latest one. // If no build metadata is specified then we'll do regular version matching. if (hasPrereleaseBuildMetadata) { int index = Array.FindIndex(releases, 0, releases.Length, release => release.Version == request.Filter.SinceRelease); if (index != -1) { // Take the newer versions and make sure to exclude the one we searched for var temp = releases.Take(index); // Limit the results here for prereleases since we could not do it earlier when querying the database if (request.Filter.Limit > 0) { temp = temp.Take(request.Filter.Limit); } releases = temp.ToArray(); } else if (releases.Any()) { releases = releases.Take(1).ToArray(); } } return(releases.Select(release => new GetReleasesListResultItem { CreatedAt = release.CreatedAt, Version = release.Version, Title = release.Title, Description = release.Description, Commit = release.Commit, Prerelease = release.Prerelease, Assets = includeAssets ? getAssets(app, release, request.AssetTag) : null })); }