public async Task <string> ExecuteAsync(string collectionUrl, Guid projectId, string projectName, string personalAccessToken, int workItemId, WorkItemTrackingHttpClientBase witClient, CancellationToken cancellationToken) { if (State == EngineState.Error) { return(string.Empty); } var context = new EngineContext(witClient, projectId, projectName, personalAccessToken, logger); var store = new WorkItemStore(context); var self = store.GetWorkItem(workItemId); logger.WriteInfo($"Initial WorkItem {workItemId} retrieved from {collectionUrl}"); var globals = new Globals { self = self, store = store }; logger.WriteInfo($"Executing Rule..."); var result = await roslynScript.RunAsync(globals, cancellationToken); if (result.Exception != null) { logger.WriteError($"Rule failed with {result.Exception}"); State = EngineState.Error; } else if (result.ReturnValue != null) { logger.WriteInfo($"Rule succeeded with {result.ReturnValue}"); } else { logger.WriteInfo($"Rule succeeded, no return value"); } State = EngineState.Success; logger.WriteVerbose($"Post-execution, save any change (mode {saveMode})..."); var saveRes = await store.SaveChanges(saveMode, !DryRun, cancellationToken); if (saveRes.created + saveRes.updated > 0) { logger.WriteInfo($"Changes saved to Azure DevOps (mode {saveMode}): {saveRes.created} created, {saveRes.updated} updated."); } else { logger.WriteInfo($"No changes saved to Azure DevOps."); } return(result.ReturnValue); }
public async Task <string> ExecuteAsync(Guid projectId, WorkItemData workItemPayload, IClientsContext clients, CancellationToken cancellationToken) { if (State == EngineState.Error) { return(string.Empty); } var workItem = workItemPayload.WorkItem; var context = new EngineContext(clients, projectId, workItem.GetTeamProject(), logger); var store = new WorkItemStore(context, workItem); var self = store.GetWorkItem(workItem.Id.Value); var selfChanges = new WorkItemUpdateWrapper(workItemPayload.WorkItemUpdate); logger.WriteInfo($"Initial WorkItem {self.Id} retrieved from {clients.WitClient.BaseAddress}"); var globals = new Globals { self = self, selfChanges = selfChanges, store = store, logger = logger }; logger.WriteInfo($"Executing Rule..."); var result = await roslynScript.RunAsync(globals, cancellationToken); if (result.Exception != null) { logger.WriteError($"Rule failed with {result.Exception}"); State = EngineState.Error; } else { logger.WriteInfo($"Rule succeeded with {result.ReturnValue ?? "no return value"}"); State = EngineState.Success; } logger.WriteVerbose($"Post-execution, save any change (mode {saveMode})..."); var saveRes = await store.SaveChanges(saveMode, !DryRun, cancellationToken); if (saveRes.created + saveRes.updated > 0) { logger.WriteInfo($"Changes saved to Azure DevOps (mode {saveMode}): {saveRes.created} created, {saveRes.updated} updated."); } else { logger.WriteInfo($"No changes saved to Azure DevOps."); } return(result.ReturnValue); }
protected RuleExecutionContext CreateRuleExecutionContext(Guid projectId, WorkItemData workItemPayload, IClientsContext clients) { var workItem = workItemPayload.WorkItem; var context = new EngineContext(clients, projectId, workItem.GetTeamProject(), logger); var store = new WorkItemStore(context, workItem); var self = store.GetWorkItem(workItem.Id.Value); var selfChanges = new WorkItemUpdateWrapper(workItemPayload.WorkItemUpdate); logger.WriteInfo($"Initial WorkItem {self.Id} retrieved from {clients.WitClient.BaseAddress}"); var globals = new RuleExecutionContext { self = self, selfChanges = selfChanges, store = store, logger = logger }; return(globals); }
internal async Task <string> Execute(string aggregatorVersion, dynamic data) { if (string.IsNullOrEmpty(aggregatorVersion)) { aggregatorVersion = "0.1"; } string collectionUrl = data.resourceContainers.collection.baseUrl; int workItemId = data.resource.id; logger.WriteVerbose($"Connecting to VSTS using {configuration.VstsTokenType}..."); var clientCredentials = default(VssCredentials); if (configuration.VstsTokenType == VstsTokenType.PAT) { clientCredentials = new VssBasicCredential(configuration.VstsTokenType.ToString(), configuration.VstsToken); } else { logger.WriteError($"VSTS Token type {configuration.VstsTokenType} not supported!"); throw new ArgumentOutOfRangeException(nameof(configuration.VstsTokenType)); } var vsts = new VssConnection(new Uri(collectionUrl), clientCredentials); await vsts.ConnectAsync(); logger.WriteInfo($"Connected to VSTS"); var witClient = vsts.GetClient <WorkItemTrackingHttpClient>(); var context = new Engine.EngineContext(witClient); var store = new Engine.WorkItemStore(context); var self = store.GetWorkItem(workItemId); logger.WriteInfo($"Initial WorkItem retrieved"); string ruleFilePath = Path.Combine(functionDirectory, $"{ruleName}.rule"); if (!File.Exists(ruleFilePath)) { logger.WriteError($"Rule code not found at {ruleFilePath}"); return("Rule file not found!"); } logger.WriteVerbose($"Rule code found at {ruleFilePath}"); string ruleCode = File.ReadAllText(ruleFilePath); logger.WriteInfo($"Executing Rule..."); var globals = new Engine.Globals { self = self, store = store }; var types = new List <Type>() { typeof(object), typeof(System.Linq.Enumerable), typeof(System.Collections.Generic.CollectionExtensions) }; var references = types.ConvertAll(t => t.Assembly); var scriptOptions = ScriptOptions.Default .WithEmitDebugInformation(true) .WithReferences(references) // Add namespaces .WithImports("System") .WithImports("System.Linq") .WithImports("System.Collections.Generic"); var result = await CSharpScript.EvaluateAsync <string>( code : ruleCode, options : scriptOptions, globals : globals, globalsType : typeof(Engine.Globals)); logger.WriteInfo($"Rule returned {result}"); logger.WriteVerbose($"Post-execution, save all changes..."); context.SaveChanges(); logger.WriteInfo($"Changes saved to VSTS"); return(result); }