示例#1
0
        internal async Task <bool> InvokeLocalAsync(string projectName, string @event, int workItemId, string ruleFilePath, bool dryRun, SaveMode saveMode)
        {
            if (!File.Exists(ruleFilePath))
            {
                logger.WriteError($"Rule code not found at {ruleFilePath}");
                return(false);
            }

            var devopsLogonData = DevOpsLogon.Load().connection;

            logger.WriteVerbose($"Connecting to Azure DevOps using {devopsLogonData.Mode}...");
            var clientCredentials = default(VssCredentials);

            if (devopsLogonData.Mode == DevOpsTokenType.PAT)
            {
                clientCredentials = new VssBasicCredential(devopsLogonData.Mode.ToString(), devopsLogonData.Token);
            }
            else
            {
                logger.WriteError($"Azure DevOps Token type {devopsLogonData.Mode} not supported!");
                throw new ArgumentOutOfRangeException(nameof(devopsLogonData.Mode));
            }

            string collectionUrl = devopsLogonData.Url;

            using (var devops = new VssConnection(new Uri(collectionUrl), clientCredentials))
            {
                await devops.ConnectAsync();

                logger.WriteInfo($"Connected to Azure DevOps");

                Guid   teamProjectId;
                string teamProjectName;
                using (var projectClient = devops.GetClient <ProjectHttpClient>())
                {
                    logger.WriteVerbose($"Reading Azure DevOps project data...");
                    var project = await projectClient.GetProject(projectName);

                    logger.WriteInfo($"Project {projectName} data read.");
                    teamProjectId   = project.Id;
                    teamProjectName = project.Name;
                }

                using (var witClient = devops.GetClient <WorkItemTrackingHttpClient>())
                {
                    logger.WriteVerbose($"Rule code found at {ruleFilePath}");
                    string[] ruleCode = File.ReadAllLines(ruleFilePath);

                    var engineLogger = new EngineWrapperLogger(logger);
                    var engine       = new Engine.RuleEngine(engineLogger, ruleCode, saveMode);
                    engine.DryRun = dryRun;

                    string result = await engine.ExecuteAsync(collectionUrl, teamProjectId, teamProjectName, devopsLogonData.Token, workItemId, witClient);

                    logger.WriteInfo($"Rule returned '{result}'");

                    return(true);
                }
            }
        }
#pragma warning disable S107  // Methods should not have too many parameters
#pragma warning disable S4457 // Parameter validation in "async"/"await" methods should be wrapped
        internal async Task <bool> InvokeLocalAsync(string projectName, string @event, int workItemId, string ruleFilePath, bool dryRun, SaveMode saveMode, bool impersonateExecution, CancellationToken cancellationToken)
#pragma warning restore S4457 // Parameter validation in "async"/"await" methods should be wrapped
#pragma warning restore S107  // Methods should not have too many parameters
        {
            if (!File.Exists(ruleFilePath))
            {
                _logger.WriteError($"Rule code not found at {ruleFilePath}");
                return(false);
            }

            var devopsLogonData = DevOpsLogon.Load().connection;

            _logger.WriteVerbose($"Connecting to Azure DevOps using {devopsLogonData.Mode}...");
            VssCredentials clientCredentials;

            if (devopsLogonData.Mode == DevOpsTokenType.PAT)
            {
                clientCredentials = new VssBasicCredential(devopsLogonData.Mode.ToString(), devopsLogonData.Token);
            }
            else
            {
                _logger.WriteError($"Azure DevOps Token type {devopsLogonData.Mode} not supported!");
                throw new ArgumentException($"Azure DevOps Token type {devopsLogonData.Mode} not supported!");
            }

            // see https://rules.sonarsource.com/csharp/RSPEC-4457
            return(await InvokeLocalAsyncImpl(projectName, @event, workItemId, ruleFilePath, dryRun, saveMode, impersonateExecution, devopsLogonData, clientCredentials, cancellationToken));
        }
        internal async Task <CommandContext> BuildAsync(CancellationToken cancellationToken)
        {
            IAzure        azure  = null;
            VssConnection devops = null;

            if (azureLogon)
            {
                logger.WriteVerbose($"Authenticating to Azure...");
                var(connection, reason) = AzureLogon.Load();
                if (reason != LogonResult.Succeeded)
                {
                    string msg = TranslateResult(reason);
                    throw new InvalidOperationException(string.Format(msg, "Azure", "logon.azure"));
                }

                azure = connection.Logon();
                logger.WriteInfo($"Connected to subscription {azure.SubscriptionId}");
            }

            if (devopsLogon)
            {
                logger.WriteVerbose($"Authenticating to Azure DevOps...");
                var(connection, reason) = DevOpsLogon.Load();
                if (reason != LogonResult.Succeeded)
                {
                    string msg = TranslateResult(reason);
                    throw new InvalidOperationException(string.Format(msg, "Azure DevOps", "logon.ado"));
                }

                devops = await connection.LogonAsync(cancellationToken);

                logger.WriteInfo($"Connected to {devops.Uri.Host}");
            }

            INamingTemplates naming;

            switch (namingTemplate.ToLower())
            {
            case "builtin":
#pragma warning disable S907 // "goto" statement should not be used
                goto case "";

#pragma warning restore S907 // "goto" statement should not be used
            case "":
                naming = new BuiltInNamingTemplates();
                break;

            default:
                // implement custom Naming Templates, e.g. reading from a file
                naming = new FileNamingTemplates(File.ReadAllText(namingTemplate));
                break;
            }

            return(new CommandContext(logger, azure, devops, naming));
        }
        internal async Task <bool> AddAsync(InstanceName instance, string location, string requiredVersion, string sourceUrl, InstanceFineTuning tuning, CancellationToken cancellationToken)
        {
            string rgName = instance.ResourceGroupName;
            bool   ok     = await MakeSureResourceGroupExistsAsync(instance.IsCustom, location, rgName, cancellationToken);

            if (!ok)
            {
                return(false);
            }

            ok = await DeployArmTemplateAsync(instance, location, rgName, tuning, cancellationToken);

            if (!ok)
            {
                return(false);
            }

            // check runtime package
            var package = new FunctionRuntimePackage(logger);

            ok = await package.UpdateVersionAsync(requiredVersion, sourceUrl, instance, azure, cancellationToken);

            if (ok)
            {
                var devopsLogonData = DevOpsLogon.Load().connection;
                if (devopsLogonData.Mode == DevOpsTokenType.PAT)
                {
                    logger.WriteVerbose($"Saving Azure DevOps token");
                    ok = await ChangeAppSettingsAsync(instance, devopsLogonData, SaveMode.Default, cancellationToken);

                    if (ok)
                    {
                        logger.WriteInfo($"Azure DevOps token saved");
                    }
                    else
                    {
                        logger.WriteError($"Failed to save Azure DevOps token");
                    }
                }
                else
                {
                    logger.WriteWarning($"Azure DevOps token type {devopsLogonData.Mode} is unsupported");
                    ok = false;
                }
            }
            return(ok);
        }
        internal async Task <bool> ChangeAppSettings(InstanceName instance, string location, SaveMode saveMode)
        {
            bool ok;
            var  devopsLogonData = DevOpsLogon.Load().connection;

            if (devopsLogonData.Mode == DevOpsTokenType.PAT)
            {
                logger.WriteVerbose($"Saving Azure DevOps token");
                ok = await ChangeAppSettings(instance, devopsLogonData, saveMode);

                logger.WriteInfo($"Azure DevOps token saved");
            }
            else
            {
                logger.WriteWarning($"Azure DevOps token type {devopsLogonData.Mode} is unsupported");
                ok = false;
            }
            return(ok);
        }
示例#6
0
        internal async Task <bool> InvokeLocalAsync(string projectName, string @event, int workItemId, string ruleFilePath, bool dryRun, SaveMode saveMode, bool impersonateExecution, CancellationToken cancellationToken)
        {
            if (!File.Exists(ruleFilePath))
            {
                _logger.WriteError($"Rule code not found at {ruleFilePath}");
                return(false);
            }

            var devopsLogonData = DevOpsLogon.Load().connection;

            _logger.WriteVerbose($"Connecting to Azure DevOps using {devopsLogonData.Mode}...");
            var clientCredentials = default(VssCredentials);

            if (devopsLogonData.Mode == DevOpsTokenType.PAT)
            {
                clientCredentials = new VssBasicCredential(devopsLogonData.Mode.ToString(), devopsLogonData.Token);
            }
            else
            {
                _logger.WriteError($"Azure DevOps Token type {devopsLogonData.Mode} not supported!");
                throw new ArgumentOutOfRangeException(nameof(devopsLogonData.Mode));
            }

            string collectionUrl = devopsLogonData.Url;

            using (var devops = new VssConnection(new Uri(collectionUrl), clientCredentials))
            {
                await devops.ConnectAsync(cancellationToken);

                _logger.WriteInfo($"Connected to Azure DevOps");

                Guid teamProjectId;
                using (var projectClient = devops.GetClient <ProjectHttpClient>())
                {
                    _logger.WriteVerbose($"Reading Azure DevOps project data...");
                    var project = await projectClient.GetProject(projectName);

                    _logger.WriteInfo($"Project {projectName} data read.");
                    teamProjectId = project.Id;
                }

                using (var clientsContext = new AzureDevOpsClientsContext(devops))
                {
                    _logger.WriteVerbose($"Rule code found at {ruleFilePath}");
                    var(preprocessedRule, _) = await RuleFileParser.ReadFile(ruleFilePath, cancellationToken);

                    var rule = new Engine.ScriptedRuleWrapper(Path.GetFileNameWithoutExtension(ruleFilePath), preprocessedRule)
                    {
                        ImpersonateExecution = impersonateExecution
                    };

                    var engineLogger = new EngineWrapperLogger(_logger);
                    var engine       = new Engine.RuleEngine(engineLogger, saveMode, dryRun: dryRun);

                    var workItem = await clientsContext.WitClient.GetWorkItemAsync(projectName, workItemId, expand : WorkItemExpand.All, cancellationToken : cancellationToken);

                    string result = await engine.RunAsync(rule, teamProjectId, workItem, clientsContext, cancellationToken);

                    _logger.WriteInfo($"Rule returned '{result}'");

                    return(true);
                }
            }
        }
示例#7
0
        internal async Task <bool> AddAsync(InstanceName instance, string location, string requiredVersion, string sourceUrl, CancellationToken cancellationToken)
        {
            string rgName = instance.ResourceGroupName;

            logger.WriteVerbose($"Checking if Resource Group {rgName} already exists");
            if (!await azure.ResourceGroups.ContainAsync(rgName, cancellationToken))
            {
                if (instance.IsCustom)
                {
                    logger.WriteError($"Resource group {rgName} is custom and cannot be created.");
                    return(false);
                }

                logger.WriteVerbose($"Creating resource group {rgName}");
                await azure.ResourceGroups
                .Define(rgName)
                .WithRegion(location)
                .CreateAsync();

                logger.WriteInfo($"Resource group {rgName} created.");
            }

            // IDEA the template should create a Storage account and/or a Key Vault for Rules' use
            // TODO https://github.com/gjlumsden/AzureFunctionsSlots suggest that slots must be created in template
            var    resourceName = "aggregator.cli.Instances.instance-template.json";
            string armTemplateString;
            var    assembly = Assembly.GetExecutingAssembly();

            using (Stream stream = assembly.GetManifestResourceStream(resourceName))
                using (StreamReader reader = new StreamReader(stream))
                {
                    armTemplateString = await reader.ReadToEndAsync();
                }

            var parsedTemplate = JObject.Parse(armTemplateString);

            // sanity checks
            if (parsedTemplate.SelectToken("parameters.appName") == null)
            {
                // not good, blah
                logger.WriteWarning($"Something is wrong with the ARM template");
            }

            string appName        = instance.FunctionAppName;
            var    infoVersion    = GetCustomAttribute <AssemblyInformationalVersionAttribute>();
            var    templateParams = new Dictionary <string, Dictionary <string, object> > {
                // TODO give use more control by setting more parameters
                { "location", new Dictionary <string, object> {
                      { "value", location }
                  } },
                { "storageAccountType", new Dictionary <string, object> {
                      { "value", "Standard_LRS" }
                  } },
                { "appName", new Dictionary <string, object> {
                      { "value", appName }
                  } },
                { "aggregatorVersion", new Dictionary <string, object> {
                      { "value", infoVersion.InformationalVersion }
                  } },
                { "hostingPlanSkuName", new Dictionary <string, object> {
                      { "value", "Y1" }
                  } },
                { "hostingPlanSkuTier", new Dictionary <string, object> {
                      { "value", "Dynamic" }
                  } },
            };

            string deploymentName = SdkContext.RandomResourceName("aggregator", 24);

            logger.WriteInfo($"Started deployment (id: {deploymentName})");
            var deployment = await azure.Deployments.Define(deploymentName)
                             .WithExistingResourceGroup(rgName)
                             .WithTemplate(armTemplateString)
                             .WithParameters(templateParams)
                             .WithMode(DeploymentMode.Incremental)
                             .CreateAsync(cancellationToken);

            // poll
            const int pollIntervalInSeconds = 3;
            int       totalDelay            = 0;

            while (!(StringComparer.OrdinalIgnoreCase.Equals(deployment.ProvisioningState, "Succeeded") ||
                     StringComparer.OrdinalIgnoreCase.Equals(deployment.ProvisioningState, "Failed") ||
                     StringComparer.OrdinalIgnoreCase.Equals(deployment.ProvisioningState, "Cancelled")))
            {
                SdkContext.DelayProvider.Delay(pollIntervalInSeconds * 1000);
                totalDelay += pollIntervalInSeconds;
                logger.WriteVerbose($"Deployment running ({totalDelay}s)");
                await deployment.RefreshAsync(cancellationToken);
            }
            logger.WriteInfo($"Deployment {deployment.ProvisioningState}");

            // check runtime package
            var  package = new FunctionRuntimePackage(logger);
            bool ok      = await package.UpdateVersionAsync(requiredVersion, sourceUrl, instance, azure, cancellationToken);

            if (ok)
            {
                var devopsLogonData = DevOpsLogon.Load().connection;
                if (devopsLogonData.Mode == DevOpsTokenType.PAT)
                {
                    logger.WriteVerbose($"Saving Azure DevOps token");
                    ok = await ChangeAppSettingsAsync(instance, devopsLogonData, SaveMode.Default, cancellationToken);

                    if (ok)
                    {
                        logger.WriteInfo($"Azure DevOps token saved");
                    }
                    else
                    {
                        logger.WriteError($"Failed to save Azure DevOps token");
                    }
                }
                else
                {
                    logger.WriteWarning($"Azure DevOps token type {devopsLogonData.Mode} is unsupported");
                    ok = false;
                }
            }
            return(ok);
        }