public TaskResult Complete(TaskResult?result = null, string currentOperation = null, string resultCode = null)
        {
            if (result != null)
            {
                Result = result;
            }

            // report total delay caused by server throttling.
            if (_totalThrottlingDelayInMilliseconds > _throttlingDelayReportThreshold)
            {
                this.Warning($"The job has experienced {TimeSpan.FromMilliseconds(_totalThrottlingDelayInMilliseconds).TotalSeconds} seconds total delay caused by server throttling.");
            }

            _record.CurrentOperation = currentOperation ?? _record.CurrentOperation;
            _record.ResultCode       = resultCode ?? _record.ResultCode;
            _record.FinishTime       = DateTime.UtcNow;
            _record.PercentComplete  = 100;
            _record.Result           = _record.Result ?? TaskResult.Succeeded;
            _record.State            = TimelineRecordState.Completed;

            _jobServerQueue.QueueTimelineRecordUpdate(_mainTimelineId, _record);

            // complete all detail timeline records.
            if (_detailTimelineId != Guid.Empty && _detailRecords.Count > 0)
            {
                foreach (var record in _detailRecords)
                {
                    record.Value.FinishTime      = record.Value.FinishTime ?? DateTime.UtcNow;
                    record.Value.PercentComplete = record.Value.PercentComplete ?? 100;
                    record.Value.Result          = record.Value.Result ?? TaskResult.Succeeded;
                    record.Value.State           = TimelineRecordState.Completed;

                    _jobServerQueue.QueueTimelineRecordUpdate(_detailTimelineId, record.Value);
                }
            }

            if (Root != this)
            {
                // only dispose TokenSource for step level ExecutionContext
                _cancellationTokenSource?.Dispose();
            }

            _logger.End();

            if (!string.IsNullOrEmpty(ContextName))
            {
                StepsContext.SetOutcome(ScopeName, ContextName, (Outcome ?? Result ?? TaskResult.Succeeded).ToActionResult());
                StepsContext.SetConclusion(ScopeName, ContextName, (Result ?? TaskResult.Succeeded).ToActionResult());
            }

            return(Result.Value);
        }
Example #2
0
        public void SetOutput(string name, string value, out string reference)
        {
            ArgUtil.NotNullOrEmpty(name, nameof(name));

            if (String.IsNullOrEmpty(ContextName))
            {
                reference = null;
                return;
            }

            // todo: restrict multiline?

            StepsContext.SetOutput(ScopeName, ContextName, name, value, out reference);
        }
        public void SetOutput(string name, string value, out string reference)
        {
            ArgUtil.NotNullOrEmpty(name, nameof(name));

            // if the ContextName follows the __GUID format which is set as the default value for ContextName if null for Composite Actions.
            if (String.IsNullOrEmpty(ContextName) || _generatedContextNamePattern.IsMatch(ContextName))
            {
                reference = null;
                return;
            }

            // todo: restrict multiline?

            StepsContext.SetOutput(ScopeName, ContextName, name, value, out reference);
        }
        public void InitializeJob(Pipelines.AgentJobRequestMessage message, CancellationToken token)
        {
            // Validation
            Trace.Entering();
            ArgUtil.NotNull(message, nameof(message));
            ArgUtil.NotNull(message.Resources, nameof(message.Resources));
            ArgUtil.NotNull(message.Variables, nameof(message.Variables));
            ArgUtil.NotNull(message.Plan, nameof(message.Plan));

            _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token);

            // Plan
            Plan     = message.Plan;
            Features = PlanUtil.GetFeatures(message.Plan);

            // Endpoints
            Endpoints = message.Resources.Endpoints;

            // Variables
            Variables = new Variables(HostContext, message.Variables);

            // Environment variables shared across all actions
            EnvironmentVariables = new Dictionary <string, string>(VarUtil.EnvironmentVariableKeyComparer);

            // Job defaults shared across all actions
            JobDefaults = new Dictionary <string, IDictionary <string, string> >(StringComparer.OrdinalIgnoreCase);

            // Job Outputs
            JobOutputs = new Dictionary <string, VariableValue>(StringComparer.OrdinalIgnoreCase);

            // Service container info
            ServiceContainers = new List <ContainerInfo>();

            // Steps context (StepsRunner manages adding the scoped steps context)
            StepsContext = new StepsContext();

            // File table
            FileTable = new List <String>(message.FileTable ?? new string[0]);

            // Expression values
            if (message.ContextData?.Count > 0)
            {
                foreach (var pair in message.ContextData)
                {
                    ExpressionValues[pair.Key] = pair.Value;
                }
            }

            ExpressionValues["secrets"] = Variables.ToSecretsContext();
            ExpressionValues["runner"]  = new RunnerContext();
            ExpressionValues["job"]     = new JobContext();

            Trace.Info("Initialize GitHub context");
            var githubAccessToken  = new StringContextData(Variables.Get("system.github.token"));
            var base64EncodedToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"x-access-token:{githubAccessToken}"));

            HostContext.SecretMasker.AddValue(base64EncodedToken);
            var githubJob     = Variables.Get("system.github.job");
            var githubContext = new GitHubContext();

            githubContext["token"] = githubAccessToken;
            if (!string.IsNullOrEmpty(githubJob))
            {
                githubContext["job"] = new StringContextData(githubJob);
            }
            var githubDictionary = ExpressionValues["github"].AssertDictionary("github");

            foreach (var pair in githubDictionary)
            {
                githubContext[pair.Key] = pair.Value;
            }
            ExpressionValues["github"] = githubContext;

            Trace.Info("Initialize Env context");
#if OS_WINDOWS
            ExpressionValues["env"] = new DictionaryContextData();
#else
            ExpressionValues["env"] = new CaseSensitiveDictionaryContextData();
#endif

            // Prepend Path
            PrependPath = new List <string>();

            // JobSteps for job ExecutionContext
            JobSteps = new List <IStep>();

            // PostJobSteps for job ExecutionContext
            PostJobSteps = new Stack <IStep>();

            // StepsWithPostRegistered for job ExecutionContext
            StepsWithPostRegistered = new HashSet <Guid>();

            // Job timeline record.
            InitializeTimelineRecord(
                timelineId: message.Timeline.Id,
                timelineRecordId: message.JobId,
                parentTimelineRecordId: null,
                recordType: ExecutionContextType.Job,
                displayName: message.JobDisplayName,
                refName: message.JobName,
                order: null); // The job timeline record's order is set by server.

            // Logger (must be initialized before writing warnings).
            _logger = HostContext.CreateService <IPagingLogger>();
            _logger.Setup(_mainTimelineId, _record.Id);

            // Initialize 'echo on action command success' property, default to false, unless Step_Debug is set
            EchoOnActionCommand = Variables.Step_Debug ?? false;

            // Verbosity (from GitHub.Step_Debug).
            WriteDebug = Variables.Step_Debug ?? false;

            // Hook up JobServerQueueThrottling event, we will log warning on server tarpit.
            _jobServerQueue.JobServerQueueThrottling += JobServerQueueThrottling_EventReceived;
        }