private async Task SaveArtifacts(Product product, BuildResponse buildEngineBuild, bool successful)
        {
            DateTime?mostRecentArtifactDate = new DateTime(2018, 10, 1);
            var      productBuild           = await ProductBuildRepository.Get()
                                              .Where(pb => pb.ProductId == product.Id && pb.BuildId == product.WorkflowBuildId)
                                              .FirstOrDefaultAsync();

            if (buildEngineBuild.Artifacts != null && productBuild != null)
            {
                foreach (KeyValuePair <string, string> entry in buildEngineBuild.Artifacts)
                {
                    Log.Information($"Artifact: key={entry.Key}, value={entry.Value}");
                    if (!String.IsNullOrEmpty(entry.Value))
                    {
                        var artifactModifiedDate = await AddProductArtifactAsync(entry.Key, entry.Value, product, productBuild, successful);

                        if ((artifactModifiedDate != null) && (artifactModifiedDate > mostRecentArtifactDate))
                        {
                            mostRecentArtifactDate = artifactModifiedDate;
                        }
                    }
                }

                product.DateBuilt = mostRecentArtifactDate;
                await ProductRepository.UpdateAsync(product);
            }
        }
        private async Task UpdateProductBuild(BuildResponse buildEngineBuild, Product product, bool success)
        {
            var build = await ProductBuildRepository.Get().Where(pb => pb.ProductId == product.Id && pb.BuildId == product.WorkflowBuildId).FirstOrDefaultAsync();

            if (build == null)
            {
                throw new Exception($"Failed to find ProductBuild: BuildId={buildEngineBuild.Id}");
            }
            build.Success = success;
            await ProductBuildRepository.UpdateAsync(build);
        }
        protected async Task CreateBuildEngineBuildAsync(Product product, Dictionary <string, object> parmsDictionary, PerformContext context)
        {
            await ResetPreviousBuildAsync(product);

            BuildResponse buildResponse = null;

            if (SetBuildEngineEndpoint(product.Project.Organization))
            {
                var targets     = GetTargets(parmsDictionary, "apk play-listing");
                var environment = GetEnvironment(parmsDictionary);
                environment["PRODUCT_ID"] = product.Id.ToString();
                environment["PROJECT_ID"] = product.ProjectId.ToString();
                var build = new Build
                {
                    Targets     = targets,
                    Environment = environment
                };
                buildResponse = BuildEngineApi.CreateBuild(product.WorkflowJobId, build);
            }
            if ((buildResponse != null) && (buildResponse.Id != 0))
            {
                product.WorkflowBuildId = buildResponse.Id;
                var productBuild = new ProductBuild
                {
                    ProductId = product.Id,
                    BuildId   = product.WorkflowBuildId
                };
                await ProductBuildRepository.CreateAsync(productBuild);

                await ProductRepository.UpdateAsync(product);

                var monitorJob = Job.FromExpression <BuildEngineBuildService>(service => service.CheckBuild(product.Id));
                RecurringJobManager.AddOrUpdate(GetHangfireToken(product.Id), monitorJob, "* * * * *");
            }
            else
            {
                var messageParms = new Dictionary <string, object>()
                {
                    { "projectName", product.Project.Name },
                    { "productName", product.ProductDefinition.Name }
                };
                await SendNotificationOnFinalRetryAsync(context, product.Project.Organization, product.Project.Owner, "buildFailedUnableToCreate", messageParms);

                // Throw Exception to force retry
                throw new Exception("Create build failed");
            }
        }
        public async Task <int> GetVersionCodeAsync(Guid productId)
        {
            var product = await ProductRepository.Get()
                          .Where(p => p.Id == productId)
                          .Include(p => p.Project)
                          .ThenInclude(pr => pr.Organization)
                          .FirstOrDefaultAsync();

            if ((product == null) || (product.WorkflowJobId == 0) || (product.WorkflowBuildId == 0))
            {
                return(0);
            }

            var productBuild = await ProductBuildRepository.Get()
                               .Where(pb => pb.ProductId == product.Id && pb.BuildId == product.WorkflowBuildId)
                               .FirstOrDefaultAsync();

            if (productBuild == null)
            {
                return(0);
            }

            var versionCodeArtifact = await ProductArtifactRepository
                                      .Get().Where(a => a.ProductId == product.Id && a.ProductBuildId == productBuild.Id && a.ArtifactType == "version")
                                      .FirstOrDefaultAsync();

            var versionJson = WebClient.DownloadString(versionCodeArtifact.Url);
            var version     = JsonConvert.DeserializeObject <Dictionary <string, object> >(versionJson);

            if (version.ContainsKey("versionCode"))
            {
                var versionCode = version["versionCode"] as String;
                return(int.Parse(versionCode));
            }

            return(0);
        }
        protected async Task <DateTime?> AddProductArtifactAsync(string key, string value, Product product, ProductBuild productBuild, bool successful)
        {
            var productArtifact = new ProductArtifact
            {
                ProductId      = product.Id,
                ProductBuildId = productBuild.Id,
                ArtifactType   = key,
                Url            = value
            };
            var updatedArtifact  = WebRequestWrapper.GetFileInfo(productArtifact);
            var existingArtifact = await ProductArtifactRepository
                                   .Get().Where(a => a.ProductId == product.Id && a.ProductBuildId == productBuild.Id && a.ArtifactType == key && a.Url == value)
                                   .FirstOrDefaultAsync();

            if (existingArtifact != null)
            {
                // Not sure why we are getting multiple of these, but we don't want multiple entries.
                // Should we ignore it or update?  Ignore for now. Updating threw exceptions
                Log.Information($"Updating Artifact: Id={existingArtifact.Id}");
                updatedArtifact.Id = existingArtifact.Id;
                // await ProductArtifactRepository.UpdateAsync(updatedArtifact);
            }
            else
            {
                var newArtifact = await ProductArtifactRepository.CreateAsync(updatedArtifact);

                Log.Information($"Created Artifact: Id={newArtifact.Id}");
            }

            // On version.json, update the ProductBuild.Version
            if (key == "version" && updatedArtifact.ContentType == "application/json")
            {
                try
                {
                    var contents = WebClient.DownloadString(value);
                    var version  = JsonConvert.DeserializeObject <Dictionary <string, object> >(contents);
                    if (version.ContainsKey("version"))
                    {
                        productBuild.Version = version["version"] as String;
                        await ProductBuildRepository.UpdateAsync(productBuild);

                        if (successful)
                        {
                            product.VersionBuilt = version["version"] as String;
                            await ProductRepository.UpdateAsync(product);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex, $"Parsing {key}: {value}");
                }
            }

            // On play-listing-manifest.json, update the Project.DefaultLanguage
            if (key == "play-listing-manifest" && updatedArtifact.ContentType == "application/json")
            {
                try
                {
                    var contents = WebClient.DownloadString(value);
                    var manifest = JsonConvert.DeserializeObject <Dictionary <string, object> >(contents);
                    if (manifest.ContainsKey("default-language"))
                    {
                        var           languageName  = manifest["default-language"] as String;
                        StoreLanguage storeLanguage = await LanguageRepository.Get().Where(lang => lang.Name == languageName).FirstOrDefaultAsync();

                        if (storeLanguage != null)
                        {
                            product.StoreLanguageId = storeLanguage.Id;
                            await ProductRepository.UpdateAsync(product);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex, $"Parsing {key}: {value}");
                }
            }

            return(updatedArtifact.LastModified);
        }