async private Task <bool> createMergeRequestWithoutPosition(NewDiscussionParameters parameters) { if (_discussionOperator == null) { return(false); } Debug.Assert(parameters.Position != null); Trace.TraceInformation("[DicsussionCreator] Reporting a discussion without Position (fallback)"); NewDiscussionParameters newDiscussionParameters = new NewDiscussionParameters( getFallbackInfo(parameters.Position.Value) + "<br>" + parameters.Body, null); try { await _discussionOperator.CreateDiscussionAsync(_mergeRequestKey, newDiscussionParameters); } catch (OperatorException ex) { ExceptionHandlers.Handle("Cannot create a discussion (again)", ex); return(false); } return(true); }
async private Task deleteMostRecentNote(NewDiscussionParameters parameters) { Debug.Assert(parameters.Position != null); Trace.TraceInformation("[DicsussionCreator] Looking up for a note with bad position..."); IEnumerable <Discussion> discussions; try { discussions = await _discussionOperator.GetDiscussionsAsync(_mergeRequestKey, null); } catch (OperatorException ex) { ExceptionHandlers.Handle("Cannot obtain discussions", ex); return; } int?deletedNoteId = new int?(); foreach (Discussion discussion in discussions.Reverse()) { if (discussion.Notes.Count() == 1) { DiscussionNote note = discussion.Notes.First(); if (_currentUser != null && note != null && note.Type == "DiffNote" && note.Author != null && note.Author.Id == _currentUser.Id && note.Body == parameters.Body) { Trace.TraceInformation( "[DicsussionCreator] Deleting discussion note." + " Id: {0}, Author.Username: {1}, Created_At: {2}, Body:\n{3}", note.Id.ToString(), note.Author.Username, note.Created_At, note.Body); try { await _discussionOperator.DeleteNoteAsync(_mergeRequestKey, note.Id); deletedNoteId = note.Id; } catch (OperatorException ex) { ExceptionHandlers.Handle("Cannot delete discussion note", ex); } break; } } } string message = deletedNoteId.HasValue ? String.Format("[DicsussionCreator] Deleted note with Id {0}", deletedNoteId.Value) : "Could not find a note to delete (or could not delete it)"; Trace.TraceInformation(message); }
internal Task <Discussion> CreateDiscussionAsync(MergeRequestKey mrk, NewDiscussionParameters parameters) { return(callWithSharedClient( async(client) => await OperatorCallWrapper.Call( async() => (Discussion)await client.RunAsync( async(gl) => await gl.Projects.Get(mrk.ProjectKey.ProjectName).MergeRequests.Get(mrk.IId). Discussions.CreateNewTaskAsync(parameters))))); }
private static void submitDiscussion(Snapshot snapshot, DiffToolInfo diffToolInfo, DiffPosition position, string body, bool includeContext) { if (body.Length == 0) { MessageBox.Show("Discussion text cannot be empty", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } NewDiscussionParameters parameters = new NewDiscussionParameters { Body = body, Position = includeContext ? createPositionParameters(position) : new Nullable <PositionParameters>() }; MergeRequestDescriptor mergeRequestDescriptor = new MergeRequestDescriptor { HostName = snapshot.Host, ProjectName = snapshot.Project, IId = snapshot.MergeRequestIId }; UserDefinedSettings settings = new UserDefinedSettings(false); DiscussionManager manager = new DiscussionManager(settings); DiscussionCreator creator = manager.GetDiscussionCreator(mergeRequestDescriptor); try { creator.CreateDiscussionAsync(parameters).Wait(); } catch (DiscussionCreatorException ex) { Trace.TraceInformation( "Additional information about exception:\n" + "Position: {0}\n" + "Include context: {1}\n" + "Snapshot refs: {2}\n" + "DiffToolInfo: {3}\n" + "Body:\n{4}", position.ToString(), includeContext.ToString(), snapshot.Refs.ToString(), diffToolInfo.ToString(), body); if (!ex.Handled) { throw; } } }
async public Task CreateDiscussionAsync(NewDiscussionParameters parameters) { try { await DiscussionOperator.CreateDiscussionAsync(MergeRequestDescriptor, parameters); } catch (OperatorException ex) { bool handled = await handleGitlabError(parameters, ex); throw new DiscussionCreatorException(handled); } }
async public Task CreateDiscussionAsync(NewDiscussionParameters parameters, bool revertOnError) { try { await _discussionOperator.CreateDiscussionAsync(_mergeRequestKey, parameters); } catch (OperatorException ex) { bool handled = await handleGitlabError(parameters, ex, revertOnError); throw new DiscussionCreatorException(handled, ex); } }
async private Task <bool> handleGitlabError(NewDiscussionParameters parameters, OperatorException ex, bool revertOnError) { if (ex == null) { Trace.TraceWarning("[DiscussionCreator] An exception with null value was caught"); return(false); } if (parameters.Position == null) { Trace.TraceWarning("[DiscussionCreator] Unexpected situation at GitLab"); return(false); } if (ex.InnerException is GitLabRequestException rx) { if (rx.InnerException is System.Net.WebException wx) { if (wx.Response == null) { Trace.TraceWarning("[DiscussionCreator] Null Response in WebException"); return(false); } System.Net.HttpWebResponse response = wx.Response as System.Net.HttpWebResponse; if (response.StatusCode == System.Net.HttpStatusCode.BadRequest) { // Something went wrong at the GitLab, let's report a discussion without Position return(await createMergeRequestWithoutPosition(parameters)); } else if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError) { // Something went wrong at the GitLab if (revertOnError) { await deleteMostRecentNote(parameters); return(await createMergeRequestWithoutPosition(parameters)); } return(true); } } } return(false); }
async private Task submitDiscussionAsync(MatchInfo matchInfo, Snapshot snapshot, DiffPosition position, string body, bool includeContext) { if (body.Length == 0) { MessageBox.Show("Discussion text cannot be empty", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification); return; } NewDiscussionParameters parameters = new NewDiscussionParameters( body, includeContext ? createPositionParameters(position) : new PositionParameters?()); MergeRequestKey mrk = getMergeRequestKey(snapshot); GitLabInstance gitLabInstance = new GitLabInstance(snapshot.Host, Program.Settings); IDiscussionCreator creator = Shortcuts.GetDiscussionCreator( gitLabInstance, _modificationListener, mrk, _currentUser); try { await creator.CreateDiscussionAsync(parameters, true); } catch (DiscussionCreatorException ex) { Trace.TraceInformation( "Additional information about exception:\n" + "Position: {0}\n" + "Include context: {1}\n" + "Snapshot refs: {2}\n" + "MatchInfo: {3}\n" + "Body:\n{4}", position.ToString(), includeContext.ToString(), snapshot.Refs.ToString(), matchInfo.ToString(), body); if (!ex.Handled) { throw; } } }
async private Task <bool> createMergeRequestWithoutPosition(NewDiscussionParameters parameters) { Debug.Assert(parameters.Position.HasValue); Trace.TraceInformation("Reporting a discussion without Position (fallback)"); parameters.Body = getFallbackInfo(parameters.Position.Value) + "<br>" + parameters.Body; parameters.Position = null; try { await DiscussionOperator.CreateDiscussionAsync(MergeRequestDescriptor, parameters); } catch (OperatorException ex) { ExceptionHandlers.Handle(ex, "Cannot create a discussion (again)"); return(false); } return(true); }
async public Task <Discussion> CreateDiscussionAsync(NewDiscussionParameters parameters, bool revertOnError) { if (_discussionOperator == null) { return(null); } try { var result = await _discussionOperator.CreateDiscussionAsync(_mergeRequestKey, parameters); _modificationListener.OnDiscussionModified(_mergeRequestKey); return(result); } catch (OperatorException ex) { bool handled = await handleGitlabError(parameters, ex, revertOnError); throw new DiscussionCreatorException(handled, ex); } }
async internal Task CreateDiscussionAsync(MergeRequestDescriptor mrd, NewDiscussionParameters parameters) { GitLabClient client = new GitLabClient(mrd.HostName, Tools.Tools.GetAccessToken(mrd.HostName, Settings)); try { await client.RunAsync(async (gitlab) => await gitlab.Projects.Get(mrd.ProjectName).MergeRequests.Get(mrd.IId). Discussions.CreateNewTaskAsync(parameters)); } catch (Exception ex) { Debug.Assert(!(ex is GitLabClientCancelled)); if (ex is GitLabSharpException || ex is GitLabRequestException) { ExceptionHandlers.Handle(ex, "Cannot create a discussion"); throw new OperatorException(ex); } throw; } }
async private Task <bool> handleGitlabError(NewDiscussionParameters parameters, OperatorException ex) { if (ex.InternalException is GitLabRequestException rex) { var webException = rex.WebException; var response = ((System.Net.HttpWebResponse)webException.Response); if (response.StatusCode == System.Net.HttpStatusCode.BadRequest) { // Something went wrong at the GitLab site, let's report a discussion without Position return(await createMergeRequestWithoutPosition(parameters)); } else if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError) { // Something went wrong at the GitLab site, let's report a discussion without Position await cleanupBadNotes(parameters); return(await createMergeRequestWithoutPosition(parameters)); } } return(false); }
// Instead of searching for a latest discussion note with some heuristically prepared parameters, // let's clean up all similar notes, including a recently added one async private Task cleanupBadNotes(NewDiscussionParameters parameters) { Debug.Assert(parameters.Position.HasValue); Trace.TraceInformation("Looking up for a note with bad position..."); int deletedCount = 0; List <Discussion> discussions = await DiscussionOperator.GetDiscussionsAsync(MergeRequestDescriptor); if (discussions == null) { Trace.TraceWarning(String.Format("No discussions found")); return; } foreach (Discussion discussion in discussions) { foreach (DiscussionNote note in discussion.Notes) { if (arePositionsEqual(note.Position, parameters.Position.Value)) { Trace.TraceInformation( "Deleting discussion note." + " Id: {0}, Author.Username: {1}, Created_At: {2} (LocalTime), Body:\n{3}", note.Id.ToString(), note.Author.Username, note.Created_At.ToLocalTime(), note.Body); await DiscussionOperator.DeleteNoteAsync(MergeRequestDescriptor, note.Id); ++deletedCount; } } } Trace.TraceInformation(String.Format("Deleted {0} notes", deletedCount)); }