示例#1
0
        public Task Build(DeploymentContext context)
        {
            var tcs = new TaskCompletionSource<object>();

            ILogger innerLogger = context.Logger.Log(Resources.Log_PreparingFiles);

            try
            {
                using (context.Tracer.Step("Copying files to output directory"))
                {
                    // Copy to the output path and use the previous manifest if there
                    DeploymentHelper.CopyWithManifest(_sourcePath, context.OutputPath, context.PreviousMainfest);
                }

                using (context.Tracer.Step("Building manifest"))
                {
                    // Generate a manifest from those build artifacts
                    context.ManifestWriter.AddFiles(_sourcePath);
                }

                // Log the copied files from the manifest
                innerLogger.LogFileList(context.ManifestWriter.GetPaths());
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                context.GlobalLogger.Log(ex);

                innerLogger.Log(ex);

                tcs.SetException(ex);

                // Bail out early
                return tcs.Task;
            }

            try
            {
                // Download node packages
                DownloadNodePackages(context);

                AddIISNodeConfig(context);

                tcs.SetResult(null);
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                // HACK: Log an empty error to the global logger (post receive hook console output).
                // The reason we don't log the real exception is because the 'live output' when downloding
                // npm packages has already been captured.
                context.GlobalLogger.LogError();

                tcs.SetException(ex);
            }

            return tcs.Task;
        }
示例#2
0
        public override Task Build(DeploymentContext context)
        {
            ILogger buildLogger = context.Logger.Log(Resources.Log_BuildingSolution, Path.GetFileName(SolutionPath));

            try
            {
                string propertyString = GetPropertyString();

                if (!String.IsNullOrEmpty(propertyString))
                {
                    propertyString = " /p:" + propertyString;
                }

                using (context.Tracer.Step("Running msbuild on solution"))
                {
                    // Build the solution first
                    string log = ExecuteMSBuild(context.Tracer, @"""{0}"" /verbosity:m /nologo{1}", SolutionPath, propertyString);
                    buildLogger.Log(log);
                }

                return BuildProject(context);
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                buildLogger.Log(ex);

                var tcs = new TaskCompletionSource<object>();
                tcs.SetException(ex);

                return tcs.Task;
            }
        }
示例#3
0
        protected override Task BuildProject(DeploymentContext context)
        {
            var tcs = new TaskCompletionSource<object>();
            ILogger copyLogger = context.Logger.Log(Resources.Log_PreparingFiles);

            try
            {
                using (context.Tracer.Step("Copying files to output directory"))
                {
                    // Copy to the output path
                    DeploymentHelper.CopyWithManifest(_projectPath, context.OutputPath, context.PreviousMainfest);
                }

                using (context.Tracer.Step("Building manifest"))
                {
                    // Generate the manifest from the project path
                    context.ManifestWriter.AddFiles(_projectPath);
                }

                // Log the copied files from the manifest
                copyLogger.LogFileList(context.ManifestWriter.GetPaths());

                tcs.SetResult(null);
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                copyLogger.Log(ex);

                tcs.SetException(ex);
            }

            return tcs.Task;
        }
示例#4
0
        protected override Task BuildProject(DeploymentContext context)
        {
            var tcs = new TaskCompletionSource<object>();
            var innerLogger = context.Logger.Log("Using website project {0}.", _projectPath);

            try
            {
                using (context.Profiler.Step("Copying files to output directory"))
                {
                    // Copy to the output path
                    DeploymentHelper.CopyWithManifest(_projectPath, context.OutputPath, context.PreviousMainfest);
                }

                using (context.Profiler.Step("Building manifest"))
                {
                    // Generate the manifest from the project path
                    context.ManifestWriter.AddFiles(_projectPath);
                }

                innerLogger.Log("Done.");
                tcs.SetResult(null);
            }
            catch (Exception e)
            {
                innerLogger.Log("Copying website failed.", LogEntryType.Error);
                innerLogger.Log(e);
                tcs.SetException(e);
            }

            return tcs.Task;
        }
示例#5
0
        /// <summary>
        /// Download node packages as part of the deployment
        /// </summary>
        private void DownloadNodePackages(ILogger logger, DeploymentContext context)
        {
            // Check to see if there's a package.json file
            string packagePath = Path.Combine(context.OutputPath, PackageJsonFile);

            if (!File.Exists(packagePath))
            {
                // If the package.json file doesn't exist then don't bother to run npm install
                return;
            }

            using (context.Profiler.Step("Downloading node packages"))
            {
                var npm = new NpmExecutable(context.OutputPath);

                if (!npm.IsAvailable)
                {
                    logger.Log("NPM not installed or couldn't be located. Skipping package installation.");
                    return;
                }

                // Set the npm proxy settings based on the default settings
                var proxy = WebRequest.DefaultWebProxy;
                var httpProxyUrl = proxy.GetProxy(new Uri("http://registry.npmjs.org/"));
                var httpsProxyUrl = proxy.GetProxy(new Uri("https://registry.npmjs.org/"));

                if (httpProxyUrl != null)
                {
                    npm.EnvironmentVariables["HTTP_PROXY"] = httpProxyUrl.ToString();
                }

                if (httpsProxyUrl != null)
                {
                    npm.EnvironmentVariables["HTTPS_PROXY"] = httpsProxyUrl.ToString();
                }

                // Use the temp path as the user profile path in case we don't have the right
                // permission set. This normally happens under IIS as a restricted user (ApplicationPoolIdentity).
                string npmUserProfile = Path.Combine(_tempPath, "npm");
                npm.EnvironmentVariables["USERPROFILE"] = npmUserProfile;
                npm.EnvironmentVariables["LocalAppData"] = npmUserProfile;
                npm.EnvironmentVariables["AppData"] = npmUserProfile;

                try
                {
                    // Use the http proxy since https is failing for some reason
                    npm.Execute("config set registry \"http://registry.npmjs.org/\"");
                }
                catch(Exception ex)
                {
                    // This fails if it's already set
                    Debug.WriteLine(ex.Message);
                }

                // Run install on the output directory
                string log = npm.Execute(context.Profiler, "install").Item1;
                logger.Log(log);
            }
        }
示例#6
0
        /// <summary>
        /// Download node packages as part of the deployment
        /// </summary>
        private void DownloadNodePackages(ILogger logger, DeploymentContext context)
        {
            // Check to see if there's a package.json file
            string packagePath = Path.Combine(context.OutputPath, PackageJsonFile);

            if (!File.Exists(packagePath))
            {
                // If the package.json file doesn't exist then don't bother to run npm install
                return;
            }

            using (context.Profiler.Step("Downloading node packages"))
            {
                var npm = new NpmExecutable(context.OutputPath);

                if (!npm.IsAvailable)
                {
                    logger.Log(Resources.Log_NpmNotInstalled);
                    return;
                }

                // Set the npm proxy settings based on the default settings
                var proxy = WebRequest.DefaultWebProxy;
                var httpUrl = new Uri("http://registry.npmjs.org/");
                var httpsUrl = new Uri("https://registry.npmjs.org/");
                var proxyHttpProxyUrl = proxy.GetProxy(httpUrl);
                var proxyHttpsProxyUrl = proxy.GetProxy(httpsUrl);

                if (proxyHttpProxyUrl != httpUrl)
                {
                    npm.EnvironmentVariables["HTTP_PROXY"] = proxyHttpProxyUrl.ToString();
                }

                if (proxyHttpsProxyUrl != httpsUrl)
                {
                    npm.EnvironmentVariables["HTTPS_PROXY"] = proxyHttpsProxyUrl.ToString();
                }

                try
                {
                    // Use the http proxy since https is failing for some reason
                    npm.Execute("config set registry \"http://registry.npmjs.org/\"");
                }
                catch (Exception ex)
                {
                    // This fails if it's already set
                    Debug.WriteLine(ex.Message);
                }

                // Run install on the output directory
                string log = npm.Execute(context.Profiler, "install").Item1;
                logger.Log(log);
            }
        }
示例#7
0
        public Task Build(DeploymentContext context)
        {
            var tcs = new TaskCompletionSource<object>();

            ILogger innerLogger = context.Logger.Log(Resources.Log_CopyingFiles);

            try
            {
                using (context.Tracer.Step("Copying files to output directory"))
                {
                    // Copy to the output path and use the previous manifest if there
                    DeploymentHelper.CopyWithManifest(_sourcePath, context.OutputPath, context.PreviousMainfest);
                }

                using (context.Tracer.Step("Building manifest"))
                {
                    // Generate a manifest from those build artifacts
                    context.ManifestWriter.AddFiles(_sourcePath);
                }

                // Log the copied files from the manifest
                innerLogger.LogFileList(context.ManifestWriter.GetPaths());
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                innerLogger.Log(ex);

                tcs.SetException(ex);

                // Bail out early
                return tcs.Task;
            }

            try
            {
                // Download node packages
                DownloadNodePackages(context);

                tcs.SetResult(null);
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                tcs.SetException(ex);
            }

            return tcs.Task;
        }
示例#8
0
        public Task Build(DeploymentContext context)
        {
            var tcs = new TaskCompletionSource<object>();

            ILogger customLogger = context.Logger.Log("Running custom deployment...");

            Executable exe = GetExecutable();
            exe.EnvironmentVariables[SourcePath] = _repositoryPath;
            exe.EnvironmentVariables[TargetPath] = context.OutputPath;

            // Populate the enviornment with the build propeties
            foreach (var property in _propertyProvider.GetProperties())
            {
                exe.EnvironmentVariables[property.Key] = property.Value;
            }

            // Add the msbuild path and git path to the %PATH% so more tools are available
            var toolsPaths = new[] {
                Path.GetDirectoryName(PathUtility.ResolveMSBuildPath()),
                Path.GetDirectoryName(PathUtility.ResolveGitPath())
            };

            exe.AddToPath(toolsPaths);

            try
            {
                string output = exe.ExecuteWithConsoleOutput(context.Tracer, String.Empty).Item1;

                customLogger.Log(output);

                tcs.SetResult(null);
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                // HACK: Log an empty error to the global logger (post receive hook console output).
                // The reason we don't log the real exception is because the 'live output' running
                // msbuild has already been captured.
                context.GlobalLogger.LogError();

                customLogger.Log(ex);

                tcs.SetException(ex);
            }

            return tcs.Task;
        }
示例#9
0
        public async Task HandleAutoSwap(string currentDeploymetId, DeploymentContext context)
        {
            ITracer tracer = context.Tracer;
            if (!IsAutoSwapEnabled())
            {

                tracer.Trace("AutoSwap is not enabled");
                return;
            }

            string jwtToken = System.Environment.GetEnvironmentVariable(Constants.SiteRestrictedJWT);
            if (string.IsNullOrWhiteSpace(jwtToken))
            {
                tracer.Trace("Jwt token is null");
                return;
            }

            // active deployment is always a success deployment
            string lastDeploymentId = _deploymentStatusManager.ActiveDeploymentId;
            if (string.Equals(currentDeploymetId, lastDeploymentId, StringComparison.OrdinalIgnoreCase))
            {
                tracer.Trace("Deployment haven't changed, no need for auto swap: {0}", lastDeploymentId);
                return;
            }

            try
            {
                FileSystemHelpers.WriteAllTextToFile(_autoSwapLockFilePath, String.Empty);
            }
            catch (Exception ex)
            {
                tracer.TraceError(ex);
            }

            string operationId = "AUTOSWAP" + Guid.NewGuid();

            var queryStrings = HttpUtility.ParseQueryString(string.Empty);
            queryStrings["slot"] = _autoSwapSlotName;
            queryStrings["operationId"] = operationId;

            var client = new OperationClient(context.Tracer);
            await client.PostAsync<string>("/operations/autoswap?" + queryStrings.ToString());
            context.Logger.Log("Requesting auto swap to slot - '{0}' operation id - '{1}' deployment id - '{2}'".FormatInvariant(_autoSwapSlotName, operationId, currentDeploymetId));
        }
        public override Task Build(DeploymentContext context)
        {
            ILogger buildLogger = context.Logger.Log(Resources.Log_BuildingSolution, Path.GetFileName(SolutionPath));

            try
            {
                string propertyString = GetPropertyString();

                if (!String.IsNullOrEmpty(propertyString))
                {
                    propertyString = " /p:" + propertyString;
                }

                string extraArguments = GetMSBuildExtraArguments();

                using (context.Tracer.Step("Running msbuild on solution"))
                {
                    // Build the solution first
                    string log = ExecuteMSBuild(context.Tracer, @"""{0}"" /verbosity:m /nologo{1} {2}", SolutionPath, propertyString, extraArguments);
                    buildLogger.Log(log);
                }

                return BuildProject(context);
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                // HACK: Log an empty error to the global logger (post receive hook console output).
                // The reason we don't log the real exception is because the 'live output' running
                // msbuild has already been captured.
                context.GlobalLogger.Log(String.Empty, LogEntryType.Error);

                buildLogger.Log(ex);

                var tcs = new TaskCompletionSource<object>();
                tcs.SetException(ex);

                return tcs.Task;
            }
        }
示例#11
0
        public override Task Build(DeploymentContext context)
        {
            var tcs = new TaskCompletionSource<object>();
            var innerLogger = context.Logger.Log("Building web project {0}.", Path.GetFileName(_projectPath));

            try
            {
                string buildTempPath = Path.Combine(_tempPath, "builds", Guid.NewGuid().ToString());
                string log = null;

                using (context.Profiler.Step("Running msbuild on project file"))
                {
                    log = BuildProject(context.Profiler, buildTempPath);
                }

                using (context.Profiler.Step("Copying files to output directory"))
                {
                    // Copy to the output path and use the previous manifest if there
                    DeploymentHelper.CopyWithManifest(buildTempPath, context.OutputPath, context.PreviousMainfest);
                }

                using (context.Profiler.Step("Building manifest"))
                {
                    // Generate a manifest from those build artifacts
                    context.ManifestWriter.AddFiles(buildTempPath);
                }

                innerLogger.Log(log);
                tcs.SetResult(null);
            }
            catch (Exception ex)
            {
                innerLogger.Log("Building web project failed.", LogEntryType.Error);
                innerLogger.Log(ex);

                tcs.SetException(ex);
            }

            return tcs.Task;
        }
示例#12
0
        public Task Build(DeploymentContext context)
        {
            var tcs = new TaskCompletionSource<object>();

            var innerLogger = context.Logger.Log("Copying files.");
            innerLogger.Log("Copying files to {0}.", context.OutputPath);

            try
            {
                using (context.Profiler.Step("Copying files to output directory"))
                {
                    // Copy to the output path and use the previous manifest if there
                    DeploymentHelper.CopyWithManifest(_sourcePath, context.OutputPath, context.PreviousMainfest);
                }

                // Download node packages
                DownloadNodePackages(innerLogger, context);

                using (context.Profiler.Step("Building manifest"))
                {
                    // Generate a manifest from those build artifacts
                    context.ManifestWriter.AddFiles(_sourcePath);
                }

                innerLogger.Log("Done.");
                tcs.SetResult(null);
            }
            catch (Exception ex)
            {
                innerLogger.Log("Copying files failed.");
                innerLogger.Log(ex);
                tcs.SetException(ex);
            }

            return tcs.Task;
        }
示例#13
0
 protected abstract Task BuildProject(DeploymentContext context);
示例#14
0
 public abstract Task Build(DeploymentContext context);
示例#15
0
        public override Task Build(DeploymentContext context)
        {
            var    tcs           = new TaskCompletionSource <object>();
            string buildTempPath = Path.Combine(_tempPath, Guid.NewGuid().ToString());

            ILogger buildLogger = context.Logger.Log(Resources.Log_BuildingWebProject, Path.GetFileName(_projectPath));

            try
            {
                using (context.Tracer.Step("Running msbuild on project file"))
                {
                    string log = BuildProject(context.Tracer, buildTempPath);

                    // Log the details of the build
                    buildLogger.Log(log);
                }
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                // HACK: Log an empty error to the global logger (post receive hook console output).
                // The reason we don't log the real exception is because the 'live output' running
                // msbuild has already been captured.
                context.GlobalLogger.LogError();

                buildLogger.Log(ex);

                tcs.SetException(ex);

                return(tcs.Task);
            }

            ILogger copyLogger = context.Logger.Log(Resources.Log_PreparingFiles);

            try
            {
                using (context.Tracer.Step("Copying files to output directory"))
                {
                    // Copy to the output path and use the previous manifest if there
                    DeploymentHelper.CopyWithManifest(buildTempPath, context.OutputPath, context.PreviousManifest);
                }

                using (context.Tracer.Step("Building manifest"))
                {
                    // Generate a manifest from those build artifacts
                    context.ManifestWriter.AddFiles(buildTempPath);
                }

                // Log the copied files from the manifest
                copyLogger.LogFileList(context.ManifestWriter.GetPaths());

                tcs.SetResult(null);
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                context.GlobalLogger.Log(ex);

                copyLogger.Log(ex);

                tcs.SetException(ex);
            }
            finally
            {
                // Clean up the build artifacts after copying them
                CleanBuild(context.Tracer, buildTempPath);
            }

            return(tcs.Task);
        }
示例#16
0
        /// <summary>
        /// Builds and deploys a particular changeset. Puts all build artifacts in a deployments/{id}
        /// </summary>
        private void Build(string id, ITracer tracer, IDisposable deployStep)
        {
            if (String.IsNullOrEmpty(id))
            {
                throw new ArgumentException("The id parameter is null or empty", "id");
            }

            ILogger logger = null;
            IDeploymentStatusFile currentStatus = null;
            IDisposable buildStep = null;

            try
            {
                logger = GetLogger(id);
                ILogger innerLogger = logger.Log(Resources.Log_PreparingDeployment, TrimId(id));

                currentStatus = _status.Open(id);
                currentStatus.Complete = false;
                currentStatus.StartTime = DateTime.Now;
                currentStatus.Status = DeployStatus.Building;
                currentStatus.StatusText = String.Format(CultureInfo.CurrentCulture, Resources.Status_BuildingAndDeploying, id);
                currentStatus.Save();

                ISiteBuilder builder = null;

                try
                {
                    builder = _builderFactory.CreateBuilder(tracer, innerLogger);
                }
                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);

                    tracer.TraceError(ex);

                    innerLogger.Log(ex);

                    currentStatus.MarkFailed();

                    deployStep.Dispose();

                    return;
                }

                buildStep = tracer.Step("Building");

                var context = new DeploymentContext
                {
                    ManifestWriter = GetDeploymentManifestWriter(id),
                    PreviousManifest = GetActiveDeploymentManifestReader(),
                    Tracer = tracer,
                    Logger = logger,
                    GlobalLogger = _globalLogger,
                    OutputPath = _environment.WebRootPath,
                };

                context.NextManifestFilePath = context.ManifestWriter.ManifestFilePath;

                if (context.PreviousManifest == null)
                {
                    // 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.PreviousManifest = new DeploymentManifest(Path.Combine(_environment.ScriptPath, Constants.FirstDeploymentManifestFileName));
                }

                context.PreviousManifestFilePath = context.PreviousManifest.ManifestFilePath;

                builder.Build(context)
                       .Then(() =>
                       {
                           // End the build step
                           buildStep.Dispose();

                           // Run post deployment steps
                           FinishDeployment(id, deployStep);
                       })
                       .Catch(ex =>
                       {
                           // End the build step
                           buildStep.Dispose();

                           currentStatus.MarkFailed();

                           // End the deploy step
                           deployStep.Dispose();

                           return ex.Handled();
                       });
            }
            catch (Exception ex)
            {
                tracer.TraceError(ex);

                if (buildStep != null)
                {
                    buildStep.Dispose();
                }

                deployStep.Dispose();
            }
        }
示例#17
0
        /// <summary>
        /// Selects a node.js version to run the application with and augments iisnode.yml accordingly
        /// </summary>
        private void SelectNodeVersion(DeploymentContext context)
        {
            var fileSystem = new FileSystem();
            var nodeSiteEnabler = new NodeSiteEnabler(
                 fileSystem,
                 repoFolder: _sourcePath,
                 siteFolder: context.OutputPath,
                 scriptPath: _scriptPath);

            ILogger innerLogger = null;

            try
            {
                if (nodeSiteEnabler.LooksLikeNode())
                {
                    innerLogger = context.Logger.Log(Resources.Log_SelectNodeJsVersion);
                    string log = nodeSiteEnabler.SelectNodeVersion(context.Tracer);

                    if (!String.IsNullOrEmpty(log))
                    {
                        innerLogger.Log(log);
                    }

                }
            }
            catch (Exception ex)
            {
                if (innerLogger != null)
                {
                    innerLogger.Log(ex);
                }

                throw;
            }
        }
示例#18
0
        /// <summary>
        /// Add a web.config file if we detect a Node site
        /// </summary>
        private void AddIISNodeConfig(DeploymentContext context)
        {
            var nodeSiteEnabler = new NodeSiteEnabler(
                new FileSystem(),
                repoFolder: _sourcePath,
                siteFolder: context.OutputPath,
                scriptPath: _scriptPath);

            // Check if need to do anythng related to Node
            if (nodeSiteEnabler.NeedNodeHandling())
            {
                // If we can figure out the start file, create the config file.
                // Otherwise give a warning
                string nodeStartFile = nodeSiteEnabler.GetNodeStartFile();
                if (nodeStartFile != null)
                {
                    context.Logger.Log(Resources.Log_CreatingNodeConfig);
                    nodeSiteEnabler.CreateConfigFile(nodeStartFile);
                }
                else
                {
                    context.Logger.Log(Resources.Log_NodeWithMissingServerJs);
                }
            }
        }
        public async Task HandleAutoSwapTests()
        {
            string deploymentId = Guid.Empty.ToString();

            var deploymentSettingsMock = new Mock<IDeploymentSettingsManager>();
            var enviromentMock = new Mock<IEnvironment>();
            var deploymentStatusManagerMock = new Mock<IDeploymentStatusManager>();
            var tracerMock = new Mock<ITracer>();
            var deploymentContextMock = new DeploymentContext()
            {
                Logger = Mock.Of<ILogger>(),
                Tracer = tracerMock.Object
            };

            enviromentMock.Setup(e => e.LocksPath).Returns(@"x:\foo");
            deploymentStatusManagerMock.Setup(d => d.ActiveDeploymentId).Returns(deploymentId);

            var handler = new AutoSwapHandler(
                enviromentMock.Object,
                deploymentSettingsMock.Object,
                Mock.Of<ITraceFactory>());

            TestTracer.Trace("Autoswap will not happen, since it is not enabled.");
            await handler.HandleAutoSwap(deploymentId, deploymentContextMock.Logger, deploymentContextMock.Tracer);

            TestTracer.Trace("Autoswap will not happen, since there is no JWT token.");
            System.Environment.SetEnvironmentVariable(Constants.SiteRestrictedJWT, null);
            deploymentSettingsMock.Setup(
                s => s.GetValue(It.Is<string>(v => "WEBSITE_SWAP_SLOTNAME".StartsWith(v)), It.IsAny<bool>())
            ).Returns("someslot");

            handler = new AutoSwapHandler(
                enviromentMock.Object,
                deploymentSettingsMock.Object,
                Mock.Of<ITraceFactory>());

            var fileSystemMock = new Mock<IFileSystem>();
            var fileInfoMock = new Mock<IFileInfoFactory>();
            var fileInfoBaseMock = new Mock<FileInfoBase>();
            FileSystemHelpers.Instance = fileSystemMock.Object;

            fileSystemMock.Setup(f => f.FileInfo).Returns(fileInfoMock.Object);
            fileInfoMock.Setup(f => f.FromFileName(It.IsAny<string>())).Returns(fileInfoBaseMock.Object);
            fileInfoBaseMock.Setup(f => f.Exists).Returns(true);
            fileInfoBaseMock.Setup(f => f.LastWriteTimeUtc).Returns(DateTime.UtcNow);
            await handler.HandleAutoSwap(deploymentId, deploymentContextMock.Logger, deploymentContextMock.Tracer);

            try
            {
                string jwtToken = Guid.NewGuid().ToString();
                string hostName = "foo.scm.bar";
                System.Environment.SetEnvironmentVariable(Constants.SiteRestrictedJWT, jwtToken);
                System.Environment.SetEnvironmentVariable(Constants.HttpHost, hostName);
                
                tracerMock.Verify(l => l.Trace("AutoSwap is not enabled", It.IsAny<IDictionary<string, string>>()), Times.Once);
                tracerMock.Verify(l => l.Trace("AutoSwap is not enabled", It.IsAny<IDictionary<string, string>>()), Times.Once);

                TestTracer.Trace("Autoswap will be triggered");
                string newDeploymentId = Guid.NewGuid().ToString();

                string autoSwapRequestUrl = null;
                string bearerToken = null;
                OperationClient.ClientHandler = new TestMessageHandler((HttpRequestMessage requestMessage) =>
                {
                    autoSwapRequestUrl = requestMessage.RequestUri.AbsoluteUri;
                    bearerToken = requestMessage.Headers.GetValues("Authorization").First();
                    return new HttpResponseMessage(HttpStatusCode.OK);
                });

                await handler.HandleAutoSwap(newDeploymentId, deploymentContextMock.Logger, deploymentContextMock.Tracer);
                Assert.NotNull(autoSwapRequestUrl);
                Assert.True(autoSwapRequestUrl.StartsWith("https://foo.scm.bar/operations/autoswap?slot=someslot&operationId=AUTOSWAP"));

                Assert.NotNull(bearerToken);
                Assert.Equal("Bearer " + jwtToken, bearerToken);
            }
            finally
            {
                System.Environment.SetEnvironmentVariable(Constants.SiteRestrictedJWT, null);
                System.Environment.SetEnvironmentVariable(Constants.HttpHost, null);
                OperationClient.ClientHandler = null;
            }
        }
示例#20
0
        /// <summary>
        /// Download node packages as part of the deployment.
        /// </summary>
        private void DownloadNodePackages(DeploymentContext context)
        {
            // Check to see if there's a package.json file
            string packagePath = Path.Combine(context.OutputPath, PackageJsonFile);

            if (!File.Exists(packagePath))
            {
                // If the package.json file doesn't exist then don't bother to run npm install
                return;
            }

            ILogger innerLogger = context.Logger.Log(Resources.Log_RunningNPM);

            using (context.Tracer.Step("Downloading node packages"))
            {
                var npm = new NpmExecutable(context.OutputPath);

                if (!npm.IsAvailable)
                {
                    context.Tracer.TraceError(Resources.Log_NpmNotInstalled);

                    innerLogger.Log(Resources.Log_NpmNotInstalled, LogEntryType.Error);
                    return;
                }

                // Set the npm proxy settings based on the default settings
                var proxy              = WebRequest.DefaultWebProxy;
                var httpUrl            = new Uri("http://registry.npmjs.org/");
                var httpsUrl           = new Uri("https://registry.npmjs.org/");
                var proxyHttpProxyUrl  = proxy.GetProxy(httpUrl);
                var proxyHttpsProxyUrl = proxy.GetProxy(httpsUrl);

                if (proxyHttpProxyUrl != httpUrl)
                {
                    npm.EnvironmentVariables["HTTP_PROXY"] = proxyHttpProxyUrl.ToString();
                }

                if (proxyHttpsProxyUrl != httpsUrl)
                {
                    npm.EnvironmentVariables["HTTPS_PROXY"] = proxyHttpsProxyUrl.ToString();
                }

                // REVIEW: Do we still need this?
                try
                {
                    // Use the http proxy since https is failing for some reason
                    npm.Execute("config set registry \"http://registry.npmjs.org/\"");
                }
                catch (Exception ex)
                {
                    // This fails if it's already set
                    context.Tracer.TraceError(ex);
                }

                try
                {
                    string log = null;

                    using (var writer = new ProgressWriter())
                    {
                        writer.Start();
                        // Run install on the output directory
                        log = npm.Install(context.Tracer, writer);
                        // Run rebuild in case any binary packages are included in the git repository
                        log = npm.Rebuild(context.Tracer, writer);
                    }

                    if (String.IsNullOrWhiteSpace(log))
                    {
                        innerLogger.Log(Resources.Log_PackagesAlreadyInstalled);
                    }
                    else
                    {
                        innerLogger.Log(log);
                    }
                }
                catch (Exception ex)
                {
                    // Log the exception
                    innerLogger.Log(ex);

                    // re-throw
                    throw;
                }
            }
        }
示例#21
0
        public string GenerateOryxBuildCommand(DeploymentContext context)
        {
            StringBuilder args = new StringBuilder();

            // Input/Output
            args.AppendFormat("oryx build {0} -o {1}", context.OutputPath, context.OutputPath);

            // Language
            switch (Language)
            {
            case Framework.None:
                break;

            case Framework.NodeJs:
                args.AppendFormat(" --platform nodejs");
                break;

            case Framework.Python:
                args.AppendFormat(" --platform python");
                break;

            case Framework.DotNETCore:
                args.AppendFormat(" --platform dotnet");
                break;

            case Framework.PHP:
                args.AppendFormat(" --platform php");
                break;
            }

            // Version
            args.AppendFormat(" --platform-version {0}", Version);

            // Build Flags
            switch (Flags)
            {
            case BuildOptimizationsFlags.Off:
            case BuildOptimizationsFlags.None:
                break;

            case BuildOptimizationsFlags.CompressModules:
                AddTempDirectoryOption(args, context.BuildTempPath);
                if (Language == Framework.NodeJs)
                {
                    AddNodeCompressOption(args, "tar-gz");
                }
                else if (Language == Framework.Python)
                {
                    AddPythonCompressOption(args);
                }

                break;

            case BuildOptimizationsFlags.UseExpressBuild:
                AddTempDirectoryOption(args, context.BuildTempPath);
                if (Language == Framework.NodeJs)
                {
                    AddNodeCompressOption(args, "zip");
                }

                break;
            }

            // Virtual Env?
            if (!String.IsNullOrEmpty(VirtualEnv))
            {
                args.AppendFormat(" -p virtualenv_name={0}", VirtualEnv);
            }

            // Publish Output?
            if (!String.IsNullOrEmpty(PublishFolder))
            {
                args.AppendFormat(" -publishedOutputPath {0}", PublishFolder);
            }

            return(args.ToString());
        }
示例#22
0
        public string GenerateOryxBuildCommand(DeploymentContext context)
        {
            StringBuilder args = new StringBuilder();

            // Language
            switch (Language)
            {
            case Framework.None:
                // Input/Output
                if (Flags == BuildOptimizationsFlags.DeploymentV2)
                {
                    OryxArgumentsHelper.AddOryxBuildCommand(args, source: context.RepositoryPath, destination: context.BuildTempPath);
                }
                else
                {
                    OryxArgumentsHelper.AddOryxBuildCommand(args, source: context.RepositoryPath, destination: context.OutputPath);
                }
                break;

            case Framework.NodeJs:
                // Input/Output
                if (Flags == BuildOptimizationsFlags.DeploymentV2)
                {
                    OryxArgumentsHelper.AddOryxBuildCommand(args, source: context.RepositoryPath, destination: context.BuildTempPath);
                }
                else
                {
                    OryxArgumentsHelper.AddOryxBuildCommand(args, source: context.RepositoryPath, destination: context.OutputPath);
                }
                OryxArgumentsHelper.AddLanguage(args, "nodejs");
                break;

            case Framework.Python:
                // Input/Output
                if (Flags == BuildOptimizationsFlags.DeploymentV2)
                {
                    OryxArgumentsHelper.AddOryxBuildCommand(args, source: context.RepositoryPath, destination: context.BuildTempPath);
                }
                else
                {
                    OryxArgumentsHelper.AddOryxBuildCommand(args, source: context.RepositoryPath, destination: context.OutputPath);
                }
                OryxArgumentsHelper.AddLanguage(args, "python");
                break;

            case Framework.DotNETCore:
                if (Flags == BuildOptimizationsFlags.UseExpressBuild || Flags == BuildOptimizationsFlags.DeploymentV2)
                {
                    // We don't want to copy the built artifacts to wwwroot for ExpressBuild scenario
                    OryxArgumentsHelper.AddOryxBuildCommand(args, source: context.RepositoryPath, destination: context.BuildTempPath);
                }
                else
                {
                    // Input/Output [For .NET core, the source path is the RepositoryPath]
                    OryxArgumentsHelper.AddOryxBuildCommand(args, source: context.RepositoryPath, destination: context.OutputPath);
                }
                OryxArgumentsHelper.AddLanguage(args, "dotnet");
                break;

            case Framework.PHP:
                // Input/Output
                if (Flags == BuildOptimizationsFlags.DeploymentV2)
                {
                    OryxArgumentsHelper.AddOryxBuildCommand(args, source: context.RepositoryPath, destination: context.BuildTempPath);
                }
                else
                {
                    OryxArgumentsHelper.AddOryxBuildCommand(args, source: context.RepositoryPath, destination: context.OutputPath);
                }
                OryxArgumentsHelper.AddLanguage(args, "php");
                break;
            }

            // Version
            switch (Language)
            {
            case Framework.None:
                break;

            case Framework.PHP:
                OryxArgumentsHelper.AddLanguageVersion(args, Version);
                break;

            case Framework.NodeJs:
                if (Version.Contains("lts", StringComparison.OrdinalIgnoreCase))
                {
                    // 10-LTS, 12-LTS should use versions 10, 12 etc
                    // Oryx Builder uses lts for major versions
                    Version = Version.Replace("lts", "").Replace("-", "");
                }

                if (string.IsNullOrEmpty(Version) || Version.Contains("10.16", StringComparison.OrdinalIgnoreCase))
                {
                    // Active LTS
                    Version = "10";
                }
                else if (Version.Contains("12.9", StringComparison.OrdinalIgnoreCase))
                {
                    Version = "12";
                }

                OryxArgumentsHelper.AddLanguageVersion(args, Version);
                break;

            case Framework.Python:
                OryxArgumentsHelper.AddLanguageVersion(args, Version);
                break;

            // work around issue regarding sdk version vs runtime version
            case Framework.DotNETCore:
                if (Version == "1.0")
                {
                    Version = "1.1";
                }
                else if (Version == "2.0")
                {
                    Version = "2.1";
                }

                OryxArgumentsHelper.AddLanguageVersion(args, Version);
                break;

            default:
                break;
            }

            // Build Flags
            switch (Flags)
            {
            case BuildOptimizationsFlags.Off:
            case BuildOptimizationsFlags.None:
                break;

            case BuildOptimizationsFlags.CompressModules:
                OryxArgumentsHelper.AddTempDirectoryOption(args, context.BuildTempPath);
                if (Language == Framework.NodeJs)
                {
                    OryxArgumentsHelper.AddNodeCompressOption(args, "tar-gz");
                }
                else if (Language == Framework.Python)
                {
                    OryxArgumentsHelper.AddPythonCompressOption(args, "tar-gz");
                }

                break;

            case BuildOptimizationsFlags.UseExpressBuild:
                OryxArgumentsHelper.AddTempDirectoryOption(args, context.BuildTempPath);
                if (Language == Framework.NodeJs)
                {
                    OryxArgumentsHelper.AddNodeCompressOption(args, "zip");
                }
                else if (Language == Framework.Python)
                {
                    OryxArgumentsHelper.AddPythonCompressOption(args, "zip");
                }

                break;

            case BuildOptimizationsFlags.UseTempDirectory:
                OryxArgumentsHelper.AddTempDirectoryOption(args, context.BuildTempPath);
                break;

            case BuildOptimizationsFlags.DeploymentV2:
                OryxArgumentsHelper.AddTempDirectoryOption(args, context.BuildTempPath);
                break;
            }

            // Virtual Env?
            if (!String.IsNullOrEmpty(VirtualEnv))
            {
                OryxArgumentsHelper.AddPythonVirtualEnv(args, VirtualEnv);
            }

            OryxArgumentsHelper.AddDebugLog(args);

            return(args.ToString());
        }
示例#23
0
 public abstract Task Build(DeploymentContext context);
示例#24
0
        /// <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,
            IRepository repository,
            DeploymentInfoBase deploymentInfo,
            DeploymentAnalytics deploymentAnalytics,
            bool fullBuildByDefault)
        {
            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;

                // Add in per-deploy default settings values based on the details of this deployment
                var perDeploymentDefaults = new Dictionary <string, string> {
                    { SettingsKeys.DoBuildDuringDeployment, fullBuildByDefault.ToString() }
                };
                var settingsProviders = _settings.SettingsProviders.Concat(
                    new[] { new BasicSettingsProvider(perDeploymentDefaults, SettingsProvidersPriority.PerDeploymentDefault) });

                var perDeploymentSettings = DeploymentSettingsManager.BuildPerDeploymentSettingsManager(repository.RepositoryPath, settingsProviders);

                string delayMaxInStr = perDeploymentSettings.GetValue(SettingsKeys.MaxRandomDelayInSec);
                if (!String.IsNullOrEmpty(delayMaxInStr))
                {
                    int maxDelay;
                    if (!Int32.TryParse(delayMaxInStr, out maxDelay) || maxDelay < 0)
                    {
                        tracer.Trace("Invalid {0} value, expect a positive integer, received {1}", SettingsKeys.MaxRandomDelayInSec, delayMaxInStr);
                    }
                    else
                    {
                        tracer.Trace("{0} is set to {1}s", SettingsKeys.MaxRandomDelayInSec, maxDelay);
                        int gap = _random.Next(maxDelay);
                        using (tracer.Step("Randomization applied to {0}, Start sleeping for {1}s", maxDelay, gap))
                        {
                            logger.Log(Resources.Log_DelayingBeforeDeployment, gap);
                            await Task.Delay(TimeSpan.FromSeconds(gap));
                        }
                    }
                }

                try
                {
                    using (tracer.Step("Determining deployment builder"))
                    {
                        builder = _builderFactory.CreateBuilder(tracer, innerLogger, perDeploymentSettings, repository);
                        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(),
                    IgnoreManifest           = deploymentInfo != null && deploymentInfo.CleanupTargetDirectory,
                    // Ignoring the manifest will cause kudusync to delete sub-directories / files
                    // in the destination directory that are not present in the source directory,
                    // without checking the manifest to see if the file was copied over to the destination
                    // during a previous kudusync operation. This effectively performs a clean deployment
                    // from the source to the destination directory.
                    Tracer        = tracer,
                    Logger        = logger,
                    GlobalLogger  = _globalLogger,
                    OutputPath    = GetOutputPath(deploymentInfo, _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 PostDeploymentHelper.SyncFunctionsTriggers(_environment.RequestId, new PostDeploymentTraceListener(tracer, logger), deploymentInfo?.SyncFunctionsTriggersPath);

                        if (_settings.TouchWatchedFileAfterDeployment())
                        {
                            TryTouchWatchedFile(context, deploymentInfo);
                        }

                        if (_settings.RunFromLocalZip() && deploymentInfo is ZipDeploymentInfo)
                        {
                            await PostDeploymentHelper.UpdateSiteVersion(deploymentInfo as ZipDeploymentInfo, _environment, logger);
                        }

                        FinishDeployment(id, deployStep);

                        deploymentAnalytics.VsProjectId = TryGetVsProjectId(context);
                        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);
            }
        }
示例#25
0
        /// <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);

                string delayMaxInStr = perDeploymentSettings.GetValue(SettingsKeys.MaxRandomDelayInSec);
                if (!String.IsNullOrEmpty(delayMaxInStr))
                {
                    int maxDelay;
                    if (!Int32.TryParse(delayMaxInStr, out maxDelay) || maxDelay < 0)
                    {
                        tracer.Trace("Invalid {0} value, expect a positive integer, received {1}", SettingsKeys.MaxRandomDelayInSec, delayMaxInStr);
                    }
                    else
                    {
                        tracer.Trace("{0} is set to {1}s", SettingsKeys.MaxRandomDelayInSec, maxDelay);
                        int gap = _random.Next(maxDelay);
                        using (tracer.Step("Randomization applied to {0}, Start sleeping for {1}s", maxDelay, gap))
                        {
                            logger.Log(Resources.Log_DelayingBeforeDeployment, gap);
                            await Task.Delay(TimeSpan.FromSeconds(gap));
                        }
                    }
                }

                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.VsProjectId = TryGetVsProjectId(context);
                        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);
            }
        }
示例#26
0
        /// <summary>
        /// Builds and deploys a particular changeset. Puts all build artifacts in a deployments/{id}
        /// </summary>
        private async Task Build(string id, ITracer tracer, IDisposable deployStep, IFileFinder fileFinder)
        {
            if (String.IsNullOrEmpty(id))
            {
                throw new ArgumentException("The id parameter is null or empty", "id");
            }

            ILogger logger = null;
            IDeploymentStatusFile currentStatus = null;

            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);
                        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);

                    tracer.TraceError(ex);

                    innerLogger.Log(ex);

                    currentStatus.MarkFailed();

                    deployStep.Dispose();

                    return;
                }

                var context = new DeploymentContext
                {
                    NextManifestFilePath     = GetDeploymentManifestPath(id),
                    PreviousManifestFilePath = GetActiveDeploymentManifestPath(),
                    Tracer       = tracer,
                    Logger       = logger,
                    GlobalLogger = _globalLogger,
                    OutputPath   = GetOutputPath(_environment, perDeploymentSettings),
                };

                if (context.PreviousManifestFilePath == null)
                {
                    // 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);
                }

                using (tracer.Step("Building"))
                {
                    try
                    {
                        await builder.Build(context);

                        TryTouchWebConfig(context);

                        // Run post deployment steps
                        FinishDeployment(id, deployStep);
                    }
                    catch (Exception ex)
                    {
                        tracer.TraceError(ex);

                        currentStatus.MarkFailed();

                        // End the deploy step
                        deployStep.Dispose();

                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                tracer.TraceError(ex);

                deployStep.Dispose();
            }
        }
示例#27
0
        /// <summary>
        /// Builds and deploys a particular changeset. Puts all build artifacts in a deployments/{id}
        /// </summary>
        private void Build(string id, ITracer tracer, IDisposable deployStep)
        {
            if (String.IsNullOrEmpty(id))
            {
                throw new ArgumentException();
            }

            ILogger logger = null;
            DeploymentStatusFile currentStatus = null;
            IDisposable          buildStep     = null;

            try
            {
                logger = GetLogger(tracer, id);
                ILogger innerLogger = logger.Log(Resources.Log_PreparingDeployment, TrimId(id));

                currentStatus            = OpenStatusFile(id);
                currentStatus.Complete   = false;
                currentStatus.StartTime  = DateTime.Now;
                currentStatus.Status     = DeployStatus.Building;
                currentStatus.StatusText = String.Format(CultureInfo.CurrentCulture, Resources.Status_BuildingAndDeploying, id);
                currentStatus.Save(_fileSystem);

                ReportStatus(id);

                ISiteBuilder builder = null;

                try
                {
                    builder = _builderFactory.CreateBuilder(tracer, innerLogger);
                }
                catch (Exception ex)
                {
                    _globalLogger.Log(ex);

                    tracer.TraceError(ex);

                    innerLogger.Log(ex);

                    MarkFailed(currentStatus);

                    ReportStatus(id);

                    deployStep.Dispose();

                    return;
                }

                buildStep = tracer.Step("Building");

                var context = new DeploymentContext
                {
                    ManifestWriter   = GetDeploymentManifestWriter(id),
                    PreviousMainfest = GetActiveDeploymentManifestReader(),
                    Tracer           = tracer,
                    Logger           = logger,
                    GlobalLogger     = _globalLogger,
                    OutputPath       = _environment.DeploymentTargetPath,
                };

                builder.Build(context)
                .Then(() =>
                {
                    // End the build step
                    buildStep.Dispose();

                    // Run post deployment steps
                    FinishDeployment(id, tracer, deployStep);
                })
                .Catch(ex =>
                {
                    // End the build step
                    buildStep.Dispose();

                    MarkFailed(currentStatus);

                    ReportStatus(id);

                    // End the deploy step
                    deployStep.Dispose();
                });
            }
            catch (Exception ex)
            {
                tracer.TraceError(ex);

                logger.LogUnexpetedError();

                if (buildStep != null)
                {
                    buildStep.Dispose();
                }

                deployStep.Dispose();
            }
        }
示例#28
0
 protected abstract Task BuildProject(DeploymentContext context);
示例#29
0
        private static string TryGetVsProjectId(DeploymentContext context)
        {
            try
            {
                // Read web.config
                string webConfigPath = Path.Combine(context.OutputPath, "web.config");
                if (File.Exists(webConfigPath))
                {
                    using (var stream = File.OpenRead(webConfigPath))
                    {
                        Guid? projectId = ProjectGuidParser.GetProjectGuidFromWebConfig(stream);
                        return projectId.HasValue ? projectId.Value.ToString() : null;
                    }
                }
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);
            }

            return null;
        }
示例#30
0
        /// <summary>
        /// Builds and deploys a particular changeset. Puts all build artifacts in a deployments/{id}
        /// </summary>
        private void Build(string id, ITracer tracer, IDisposable deployStep)
        {
            if (String.IsNullOrEmpty(id))
            {
                throw new ArgumentException();
            }

            ILogger logger = null;
            DeploymentStatusFile currentStatus = null;
            IDisposable buildStep = null;

            try
            {
                logger = GetLogger(id);
                ILogger innerLogger = logger.Log(Resources.Log_PreparingDeployment, TrimId(id));

                currentStatus = OpenStatusFile(id);
                currentStatus.Complete = false;
                currentStatus.StartTime = DateTime.Now;
                currentStatus.Status = DeployStatus.Building;
                currentStatus.StatusText = String.Format(CultureInfo.CurrentCulture, Resources.Status_BuildingAndDeploying, id);
                currentStatus.Save(_fileSystem);

                ReportStatus(id);

                ISiteBuilder builder = null;

                try
                {
                    builder = _builderFactory.CreateBuilder(tracer, innerLogger);
                }
                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);

                    tracer.TraceError(ex);

                    innerLogger.Log(ex);

                    MarkFailed(currentStatus);

                    ReportStatus(id);

                    deployStep.Dispose();

                    return;
                }

                buildStep = tracer.Step("Building");

                var context = new DeploymentContext
                {
                    ManifestWriter = GetDeploymentManifestWriter(id),
                    PreviousManifest = GetActiveDeploymentManifestReader(),
                    Tracer = tracer,
                    Logger = logger,
                    GlobalLogger = _globalLogger,
                    OutputPath = _environment.WebRootPath,
                };

                context.NextManifestFilePath = context.ManifestWriter.ManifestFilePath;

                if (context.PreviousManifest != null)
                {
                    context.PreviousManifestFilePath = context.PreviousManifest.ManifestFilePath;
                }
                else
                {
                    // In this case it is the first deployment (no active deployment)
                    // So we remove all files from wwwroot
                    FileSystemHelpers.DeleteDirectoryContentsSafe(context.OutputPath);
                }

                builder.Build(context)
                       .Then(() =>
                       {
                           // End the build step
                           buildStep.Dispose();

                           // Run post deployment steps
                           FinishDeployment(id, tracer, deployStep);
                       })
                       .Catch(ex =>
                       {
                           // End the build step
                           buildStep.Dispose();

                           MarkFailed(currentStatus);

                           ReportStatus(id);

                           // End the deploy step
                           deployStep.Dispose();

                           return ex.Handled();
                       });
            }
            catch (Exception ex)
            {
                tracer.TraceError(ex);

                logger.LogUnexpetedError();

                if (buildStep != null)
                {
                    buildStep.Dispose();
                }

                deployStep.Dispose();
            }
        }
示例#31
0
        public Task Build(DeploymentContext context)
        {
            var tcs = new TaskCompletionSource<object>();

            ILogger customLogger = context.Logger.Log("Running custom deployment command...");

            // Creates an executable pointing to cmd and the working directory being
            // the repository root
            var exe = new Executable("cmd", _repositoryPath);
            exe.EnvironmentVariables[SourcePath] = _repositoryPath;
            exe.EnvironmentVariables[TargetPath] = context.OutputPath;

            // Create a directory for the script output temporary artifacts
            string buildTempPath = Path.Combine(_tempPath, Guid.NewGuid().ToString());
            FileSystemHelpers.EnsureDirectory(buildTempPath);
            exe.EnvironmentVariables[BuildTempPath] = buildTempPath;

            // Populate the enviornment with the build propeties
            foreach (var property in _propertyProvider.GetProperties())
            {
                exe.EnvironmentVariables[property.Key] = property.Value;
            }

            // Set the path so we can add more variables
            exe.EnvironmentVariables["PATH"] = System.Environment.GetEnvironmentVariable("PATH");

            // Add the msbuild path and git path to the %PATH% so more tools are available
            var toolsPaths = new[] {
                Path.GetDirectoryName(PathUtility.ResolveMSBuildPath()),
                Path.GetDirectoryName(PathUtility.ResolveGitPath())
            };

            exe.AddToPath(toolsPaths);

            try
            {
                string output = exe.ExecuteWithConsoleOutput(context.Tracer, "/c " + _command, String.Empty).Item1;

                customLogger.Log(output);

                tcs.SetResult(null);
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                // HACK: Log an empty error to the global logger (post receive hook console output).
                // The reason we don't log the real exception is because the 'live output' running
                // msbuild has already been captured.
                context.GlobalLogger.LogError();

                customLogger.Log(ex);

                tcs.SetException(ex);
            }
            finally
            {
                // Clean the temp folder up
                FileSystemHelpers.DeleteDirectorySafe(buildTempPath);
            }

            return tcs.Task;
        }
示例#32
0
        /// <summary>
        /// Download node packages as part of the deployment.
        /// </summary>
        private void DownloadNodePackages(DeploymentContext context)
        {
            // Check to see if there's a package.json file
            string packagePath = Path.Combine(context.OutputPath, PackageJsonFile);

            if (!File.Exists(packagePath))
            {
                // If the package.json file doesn't exist then don't bother to run npm install
                return;
            }

            ILogger innerLogger = context.Logger.Log(Resources.Log_RunningNPM);

            using (context.Tracer.Step("Downloading node packages"))
            {
                var npm = new NpmExecutable(context.OutputPath);

                if (!npm.IsAvailable)
                {
                    context.Tracer.TraceError(Resources.Log_NpmNotInstalled);

                    innerLogger.Log(Resources.Log_NpmNotInstalled, LogEntryType.Error);
                    return;
                }

                // Set the npm proxy settings based on the default settings
                var proxy = WebRequest.DefaultWebProxy;
                var httpUrl = new Uri("http://registry.npmjs.org/");
                var httpsUrl = new Uri("https://registry.npmjs.org/");
                var proxyHttpProxyUrl = proxy.GetProxy(httpUrl);
                var proxyHttpsProxyUrl = proxy.GetProxy(httpsUrl);

                if (proxyHttpProxyUrl != httpUrl)
                {
                    npm.EnvironmentVariables["HTTP_PROXY"] = proxyHttpProxyUrl.ToString();
                }

                if (proxyHttpsProxyUrl != httpsUrl)
                {
                    npm.EnvironmentVariables["HTTPS_PROXY"] = proxyHttpsProxyUrl.ToString();
                }

                npm.SetHomePath(_homePath);

                // REVIEW: Do we still need this?
                try
                {
                    // Use the http proxy since https is failing for some reason
                    npm.Execute("config set registry \"http://registry.npmjs.org/\"");
                }
                catch (Exception ex)
                {
                    // This fails if it's already set
                    context.Tracer.TraceError(ex);
                }

                try
                {
                    string log = null;

                    using (var writer = new ProgressWriter())
                    {
                        writer.Start();

                        // Run install on the output directory
                        log = npm.Install(context.Tracer, writer);
                    }

                    if (String.IsNullOrWhiteSpace(log))
                    {
                        innerLogger.Log(Resources.Log_PackagesAlreadyInstalled);
                    }
                    else
                    {
                        innerLogger.Log(log);
                    }
                }
                catch (Exception ex)
                {
                    // Log the exception
                    innerLogger.Log(ex);

                    // re-throw
                    throw;
                }
            }
        }
示例#33
0
        private static void TouchWatchedFileIfNeeded(IDeploymentSettingsManager settings, DeploymentInfoBase deploymentInfo, DeploymentContext context)
        {
            if (deploymentInfo != null && !deploymentInfo.WatchedFileEnabled)
            {
                return;
            }

            if (!settings.RunFromZip() && settings.TouchWatchedFileAfterDeployment())
            {
                TryTouchWatchedFile(context, deploymentInfo);
            }
        }
示例#34
0
        public override Task Build(DeploymentContext context)
        {
            var tcs = new TaskCompletionSource<object>();
            string buildTempPath = Path.Combine(_tempPath, Guid.NewGuid().ToString());

            ILogger buildLogger = context.Logger.Log(Resources.Log_BuildingWebProject, Path.GetFileName(_projectPath));

            try
            {
                using (context.Tracer.Step("Running msbuild on project file"))
                {
                    string log = BuildProject(context.Tracer, buildTempPath);

                    // Log the details of the build
                    buildLogger.Log(log);
                }
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                // HACK: Log an empty error to the global logger (post receive hook console output).
                // The reason we don't log the real exception is because the 'live output' running
                // msbuild has already been captured.
                context.GlobalLogger.LogError();

                buildLogger.Log(ex);

                tcs.SetException(ex);

                return tcs.Task;
            }

            ILogger copyLogger = context.Logger.Log(Resources.Log_PreparingFiles);

            try
            {
                using (context.Tracer.Step("Copying files to output directory"))
                {
                    // Copy to the output path and use the previous manifest if there
                    DeploymentHelper.CopyWithManifest(buildTempPath, context.OutputPath, context.PreviousMainfest);
                }

                using (context.Tracer.Step("Building manifest"))
                {
                    // Generate a manifest from those build artifacts
                    context.ManifestWriter.AddFiles(buildTempPath);
                }

                // Log the copied files from the manifest
                copyLogger.LogFileList(context.ManifestWriter.GetPaths());

                tcs.SetResult(null);
            }
            catch (Exception ex)
            {
                context.Tracer.TraceError(ex);

                context.GlobalLogger.Log(ex);

                copyLogger.Log(ex);

                tcs.SetException(ex);
            }
            finally
            {
                // Clean up the build artifacts after copying them
                CleanBuild(context.Tracer, buildTempPath);
            }

            return tcs.Task;
        }
示例#35
0
 public override Task Build(DeploymentContext context)
 {
     throw new NotImplementedException();
 }
示例#36
0
        /// <summary>
        /// Builds and deploys a particular changeset. Puts all build artifacts in a deployments/{id}
        /// </summary>
        private void Build(string id, ITracer tracer, IDisposable deployStep)
        {
            if (String.IsNullOrEmpty(id))
            {
                throw new ArgumentException();
            }

            ILogger logger = null;
            DeploymentStatusFile currentStatus = null;
            IDisposable buildStep = null;

            try
            {
                logger = GetLogger(id);
                ILogger innerLogger = logger.Log(Resources.Log_PreparingDeployment, TrimId(id));

                currentStatus = OpenStatusFile(id);
                currentStatus.Complete = false;
                currentStatus.StartTime = DateTime.Now;
                currentStatus.Status = DeployStatus.Building;
                currentStatus.StatusText = String.Format(CultureInfo.CurrentCulture, Resources.Status_BuildingAndDeploying, id);
                currentStatus.Save(_fileSystem);

                ReportStatus(id);

                ISiteBuilder builder = null;

                try
                {
                    builder = _builderFactory.CreateBuilder(tracer, innerLogger);
                }
                catch (Exception ex)
                {
                    _globalLogger.Log(ex);

                    tracer.TraceError(ex);

                    innerLogger.Log(ex);

                    MarkFailed(currentStatus);

                    ReportStatus(id);

                    deployStep.Dispose();

                    return;
                }

                buildStep = tracer.Step("Building");

                var context = new DeploymentContext
                {
                    ManifestWriter = GetDeploymentManifestWriter(id),
                    PreviousMainfest = GetActiveDeploymentManifestReader(),
                    Tracer = tracer,
                    Logger = logger,
                    GlobalLogger = _globalLogger,
                    OutputPath = _environment.DeploymentTargetPath,
                };

                builder.Build(context)
                       .Then(() =>
                       {
                           // End the build step
                           buildStep.Dispose();

                           // Run post deployment steps
                           FinishDeployment(id, tracer, deployStep);
                       })
                       .Catch(ex =>
                       {
                           // End the build step
                           buildStep.Dispose();

                           MarkFailed(currentStatus);

                           ReportStatus(id);

                           // End the deploy step
                           deployStep.Dispose();
                       });
            }
            catch (Exception ex)
            {
                tracer.TraceError(ex);

                logger.LogUnexpetedError();

                if (buildStep != null)
                {
                    buildStep.Dispose();
                }

                deployStep.Dispose();
            }
        }
示例#37
0
 private static void TryTouchWebConfig(DeploymentContext context)
 {
     try
     {
         // Touch web.config
         string webConfigPath = Path.Combine(context.OutputPath, "web.config");
         if (File.Exists(webConfigPath))
         {
             File.SetLastWriteTimeUtc(webConfigPath, DateTime.UtcNow);
         }
     }
     catch (Exception ex)
     {
         context.Tracer.TraceError(ex);
     }
 }
示例#38
0
        /// <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);
            }
        }
示例#39
0
        /// <summary>
        /// Builds and deploys a particular changeset. Puts all build artifacts in a deployments/{id}
        /// </summary>
        private async Task Build(string id, ITracer tracer, IDisposable deployStep, IFileFinder fileFinder)
        {
            if (String.IsNullOrEmpty(id))
            {
                throw new ArgumentException("The id parameter is null or empty", "id");
            }

            ILogger logger = null;
            IDeploymentStatusFile currentStatus = null;

            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);
                        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);

                    tracer.TraceError(ex);

                    innerLogger.Log(ex);

                    currentStatus.MarkFailed();

                    deployStep.Dispose();

                    return;
                }

                var context = new DeploymentContext
                {
                    NextManifestFilePath = GetDeploymentManifestPath(id),
                    PreviousManifestFilePath = GetActiveDeploymentManifestPath(),
                    Tracer = tracer,
                    Logger = logger,
                    GlobalLogger = _globalLogger,
                    OutputPath = GetOutputPath(_environment, perDeploymentSettings),
                };

                if (context.PreviousManifestFilePath == null)
                {
                    // 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);
                }

                using (tracer.Step("Building"))
                {
                    try
                    {
                        await builder.Build(context);

                        TryTouchWebConfig(context);

                        // Run post deployment steps
                        FinishDeployment(id, deployStep);
                    }
                    catch (Exception ex)
                    {
                        tracer.TraceError(ex);

                        currentStatus.MarkFailed();

                        // End the deploy step
                        deployStep.Dispose();

                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                tracer.TraceError(ex);

                deployStep.Dispose();
            }
        }
示例#40
0
        public Task Build(DeploymentContext context)
        {
            var tcs = new TaskCompletionSource<object>();

            ILogger customLogger = context.Logger.Log("Running custom deployment command...");

            // Creates an executable pointing to cmd and the working directory being
            // the repository root
            var exe = new Executable(StarterScriptPath, _repositoryPath, _settings.GetCommandIdleTimeout());
            exe.AddDeploymentSettingsAsEnvironmentVariables(_settings);
            exe.EnvironmentVariables[ExternalCommandFactory.SourcePath] = _repositoryPath;
            exe.EnvironmentVariables[ExternalCommandFactory.TargetPath] = context.OutputPath;
            exe.EnvironmentVariables[ExternalCommandBuilder.PreviousManifestPath] = (context.PreviousManifest != null) ? context.PreviousManifest.ManifestFilePath : String.Empty;
            exe.EnvironmentVariables[ExternalCommandBuilder.NextManifestPath] = context.ManifestWriter.ManifestFilePath;
            exe.EnvironmentVariables[ExternalCommandFactory.MSBuildPath] = PathUtility.ResolveMSBuildPath();
            exe.EnvironmentVariables[ExternalCommandFactory.KuduSyncCommandKey] = KuduSyncCommand;
            exe.EnvironmentVariables[ExternalCommandFactory.SelectNodeVersionCommandKey] = SelectNodeVersionCommand;
            exe.EnvironmentVariables[ExternalCommandFactory.NpmJsPathKey] = PathUtility.ResolveNpmJsPath();
            exe.EnvironmentVariables[WellKnownEnvironmentVariables.NuGetPackageRestoreKey] = "true";

            exe.SetHomePath(_homePath);

            // Create a directory for the script output temporary artifacts
            string buildTempPath = Path.Combine(_tempPath, Guid.NewGuid().ToString());
            FileSystemHelpers.EnsureDirectory(buildTempPath);
            exe.EnvironmentVariables[ExternalCommandBuilder.BuildTempPath] = buildTempPath;

            // Populate the enviornment with the build propeties
            foreach (var property in _propertyProvider.GetProperties())
            {
                exe.EnvironmentVariables[property.Key] = property.Value;
            }

            // Set the path so we can add more variables
            exe.EnvironmentVariables["PATH"] = System.Environment.GetEnvironmentVariable("PATH");

            // Add the msbuild path and git path to the %PATH% so more tools are available
            var toolsPaths = new[] {
                Path.GetDirectoryName(PathUtility.ResolveMSBuildPath()),
                Path.GetDirectoryName(PathUtility.ResolveGitPath())
            };

            exe.AddToPath(toolsPaths);

            try
            {
                exe.ExecuteWithProgressWriter(customLogger, context.Tracer, _command, String.Empty);

                tcs.SetResult(null);
            }
            catch (CommandLineException ex)
            {
                context.Tracer.TraceError(ex);

                // HACK: Log an empty error to the global logger (post receive hook console output).
                // The reason we don't log the real exception is because the 'live output' running
                // msbuild has already been captured.
                context.GlobalLogger.LogError();

                // Add the output stream and the error stream to the log for better
                // debugging
                customLogger.Log(ex.Output, LogEntryType.Error);
                customLogger.Log(ex.Error, LogEntryType.Error);

                tcs.SetException(ex);
            }
            finally
            {
                // Clean the temp folder up
                FileSystemHelpers.DeleteDirectorySafe(buildTempPath);
            }

            return tcs.Task;
        }
示例#41
0
        /// <summary>
        /// Selects a node.js version to run the application with and augments iisnode.yml accordingly
        /// </summary>
        private void SelectNodeVersion(DeploymentContext context)
        {
            var fileSystem = new FileSystem();
            var nodeSiteEnabler = new NodeSiteEnabler(
                 fileSystem,
                 repoFolder: _sourcePath,
                 siteFolder: context.OutputPath,
                 scriptPath: _scriptPath);

            if (nodeSiteEnabler.LooksLikeNode())
            {
                nodeSiteEnabler.SelectNodeVersion(context.Tracer);
            }
        }
示例#42
0
        /// <summary>
        /// Builds and deploys a particular changeset. Puts all build artifacts in a deployments/{id}
        /// </summary>
        private async Task Build(string id, ITracer tracer, IDisposable deployStep, IFileFinder fileFinder, DeploymentAnalytics deploymentAnalytics)
        {
            if (String.IsNullOrEmpty(id))
            {
                throw new ArgumentException("The id parameter is null or empty", "id");
            }

            ILogger logger = null;
            IDeploymentStatusFile currentStatus = null;
            string buildTempPath = null;

            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
                buildTempPath = Path.Combine(_environment.TempPath, Guid.NewGuid().ToString());
                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
                };

                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);

                        TryTouchWebConfig(context);

                        // Run post deployment steps
                        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);
            }
        }
示例#43
0
        public Task Build(DeploymentContext context)
        {
            var tcs = new TaskCompletionSource <object>();

            ILogger customLogger = context.Logger.Log("Running custom deployment command...");

            // Creates an executable pointing to cmd and the working directory being
            // the repository root
            var exe = new Executable(StarterScriptPath, _repositoryPath, _settings.GetCommandIdleTimeout());

            exe.EnvironmentVariables[ExternalCommandFactory.SourcePath]                    = _repositoryPath;
            exe.EnvironmentVariables[ExternalCommandFactory.TargetPath]                    = context.OutputPath;
            exe.EnvironmentVariables[ExternalCommandBuilder.PreviousManifestPath]          = (context.PreviousManifest != null) ? context.PreviousManifest.ManifestFilePath : String.Empty;
            exe.EnvironmentVariables[ExternalCommandBuilder.NextManifestPath]              = context.ManifestWriter.ManifestFilePath;
            exe.EnvironmentVariables[ExternalCommandFactory.MSBuildPath]                   = PathUtility.ResolveMSBuildPath();
            exe.EnvironmentVariables[ExternalCommandFactory.KuduSyncCommandKey]            = KuduSyncCommand;
            exe.EnvironmentVariables[ExternalCommandFactory.SelectNodeVersionCommandKey]   = SelectNodeVersionCommand;
            exe.EnvironmentVariables[ExternalCommandFactory.NpmJsPathKey]                  = PathUtility.ResolveNpmJsPath();
            exe.EnvironmentVariables[WellKnownEnvironmentVariables.NuGetPackageRestoreKey] = "true";
            exe.AddDeploymentSettingsAsEnvironmentVariables(_settings);

            exe.SetHomePath(_homePath);

            // Create a directory for the script output temporary artifacts
            string buildTempPath = Path.Combine(_tempPath, Guid.NewGuid().ToString());

            FileSystemHelpers.EnsureDirectory(buildTempPath);
            exe.EnvironmentVariables[ExternalCommandBuilder.BuildTempPath] = buildTempPath;

            // Populate the enviornment with the build propeties
            foreach (var property in _propertyProvider.GetProperties())
            {
                exe.EnvironmentVariables[property.Key] = property.Value;
            }

            // Set the path so we can add more variables
            exe.EnvironmentVariables["PATH"] = System.Environment.GetEnvironmentVariable("PATH");

            // Add the msbuild path and git path to the %PATH% so more tools are available
            var toolsPaths = new[] {
                Path.GetDirectoryName(PathUtility.ResolveMSBuildPath()),
                Path.GetDirectoryName(PathUtility.ResolveGitPath()),
                Path.GetDirectoryName(PathUtility.ResolveVsTestPath())
            };

            exe.AddToPath(toolsPaths);

            try
            {
                exe.ExecuteWithProgressWriter(customLogger, context.Tracer, _command, String.Empty);

                tcs.SetResult(null);
            }
            catch (CommandLineException ex)
            {
                context.Tracer.TraceError(ex);

                // HACK: Log an empty error to the global logger (post receive hook console output).
                // The reason we don't log the real exception is because the 'live output' running
                // msbuild has already been captured.
                context.GlobalLogger.LogError();

                // Add the output stream and the error stream to the log for better
                // debugging
                customLogger.Log(ex.Output, LogEntryType.Error);
                customLogger.Log(ex.Error, LogEntryType.Error);

                tcs.SetException(ex);
            }
            finally
            {
                // Clean the temp folder up
                FileSystemHelpers.DeleteDirectorySafe(buildTempPath);
            }

            return(tcs.Task);
        }