public ChangeSetViewModel(ChangeSet changeSet) { Id = changeSet.Id; ShortId = changeSet.Id.Substring(0, 12); AuthorName = changeSet.AuthorName; EmailHash = String.IsNullOrEmpty(changeSet.AuthorEmail) ? null : Hash(changeSet.AuthorEmail); Date = changeSet.Timestamp.ToString("u"); Message = Process(changeSet.Message); // Show first line only var reader = new StringReader(changeSet.Message); Summary = Process(Trim(reader.ReadLine(), 300)); }
public void GetOrCreateStatusFileUpdatesFileIfItAlreadyExists() { // Arrange var changeSet = new ChangeSet("test-changeset-id", "author", "*****@*****.**", "commit message", DateTimeOffset.UtcNow); var status = new Mock<IDeploymentStatusManager>(MockBehavior.Strict); var statusFile = new TestDeploymentStatusFile(); status.Setup(s => s.Open("test-changeset-id")).Returns(statusFile).Verifiable(); var deploymentManager = CreateDeploymentManager(status: status.Object); var tracer = Mock.Of<ITracer>(); // Act deploymentManager.GetOrCreateStatusFile(changeSet, tracer, "test-deployer"); // Assert status.Verify(); Assert.Equal("test-deployer", statusFile.Deployer); Assert.Equal("author", statusFile.Author); Assert.Equal("*****@*****.**", statusFile.AuthorEmail); Assert.Equal("commit message", statusFile.Message); }
public Task DeployAsync(IRepository repository, ChangeSet changeSet, string deployer, bool clean, bool needFileUpdate = true) { ++DeployCount; return Task.FromResult(1); }
public void GitRepoParsesCommitDetails(string id, ChangeSet expectedChangeset) { foreach (Type gitRepoType in new[] { typeof(LibGit2SharpRepository), typeof(GitExeRepository) }) { using (var testRepository = Git.Clone("Mvc3Application_NoSolution")) { // Arrange var gitRepo = (IGitRepository)Activator.CreateInstance(gitRepoType, testRepository.Environment, new MockDeploymentSettingsManager(), NullTracerFactory.Instance); // Act var changeset = gitRepo.GetChangeSet(id); // Assert Assert.Equal(expectedChangeset.Id, changeset.Id); Assert.Equal(expectedChangeset.AuthorName, changeset.AuthorName); Assert.Equal(expectedChangeset.AuthorEmail, changeset.AuthorEmail); Assert.Equal(expectedChangeset.Message, changeset.Message.Trim()); Assert.Equal(expectedChangeset.Timestamp, changeset.Timestamp); } } }
// key goal is to create background tracer that is independent of request. public static void PerformBackgroundDeployment(DeploymentInfo deployInfo, IEnvironment environment, IDeploymentSettingsManager settings, TraceLevel traceLevel, Uri uri, IDisposable tempDeployment, IAutoSwapHandler autoSwapHandler, ChangeSet tempChangeSet) { var tracer = traceLevel <= TraceLevel.Off ? NullTracer.Instance : new XmlTracer(environment.TracePath, traceLevel); var traceFactory = new TracerFactory(() => tracer); var backgroundTrace = tracer.Step(XmlTracer.BackgroundTrace, new Dictionary<string, string> { {"url", uri.AbsolutePath}, {"method", "POST"} }); Task.Run(() => { try { // lock related string lockPath = Path.Combine(environment.SiteRootPath, Constants.LockPath); string deploymentLockPath = Path.Combine(lockPath, Constants.DeploymentLockFile); string statusLockPath = Path.Combine(lockPath, Constants.StatusLockFile); string hooksLockPath = Path.Combine(lockPath, Constants.HooksLockFile); var statusLock = new LockFile(statusLockPath, traceFactory); var hooksLock = new LockFile(hooksLockPath, traceFactory); var deploymentLock = new DeploymentLockFile(deploymentLockPath, traceFactory); var analytics = new Analytics(settings, new ServerConfiguration(), traceFactory); var deploymentStatusManager = new DeploymentStatusManager(environment, analytics, statusLock); var repositoryFactory = new RepositoryFactory(environment, settings, traceFactory); var siteBuilderFactory = new SiteBuilderFactory(new BuildPropertyProvider(), environment); var webHooksManager = new WebHooksManager(tracer, environment, hooksLock); var functionManager = new FunctionManager(environment, traceFactory); var deploymentManager = new DeploymentManager(siteBuilderFactory, environment, traceFactory, analytics, settings, deploymentStatusManager, deploymentLock, NullLogger.Instance, webHooksManager, autoSwapHandler, functionManager); var fetchHandler = new FetchHandler(tracer, deploymentManager, settings, deploymentStatusManager, deploymentLock, environment, null, repositoryFactory, null); // Perform deployment var acquired = deploymentLock.TryLockOperation(() => { fetchHandler.PerformDeployment(deployInfo, tempDeployment, tempChangeSet).Wait(); }, TimeSpan.Zero); if (!acquired) { if (tempDeployment != null) { tempDeployment.Dispose(); } using (tracer.Step("Update pending deployment marker file")) { // REVIEW: This makes the assumption that the repository url is the same. // If it isn't the result would be buggy either way. FileSystemHelpers.SetLastWriteTimeUtc(fetchHandler._markerFilePath, DateTime.UtcNow); } } } catch (Exception ex) { tracer.TraceError(ex); } finally { backgroundTrace.Dispose(); } }); }
public async Task PerformDeployment(DeploymentInfo deploymentInfo, IDisposable tempDeployment = null, ChangeSet tempChangeSet = null) { DateTime currentMarkerFileUTC; DateTime nextMarkerFileUTC = FileSystemHelpers.GetLastWriteTimeUtc(_markerFilePath); do { // save the current marker currentMarkerFileUTC = nextMarkerFileUTC; string targetBranch = _settings.GetBranch(); using (_tracer.Step("Performing fetch based deployment")) { // create temporary deployment before the actual deployment item started // this allows portal ui to readily display on-going deployment (not having to wait for fetch to complete). // in addition, it captures any failure that may occur before the actual deployment item started tempDeployment = tempDeployment ?? _deploymentManager.CreateTemporaryDeployment( Resources.ReceivingChanges, out tempChangeSet, deploymentInfo.TargetChangeset, deploymentInfo.Deployer); ILogger innerLogger = null; try { ILogger logger = _deploymentManager.GetLogger(tempChangeSet.Id); // Fetch changes from the repository innerLogger = logger.Log(Resources.FetchingChanges); IRepository repository = _repositoryFactory.EnsureRepository(deploymentInfo.RepositoryType); try { await deploymentInfo.Handler.Fetch(repository, deploymentInfo, targetBranch, innerLogger); } catch (BranchNotFoundException) { // mark no deployment is needed deploymentInfo.TargetChangeset = null; } // set to null as Deploy() below takes over logging innerLogger = null; // The branch or commit id to deploy string deployBranch = !String.IsNullOrEmpty(deploymentInfo.CommitId) ? deploymentInfo.CommitId : targetBranch; // In case the commit or perhaps fetch do no-op. if (deploymentInfo.TargetChangeset != null && ShouldDeploy(repository, deploymentInfo, deployBranch)) { // Perform the actual deployment var changeSet = repository.GetChangeSet(deployBranch); if (changeSet == null && !String.IsNullOrEmpty(deploymentInfo.CommitId)) { throw new InvalidOperationException(String.Format("Invalid revision '{0}'!", deploymentInfo.CommitId)); } // Here, we don't need to update the working files, since we know Fetch left them in the correct state // unless for GenericHandler where specific commitId is specified bool deploySpecificCommitId = !String.IsNullOrEmpty(deploymentInfo.CommitId); await _deploymentManager.DeployAsync(repository, changeSet, deploymentInfo.Deployer, clean: false, needFileUpdate: deploySpecificCommitId); } } catch (Exception ex) { if (innerLogger != null) { innerLogger.Log(ex); } // In case the commit or perhaps fetch do no-op. if (deploymentInfo.TargetChangeset != null) { IDeploymentStatusFile statusFile = _status.Open(deploymentInfo.TargetChangeset.Id); if (statusFile != null) { statusFile.MarkFailed(); } } throw; } // only clean up temp deployment if successful tempDeployment.Dispose(); } // check marker file and, if changed (meaning new /deploy request), redeploy. nextMarkerFileUTC = FileSystemHelpers.GetLastWriteTimeUtc(_markerFilePath); } while (deploymentInfo.IsReusable && currentMarkerFileUTC != nextMarkerFileUTC); }
public void Clean() { _latestChangeSet = null; }
internal IDeploymentStatusFile GetOrCreateStatusFile(ChangeSet changeSet, ITracer tracer, string deployer) { string id = changeSet.Id; using (tracer.Step("Collecting changeset information")) { // Check if the status file already exists. This would happen when we're doing a redeploy IDeploymentStatusFile statusFile = _status.Open(id); if (statusFile == null) { // Create the status file and store information about the commit statusFile = _status.Create(id); } statusFile.Message = changeSet.Message; statusFile.Author = changeSet.AuthorName; statusFile.Deployer = deployer; statusFile.AuthorEmail = changeSet.AuthorEmail; statusFile.IsReadOnly = changeSet.IsReadOnly; statusFile.Save(); return statusFile; } }
public async Task DeployAsync(IRepository repository, ChangeSet changeSet, string deployer, bool clean, bool needFileUpdate = true) { using (var deploymentAnalytics = new DeploymentAnalytics(_analytics, _settings)) { Exception exception = null; ITracer tracer = _traceFactory.GetTracer(); IDisposable deployStep = null; ILogger innerLogger = null; string targetBranch = null; // If we don't get a changeset, find out what branch we should be deploying and get the commit ID from it if (changeSet == null) { targetBranch = _settings.GetBranch(); changeSet = repository.GetChangeSet(targetBranch); if (changeSet == null) { throw new InvalidOperationException(String.Format("The current deployment branch is '{0}', but nothing has been pushed to it", targetBranch)); } } string id = changeSet.Id; IDeploymentStatusFile statusFile = null; try { deployStep = tracer.Step("DeploymentManager.Deploy(id)"); // Remove the old log file for this deployment id string logPath = GetLogPath(id); FileSystemHelpers.DeleteFileSafe(logPath); statusFile = GetOrCreateStatusFile(changeSet, tracer, deployer); statusFile.MarkPending(); ILogger logger = GetLogger(changeSet.Id); if (needFileUpdate) { using (tracer.Step("Updating to specific changeset")) { innerLogger = logger.Log(Resources.Log_UpdatingBranch, targetBranch ?? id); using (var writer = new ProgressWriter()) { // Update to the specific changeset or branch repository.Update(targetBranch ?? id); } } } if (_settings.ShouldUpdateSubmodules()) { using (tracer.Step("Updating submodules")) { innerLogger = logger.Log(Resources.Log_UpdatingSubmodules); repository.UpdateSubmodules(); } } if (clean) { tracer.Trace("Cleaning {0} repository", repository.RepositoryType); innerLogger = logger.Log(Resources.Log_CleaningRepository, repository.RepositoryType); repository.Clean(); } // set to null as Build() below takes over logging innerLogger = null; // Perform the build deployment of this changeset await Build(changeSet, tracer, deployStep, repository, deploymentAnalytics); } catch (Exception ex) { exception = ex; if (innerLogger != null) { innerLogger.Log(ex); } if (statusFile != null) { MarkStatusComplete(statusFile, success: false); } tracer.TraceError(ex); deploymentAnalytics.Error = ex.ToString(); if (deployStep != null) { deployStep.Dispose(); } } // Reload status file with latest updates statusFile = _status.Open(id); if (statusFile != null) { await _hooksManager.PublishEventAsync(HookEventTypes.PostDeployment, statusFile); } if (exception != null) { throw new DeploymentFailedException(exception); } } }
public void Deploy(IRepository repository, ChangeSet changeSet, string deployer, bool clean) { ITracer tracer = _traceFactory.GetTracer(); IDisposable deployStep = null; var deploymentRepository = new DeploymentRepository(repository); // If we don't get a changeset, find out what branch we should be deploying and update the repo to it if (changeSet == null) { string targetBranch = _settings.GetValue(SettingsKeys.Branch); deploymentRepository.Update(targetBranch); changeSet = deploymentRepository.GetChangeSet(repository.CurrentId); } string id = changeSet.Id; try { deployStep = tracer.Step("DeploymentManager.Deploy(id)"); // Remove the old log file for this deployment id string logPath = GetLogPath(id); FileSystemHelpers.DeleteFileSafe(logPath); ILogger logger = GetOrCreateStatusFile(changeSet, tracer, deployer); using (tracer.Step("Updating to specific changeset")) { // Update to the the specific changeset deploymentRepository.Update(id); } using (tracer.Step("Updating submodules")) { deploymentRepository.UpdateSubmodules(); } if (clean) { tracer.Trace("Cleaning {0} repository", repository.RepositoryType); logger.Log(Resources.Log_CleaningRepository, repository.RepositoryType); deploymentRepository.Clean(); } // Perform the build deployment of this changeset Build(id, tracer, deployStep); } catch (Exception ex) { tracer.TraceError(ex); if (deployStep != null) { deployStep.Dispose(); } throw; } }
public bool Commit(string message, string authorName, string emailAddress) { var tracer = _traceFactory.GetTracer(); using (tracer.Step("None repository commit")) { var changeSet = new ChangeSet(Guid.NewGuid().ToString("N"), !string.IsNullOrEmpty(authorName) ? authorName : Resources.Deployment_UnknownValue, !string.IsNullOrEmpty(emailAddress) ? emailAddress : Resources.Deployment_UnknownValue, message ?? Resources.Deployment_UnknownValue, DateTimeOffset.UtcNow); // Does not support rollback changeSet.IsReadOnly = true; // The lifetime is per request _httpContext.Items[_changeSetKey] = changeSet; tracer.Trace("Commit id: " + changeSet.Id, new Dictionary<string, string> { { "Messsage", changeSet.Message }, { "AuthorName", changeSet.AuthorName }, { "AuthorEmail", changeSet.AuthorEmail } }); } return true; }
public bool Commit(string message, string authorName) { var tracer = _traceFactory.GetTracer(); using (tracer.Step("None repository commit")) { string[] parts = String.IsNullOrEmpty(authorName) ? new string[0] : authorName.Split(new[] { '<', '>' }, StringSplitOptions.RemoveEmptyEntries); var changeSet = new ChangeSet(Guid.NewGuid().ToString("N"), parts.Length > 0 ? parts[0].Trim() : Resources.Deployment_UnknownValue, parts.Length > 1 ? parts[1].Trim() : Resources.Deployment_UnknownValue, message ?? Resources.Deployment_UnknownValue, DateTimeOffset.UtcNow); // Does not support rollback changeSet.IsReadOnly = true; // The lifetime is per request _httpContext.Items[_changeSetKey] = changeSet; tracer.Trace("Commit id: " + changeSet.Id, new Dictionary<string, string> { { "Messsage", changeSet.Message }, { "AuthorName", changeSet.AuthorName }, { "AuthorEmail", changeSet.AuthorEmail } }); } return true; }
public IDisposable CreateTemporaryDeployment(string statusText, ChangeSet changeSet = null, string deployedBy = null) { var tracer = _traceFactory.GetTracer(); using (tracer.Step("Creating temporary deployment")) { changeSet = changeSet ?? CreateTemporaryChangeSet(); DeploymentStatusFile statusFile = CreateStatusFile(changeSet.Id); statusFile.Id = changeSet.Id; statusFile.Message = changeSet.Message; statusFile.Author = changeSet.AuthorName; statusFile.Deployer = deployedBy; statusFile.AuthorEmail = changeSet.AuthorEmail; statusFile.Status = DeployStatus.Pending; statusFile.StatusText = statusText; statusFile.Save(_fileSystem); } // Return a handle that deletes the deployment on dispose. return new DisposableAction(() => { if (changeSet.IsTemporary) { DeleteTemporaryDeployment(changeSet.Id); } }); }
public void Deploy(IRepository repository, ChangeSet changeSet, string deployer, bool clean, bool needFileUpdate = true) { ++DeployCount; }
public IDisposable CreateTemporaryDeployment(string statusText, out ChangeSet tempChangeSet, ChangeSet changeset = null, string deployedBy = null) { tempChangeSet = GetChangeSet(); return new NoopDisposable(); }
private ILogger GetOrCreateStatusFile(ChangeSet changeSet, ITracer tracer, string deployer) { string id = changeSet.Id; ILogger logger = GetLogger(id); using (tracer.Step("Collecting changeset information")) { // Remove any old instance of a temporary deployment if exists DeleteTemporaryDeployment(); // Check if the status file already exists. This would happen when we're doing a redeploy DeploymentStatusFile statusFile = OpenStatusFile(id); if (statusFile == null) { // Create the status file and store information about the commit statusFile = CreateStatusFile(id); statusFile.Message = changeSet.Message; statusFile.Author = changeSet.AuthorName; statusFile.Deployer = deployer; statusFile.AuthorEmail = changeSet.AuthorEmail; statusFile.Save(_fileSystem); } } return logger; }
public void GitRepoParsesCommitDetails(string id, ChangeSet expectedChangeset) { using (var testRepository = Git.Clone("Mvc3Application_NoSolution")) { // Arrange var gitRepo = new GitExeRepository(testRepository.Environment, new MockDeploymentSettingsManager(), NullTracerFactory.Instance); // Act var changeset = gitRepo.GetChangeSet(id); // Assert Assert.Equal(expectedChangeset.Id, changeset.Id); Assert.Equal(expectedChangeset.AuthorName, changeset.AuthorName); Assert.Equal(expectedChangeset.AuthorEmail, changeset.AuthorEmail); Assert.Equal(expectedChangeset.Message, changeset.Message.Trim()); Assert.Equal(expectedChangeset.Timestamp, changeset.Timestamp); } }
public IDisposable CreateTemporaryDeployment(string statusText, ChangeSet changeSet = null, string deployedBy = null) { var tracer = _traceFactory.GetTracer(); string unknown = Resources.Deployment_UnknownValue; using (tracer.Step("Creating temporary deployment")) { changeSet = changeSet ?? new ChangeSet(TemporaryDeploymentId, unknown, unknown, unknown, DateTimeOffset.MinValue); DeploymentStatusFile statusFile = CreateStatusFile(TemporaryDeploymentId); statusFile.Id = changeSet.Id; statusFile.Message = changeSet.Message; statusFile.Author = changeSet.AuthorName; statusFile.Deployer = deployedBy; statusFile.AuthorEmail = changeSet.AuthorEmail; statusFile.Status = DeployStatus.Pending; statusFile.StatusText = statusText; statusFile.Save(_fileSystem); } // Return a handle that deletes the deployment on dispose. return new DisposableAction(DeleteTemporaryDeployment); }
public IDisposable CreateTemporaryDeployment(string statusText, out ChangeSet tempChangeSet, ChangeSet changeSet = null, string deployedBy = null) { var tracer = _traceFactory.GetTracer(); using (tracer.Step("Creating temporary deployment")) { changeSet = changeSet != null && changeSet.IsTemporary ? changeSet : CreateTemporaryChangeSet(); IDeploymentStatusFile statusFile = _status.Create(changeSet.Id); statusFile.Id = changeSet.Id; statusFile.Message = changeSet.Message; statusFile.Author = changeSet.AuthorName; statusFile.Deployer = deployedBy; statusFile.AuthorEmail = changeSet.AuthorEmail; statusFile.Status = DeployStatus.Pending; statusFile.StatusText = statusText; statusFile.IsTemporary = changeSet.IsTemporary; statusFile.IsReadOnly = changeSet.IsReadOnly; statusFile.Save(); } tempChangeSet = changeSet; // Return a handle that deletes the deployment on dispose. return new DisposableAction(() => { if (changeSet.IsTemporary) { _status.Delete(changeSet.Id); } }); }
public void Deploy(IRepository repository, ChangeSet changeSet, string deployer, bool clean) { ITracer tracer = _traceFactory.GetTracer(); IDisposable deployStep = null; ILogger innerLogger = null; string targetBranch = null; var deploymentRepository = new DeploymentRepository(repository); // If we don't get a changeset, find out what branch we should be deploying and get the commit ID from it if (changeSet == null) { targetBranch = _settings.GetBranch(); changeSet = deploymentRepository.GetChangeSet(targetBranch); } string id = changeSet.Id; IDeploymentStatusFile statusFile = null; try { deployStep = tracer.Step("DeploymentManager.Deploy(id)"); // Remove the old log file for this deployment id string logPath = GetLogPath(id); FileSystemHelpers.DeleteFileSafe(logPath); statusFile = GetOrCreateStatusFile(changeSet, tracer, deployer); statusFile.MarkPending(); ILogger logger = GetLogger(changeSet.Id); using (tracer.Step("Updating to specific changeset")) { innerLogger = logger.Log(Resources.Log_UpdatingBranch, targetBranch ?? id); using (var writer = new ProgressWriter()) { // Update to the the specific changeset deploymentRepository.Update(id); } } using (tracer.Step("Updating submodules")) { innerLogger = logger.Log(Resources.Log_UpdatingSubmodules); deploymentRepository.UpdateSubmodules(); } if (clean) { tracer.Trace("Cleaning {0} repository", repository.RepositoryType); innerLogger = logger.Log(Resources.Log_CleaningRepository, repository.RepositoryType); deploymentRepository.Clean(); } // set to null as Build() below takes over logging innerLogger = null; // Perform the build deployment of this changeset Build(id, tracer, deployStep); } catch (Exception ex) { if (innerLogger != null) { innerLogger.Log(ex); } if (statusFile != null) { statusFile.MarkFailed(); } tracer.TraceError(ex); if (deployStep != null) { deployStep.Dispose(); } throw; } }
/// <summary> /// Builds and deploys a particular changeset. Puts all build artifacts in a deployments/{id} /// </summary> private async Task Build(ChangeSet changeSet, ITracer tracer, IDisposable deployStep, IFileFinder fileFinder, DeploymentAnalytics deploymentAnalytics) { if (changeSet == null || String.IsNullOrEmpty(changeSet.Id)) { throw new ArgumentException("The changeSet.Id parameter is null or empty", "changeSet.Id"); } ILogger logger = null; IDeploymentStatusFile currentStatus = null; string buildTempPath = null; string id = changeSet.Id; try { logger = GetLogger(id); ILogger innerLogger = logger.Log(Resources.Log_PreparingDeployment, TrimId(id)); currentStatus = _status.Open(id); currentStatus.Complete = false; currentStatus.StartTime = DateTime.UtcNow; currentStatus.Status = DeployStatus.Building; currentStatus.StatusText = String.Format(CultureInfo.CurrentCulture, Resources.Status_BuildingAndDeploying, id); currentStatus.Save(); ISiteBuilder builder = null; string repositoryRoot = _environment.RepositoryPath; var perDeploymentSettings = DeploymentSettingsManager.BuildPerDeploymentSettingsManager(repositoryRoot, _settings); try { using (tracer.Step("Determining deployment builder")) { builder = _builderFactory.CreateBuilder(tracer, innerLogger, perDeploymentSettings, fileFinder); deploymentAnalytics.ProjectType = builder.ProjectType; tracer.Trace("Builder is {0}", builder.GetType().Name); } } catch (Exception ex) { // If we get a TargetInvocationException, use the inner exception instead to avoid // useless 'Exception has been thrown by the target of an invocation' messages var targetInvocationException = ex as System.Reflection.TargetInvocationException; if (targetInvocationException != null) { ex = targetInvocationException.InnerException; } _globalLogger.Log(ex); innerLogger.Log(ex); MarkStatusComplete(currentStatus, success: false); FailDeployment(tracer, deployStep, deploymentAnalytics, ex); return; } // Create a directory for the script output temporary artifacts // Use tick count (in hex) instead of guid to keep the path for getting to long buildTempPath = Path.Combine(_environment.TempPath, DateTime.UtcNow.Ticks.ToString("x")); FileSystemHelpers.EnsureDirectory(buildTempPath); var context = new DeploymentContext { NextManifestFilePath = GetDeploymentManifestPath(id), PreviousManifestFilePath = GetActiveDeploymentManifestPath(), Tracer = tracer, Logger = logger, GlobalLogger = _globalLogger, OutputPath = GetOutputPath(_environment, perDeploymentSettings), BuildTempPath = buildTempPath, CommitId = id, Message = changeSet.Message }; if (context.PreviousManifestFilePath == null) { // this file (/site/firstDeploymentManifest) capture the last active deployment when disconnecting SCM context.PreviousManifestFilePath = Path.Combine(_environment.SiteRootPath, Constants.FirstDeploymentManifestFileName); if (!FileSystemHelpers.FileExists(context.PreviousManifestFilePath)) { // In the first deployment we want the wwwroot directory to be cleaned, we do that using a manifest file // That has the expected content of a clean deployment (only one file: hostingstart.html) // This will result in KuduSync cleaning this file. context.PreviousManifestFilePath = Path.Combine(_environment.ScriptPath, Constants.FirstDeploymentManifestFileName); } } PreDeployment(tracer); using (tracer.Step("Building")) { try { await builder.Build(context); builder.PostBuild(context); await _functionManager.SyncTriggersAsync(); if (_settings.TouchWebConfigAfterDeployment()) { TryTouchWebConfig(context); } FinishDeployment(id, deployStep); deploymentAnalytics.Result = DeployStatus.Success.ToString(); } catch (Exception ex) { MarkStatusComplete(currentStatus, success: false); FailDeployment(tracer, deployStep, deploymentAnalytics, ex); return; } } } catch (Exception ex) { FailDeployment(tracer, deployStep, deploymentAnalytics, ex); } finally { // Clean the temp folder up CleanBuild(tracer, buildTempPath); } }
public ChangeSetDetail(ChangeSet changeSet) { ChangeSet = changeSet; Files = new Dictionary<string, FileInfo>(StringComparer.OrdinalIgnoreCase); }