You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by dp...@apache.org on 2019/08/13 17:58:15 UTC

[ignite-teamcity-bot] branch master updated: Resolve button without check conditions. - Fixes #152.

This is an automated email from the ASF dual-hosted git repository.

dpavlov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite-teamcity-bot.git


The following commit(s) were added to refs/heads/master by this push:
     new 995b94d  Resolve button without check conditions. - Fixes #152.
995b94d is described below

commit 995b94d9337e79ad3b9a7648db3864ee214e4204
Author: Dmitriy Pavlov <dp...@apache.org>
AuthorDate: Tue Aug 13 20:56:20 2019 +0300

    Resolve button without check conditions. - Fixes #152.
    
    Signed-off-by: Dmitriy Pavlov <dp...@apache.org>
---
 .../ignite/ci/runners/RemoteClientTmpHelper.java   |  2 +-
 .../apache/ignite/ci/tcbot/TcBotWebAppModule.java  | 25 +++++++++------------
 .../ignite/ci/tcbot/issue/IssueDetector.java       |  2 +-
 .../org/apache/ignite/ci/user/ITcBotUserCreds.java |  6 +----
 .../ignite/ci/web/auth/AuthenticationFilter.java   |  2 +-
 .../ignite/ci/web/rest/board/BoardRestService.java | 10 ++++-----
 ...oardRestService.java => DefectRestService.java} | 26 +++++++++++-----------
 .../org/apache/ignite/ci/web/rest/login/Login.java |  2 +-
 .../ignite/ci/web/rest/login/UserService.java      |  2 +-
 .../src/main/webapp/board/index.html               | 18 +++++++++++++++
 .../ci/tcbot/chain/MockBasedTcBotModule.java       |  2 +-
 .../org/apache/ignite/ci/user/LoginAuthTest.java   |  2 +-
 .../org/apache/ignite/ci/user/TcHelperUser.java    |  0
 .../org/apache/ignite/ci/user/UserSession.java     |  0
 .../ignite/tcbot/engine/TcBotEngineModule.java     |  4 ++++
 .../ignite/tcbot/engine/board/BoardService.java    | 19 +++++++++++++++-
 .../tcbot/engine/defect/DefectCompacted.java       |  9 ++++++--
 .../ignite/tcbot/engine/defect/DefectsStorage.java | 20 +++++++++++++++--
 .../ignite/tcbot/engine}/user/IUserStorage.java    |  5 +++--
 .../tcbot/engine}/user/UserAndSessionsStorage.java |  4 ++--
 .../ignite/tcignited/creds/ICredentialsProv.java   |  2 ++
 21 files changed, 107 insertions(+), 55 deletions(-)

diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/RemoteClientTmpHelper.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/RemoteClientTmpHelper.java
index ad01803..8a74ca1 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/RemoteClientTmpHelper.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/RemoteClientTmpHelper.java
@@ -37,7 +37,7 @@ import org.apache.ignite.ci.issue.Issue;
 import org.apache.ignite.ci.issue.IssueKey;
 import org.apache.ignite.tcbot.engine.issue.IssueType;
 import org.apache.ignite.tcbot.engine.issue.IssuesStorage;
-import org.apache.ignite.ci.tcbot.user.UserAndSessionsStorage;
+import org.apache.ignite.tcbot.engine.user.UserAndSessionsStorage;
 import org.apache.ignite.ci.teamcity.ignited.BuildRefCompacted;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 import org.apache.ignite.ci.user.TcHelperUser;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/TcBotWebAppModule.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/TcBotWebAppModule.java
index bb1bbd5..c4affe0 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/TcBotWebAppModule.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/TcBotWebAppModule.java
@@ -26,28 +26,24 @@ import java.util.concurrent.TimeoutException;
 import javax.inject.Provider;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.ci.db.Ignite1Init;
+import org.apache.ignite.ci.observer.BuildObserver;
+import org.apache.ignite.ci.observer.ObserverTask;
 import org.apache.ignite.ci.tcbot.conf.LocalFilesBasedConfig;
+import org.apache.ignite.ci.tcbot.issue.IssueDetector;
 import org.apache.ignite.ci.tcbot.trends.MasterTrendsService;
-import org.apache.ignite.ci.tcbot.user.IUserStorage;
-import org.apache.ignite.ci.tcbot.user.UserAndSessionsStorage;
+import org.apache.ignite.ci.web.model.hist.VisasHistoryStorage;
+import org.apache.ignite.githubignited.GitHubIgnitedModule;
+import org.apache.ignite.jiraignited.JiraIgnitedModule;
 import org.apache.ignite.tcbot.common.conf.IDataSourcesConfigSupplier;
+import org.apache.ignite.tcbot.common.exeption.ExceptionUtil;
+import org.apache.ignite.tcbot.common.exeption.ServicesStartingException;
 import org.apache.ignite.tcbot.engine.TcBotEngineModule;
 import org.apache.ignite.tcbot.engine.conf.ITcBotConfig;
-import org.apache.ignite.tcbot.engine.issue.IIssuesStorage;
-import org.apache.ignite.tcbot.engine.issue.IssuesStorage;
+import org.apache.ignite.tcbot.engine.pool.TcUpdatePool;
 import org.apache.ignite.tcbot.notify.TcBotNotificationsModule;
-import org.apache.ignite.tcbot.persistence.scheduler.SchedulerModule;
-import org.apache.ignite.githubignited.GitHubIgnitedModule;
-import org.apache.ignite.jiraignited.JiraIgnitedModule;
-import org.apache.ignite.ci.observer.BuildObserver;
-import org.apache.ignite.ci.observer.ObserverTask;
-import org.apache.ignite.ci.tcbot.issue.IssueDetector;
-import org.apache.ignite.tcbot.common.exeption.ServicesStartingException;
 import org.apache.ignite.tcbot.persistence.TcBotPersistenceModule;
+import org.apache.ignite.tcbot.persistence.scheduler.SchedulerModule;
 import org.apache.ignite.tcignited.TeamcityIgnitedModule;
-import org.apache.ignite.tcbot.common.exeption.ExceptionUtil;
-import org.apache.ignite.tcbot.engine.pool.TcUpdatePool;
-import org.apache.ignite.ci.web.model.hist.VisasHistoryStorage;
 
 /**
  *
@@ -92,7 +88,6 @@ public class TcBotWebAppModule extends AbstractModule {
         bind(ITcBotConfig.class).to(LocalFilesBasedConfig.class).in(new SingletonScope());
         //todo remove duplication of instances for base and for overriden class
         bind(IDataSourcesConfigSupplier.class).to(LocalFilesBasedConfig.class).in(new SingletonScope());
-        bind(IUserStorage.class).to(UserAndSessionsStorage.class).in(new SingletonScope());
         bind(MasterTrendsService.class).in(new SingletonScope());
         bind(ITcBotBgAuth.class).to(TcBotBgAuthImpl.class).in(new SingletonScope());
     }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java
index 807b63d..e96a0be 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java
@@ -40,7 +40,7 @@ import org.apache.ignite.tcbot.engine.issue.IssueType;
 import org.apache.ignite.ci.jobs.CheckQueueJob;
 import org.apache.ignite.tcbot.engine.tracked.DisplayMode;
 import org.apache.ignite.tcbot.notify.ISlackSender;
-import org.apache.ignite.ci.tcbot.user.IUserStorage;
+import org.apache.ignite.tcbot.engine.user.IUserStorage;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeCompacted;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 import org.apache.ignite.ci.user.ITcBotUserCreds;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/ITcBotUserCreds.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/ITcBotUserCreds.java
index 95283ba..bef6f1f 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/ITcBotUserCreds.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/ITcBotUserCreds.java
@@ -17,10 +17,8 @@
 
 package org.apache.ignite.ci.user;
 
-import com.google.common.base.Strings;
-import org.apache.ignite.tcignited.creds.ICredentialsProv;
-
 import javax.servlet.http.HttpServletRequest;
+import org.apache.ignite.tcignited.creds.ICredentialsProv;
 
 public interface ITcBotUserCreds extends ICredentialsProv {
     /** Key for context attribute. */
@@ -30,8 +28,6 @@ public interface ITcBotUserCreds extends ICredentialsProv {
     public static ITcBotUserCreds get(HttpServletRequest req) {
         return (ITcBotUserCreds) req.getAttribute(_KEY);
     }
-  
-    String getPrincipalId();
 
     byte[] getUserKey();
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/auth/AuthenticationFilter.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/auth/AuthenticationFilter.java
index 92d08b1..b81b834 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/auth/AuthenticationFilter.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/auth/AuthenticationFilter.java
@@ -38,7 +38,7 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.Provider;
 import org.apache.ignite.Ignite;
-import org.apache.ignite.ci.tcbot.user.IUserStorage;
+import org.apache.ignite.tcbot.engine.user.IUserStorage;
 import org.apache.ignite.ci.user.ITcBotUserCreds;
 import org.apache.ignite.ci.user.TcHelperUser;
 import org.apache.ignite.ci.user.UserSession;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/board/BoardRestService.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/board/BoardRestService.java
index d8550a4..f6cbde5 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/board/BoardRestService.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/board/BoardRestService.java
@@ -20,6 +20,7 @@ import com.google.inject.Injector;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.GET;
+import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
@@ -32,7 +33,7 @@ import org.apache.ignite.tcbot.engine.ui.BoardSummaryUi;
 @Path(BoardRestService.BOARD)
 @Produces(MediaType.APPLICATION_JSON)
 public class BoardRestService {
-    public static final String BOARD = "board";
+    static final String BOARD = "board";
 
     /** Servlet Context. */
     @Context
@@ -45,11 +46,8 @@ public class BoardRestService {
     @GET
     @Path("summary")
     public BoardSummaryUi getSummary() {
+        ITcBotUserCreds creds = ITcBotUserCreds.get(req);
 
-        final ITcBotUserCreds creds = ITcBotUserCreds.get(req);
-        final Injector injector = CtxListener.getInjector(ctx);
-        final BoardService boardSvc = injector.getInstance(BoardService.class);
-
-        return boardSvc.summary(creds);
+        return CtxListener.getInjector(ctx).getInstance(BoardService.class).summary(creds);
     }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/board/BoardRestService.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/board/DefectRestService.java
similarity index 72%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/board/BoardRestService.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/board/DefectRestService.java
index d8550a4..f30dae8 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/board/BoardRestService.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/board/DefectRestService.java
@@ -16,10 +16,10 @@
  */
 package org.apache.ignite.ci.web.rest.board;
 
-import com.google.inject.Injector;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.GET;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
@@ -27,12 +27,11 @@ import javax.ws.rs.core.MediaType;
 import org.apache.ignite.ci.user.ITcBotUserCreds;
 import org.apache.ignite.ci.web.CtxListener;
 import org.apache.ignite.tcbot.engine.board.BoardService;
-import org.apache.ignite.tcbot.engine.ui.BoardSummaryUi;
 
-@Path(BoardRestService.BOARD)
+@Path(DefectRestService.BOARD)
 @Produces(MediaType.APPLICATION_JSON)
-public class BoardRestService {
-    public static final String BOARD = "board";
+public class DefectRestService {
+    static final String BOARD = "defect";
 
     /** Servlet Context. */
     @Context
@@ -42,14 +41,15 @@ public class BoardRestService {
     @Context
     private HttpServletRequest req;
 
-    @GET
-    @Path("summary")
-    public BoardSummaryUi getSummary() {
 
-        final ITcBotUserCreds creds = ITcBotUserCreds.get(req);
-        final Injector injector = CtxListener.getInjector(ctx);
-        final BoardService boardSvc = injector.getInstance(BoardService.class);
+    @POST
+    @Path("resolve")
+    public void resolveDefect(@FormParam("id") Integer defectId) {
+        ITcBotUserCreds creds = ITcBotUserCreds.get(req);
 
-        return boardSvc.summary(creds);
+        CtxListener.getInjector(ctx)
+                .getInstance(BoardService.class)
+                .resolveDefect(defectId, creds);
     }
+
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/Login.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/Login.java
index 37337bf..9716374 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/Login.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/Login.java
@@ -20,7 +20,7 @@ package org.apache.ignite.ci.web.rest.login;
 import com.google.common.base.Preconditions;
 import com.google.inject.Injector;
 import org.apache.ignite.tcbot.engine.conf.ITcBotConfig;
-import org.apache.ignite.ci.tcbot.user.IUserStorage;
+import org.apache.ignite.tcbot.engine.user.IUserStorage;
 import org.apache.ignite.tcservice.model.user.User;
 import org.apache.ignite.tcignited.ITeamcityIgnitedProvider;
 import org.apache.ignite.tcservice.login.ITcLogin;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/UserService.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/UserService.java
index fb6229a..d88f36f 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/UserService.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/login/UserService.java
@@ -34,7 +34,7 @@ import javax.ws.rs.core.MediaType;
 import org.apache.ignite.ci.tcbot.ITcBotBgAuth;
 import org.apache.ignite.tcbot.engine.conf.ITcBotConfig;
 import org.apache.ignite.ci.tcbot.issue.IssueDetector;
-import org.apache.ignite.ci.tcbot.user.IUserStorage;
+import org.apache.ignite.tcbot.engine.user.IUserStorage;
 import org.apache.ignite.ci.tcbot.visa.TcBotTriggerAndSignOffService;
 import org.apache.ignite.tcbot.engine.conf.ITrackedBranch;
 import org.apache.ignite.tcservice.model.user.User;
diff --git a/ignite-tc-helper-web/src/main/webapp/board/index.html b/ignite-tc-helper-web/src/main/webapp/board/index.html
index 5f9c86a..4f8774b 100644
--- a/ignite-tc-helper-web/src/main/webapp/board/index.html
+++ b/ignite-tc-helper-web/src/main/webapp/board/index.html
@@ -60,6 +60,20 @@
             },
             methods: {
                 formChanged: function () {
+                },
+
+                onResolve: function (id) {
+                    $.ajax({
+                        url: "/rest/defect/resolve",
+                        type: 'POST',
+                        data: { id: id } ,
+                        success: function (res) {
+                            window.alert("Resolved defect [" + id + "]");
+
+                            loadData();
+                        },
+                        error: showErrInLoadStatus
+                    });
                 }
             }
         });
@@ -162,14 +176,18 @@
             <template v-slot:expanded-item="{ headers, item }">
                 <td :colspan="headers.length">
                     Branch: <a :href="'/current.html?branch=' + item.trackedBranch">{{item.trackedBranch}}</a>
+
                     Commits from:
                     <div v-for="(candidate) in item.blameCandidates">
                         {{ candidate }}
                     </div>
 
+                    Tests affected:
                     <div v-for="(test) in item.testOrSuitesAffected">
                         {{ test }}
                     </div>
+
+                    <button v-on:click="onResolve(item.id)">Resolve</button>
                 </td>
             </template>
 
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
index 6f54189..04e39be 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
@@ -40,7 +40,7 @@ import org.apache.ignite.tcbot.engine.conf.ITrackedBranchesConfig;
 import org.apache.ignite.tcbot.engine.conf.NotificationsConfig;
 import org.apache.ignite.tcbot.engine.conf.TcServerConfig;
 import org.apache.ignite.tcbot.engine.issue.IIssuesStorage;
-import org.apache.ignite.ci.tcbot.user.IUserStorage;
+import org.apache.ignite.tcbot.engine.user.IUserStorage;
 import org.apache.ignite.tcbot.notify.IEmailSender;
 import org.apache.ignite.tcbot.notify.ISlackSender;
 import org.apache.ignite.tcbot.persistence.IStringCompactor;
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/user/LoginAuthTest.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/user/LoginAuthTest.java
index 483cafc..5b1b7f9 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/user/LoginAuthTest.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/user/LoginAuthTest.java
@@ -22,7 +22,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
 import javax.ws.rs.container.ContainerRequestContext;
-import org.apache.ignite.ci.tcbot.user.UserAndSessionsStorage;
+import org.apache.ignite.tcbot.engine.user.UserAndSessionsStorage;
 import org.apache.ignite.tcservice.model.user.User;
 import org.apache.ignite.tcservice.login.ITcLogin;
 import org.apache.ignite.tcbot.common.util.Base64Util;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/TcHelperUser.java b/tcbot-engine/src/main/java/org/apache/ignite/ci/user/TcHelperUser.java
similarity index 100%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/TcHelperUser.java
rename to tcbot-engine/src/main/java/org/apache/ignite/ci/user/TcHelperUser.java
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/UserSession.java b/tcbot-engine/src/main/java/org/apache/ignite/ci/user/UserSession.java
similarity index 100%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/UserSession.java
rename to tcbot-engine/src/main/java/org/apache/ignite/ci/user/UserSession.java
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/TcBotEngineModule.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/TcBotEngineModule.java
index ab39d2d..515e8e6 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/TcBotEngineModule.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/TcBotEngineModule.java
@@ -28,6 +28,8 @@ import org.apache.ignite.tcbot.engine.issue.IIssuesStorage;
 import org.apache.ignite.tcbot.engine.issue.IssuesStorage;
 import org.apache.ignite.tcbot.engine.tracked.IDetailedStatusForTrackedBranch;
 import org.apache.ignite.tcbot.engine.tracked.TrackedBranchChainsProcessor;
+import org.apache.ignite.tcbot.engine.user.IUserStorage;
+import org.apache.ignite.tcbot.engine.user.UserAndSessionsStorage;
 
 /**
  *
@@ -45,6 +47,8 @@ public class TcBotEngineModule extends AbstractModule {
 
         bind(BoardService.class).in(new SingletonScope());
 
+        bind(IUserStorage.class).to(UserAndSessionsStorage.class).in(new SingletonScope());
+
         install(new TcBotCommonModule());
     }
 }
\ No newline at end of file
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/board/BoardService.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/board/BoardService.java
index 0d4291d..71e516c 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/board/BoardService.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/board/BoardService.java
@@ -28,11 +28,14 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import javax.inject.Inject;
+
+import com.google.common.base.Preconditions;
 import org.apache.ignite.ci.issue.Issue;
 import org.apache.ignite.ci.issue.IssueKey;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeCompacted;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeDao;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
+import org.apache.ignite.ci.user.TcHelperUser;
 import org.apache.ignite.tcbot.common.conf.ITcServerConfig;
 import org.apache.ignite.tcbot.common.interceptor.MonitoredTask;
 import org.apache.ignite.tcbot.common.util.FutureUtil;
@@ -47,6 +50,7 @@ import org.apache.ignite.tcbot.engine.issue.IIssuesStorage;
 import org.apache.ignite.tcbot.engine.issue.IssueType;
 import org.apache.ignite.tcbot.engine.ui.BoardDefectSummaryUi;
 import org.apache.ignite.tcbot.engine.ui.BoardSummaryUi;
+import org.apache.ignite.tcbot.engine.user.IUserStorage;
 import org.apache.ignite.tcbot.persistence.IStringCompactor;
 import org.apache.ignite.tcbot.persistence.scheduler.IScheduler;
 import org.apache.ignite.tcignited.ITeamcityIgnited;
@@ -63,8 +67,8 @@ public class BoardService {
     @Inject DefectsStorage defectStorage;
     @Inject IScheduler scheduler;
     @Inject IStringCompactor compactor;
-
     @Inject BuildChainProcessor buildChainProcessor;
+    @Inject IUserStorage userStorage;
 
     /**
      * @param creds Credentials.
@@ -211,4 +215,17 @@ public class BoardService {
 
         return cntDefects.get() + " defects processed for " + cntIssues.get() + " issues checked";
     }
+
+    public void resolveDefect(Integer defectId, ICredentialsProv creds) {
+        DefectCompacted defect = defectStorage.load(defectId);
+        Preconditions.checkState(defect!=null, "Can't find defect by ID");
+
+        String principalId = creds.getPrincipalId();
+        TcHelperUser user = userStorage.getUser(principalId);
+
+        int stringId = compactor.getStringId(principalId);
+        defect.resolvedByUsernameId(stringId);
+
+        defectStorage.save(defect);
+    }
 }
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectCompacted.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectCompacted.java
index a0c105b..c9cf35b 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectCompacted.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectCompacted.java
@@ -26,7 +26,7 @@ import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 import org.apache.ignite.tcbot.persistence.IStringCompactor;
 
 public class DefectCompacted {
-    /** Syntetic Defect Id. */
+    /** Synthetic Defect Id. */
     private int id;
 
     private int tcBranch = -1;
@@ -40,8 +40,9 @@ public class DefectCompacted {
     /** Tracked branch Compactor string ID. */
     private int trackedBranchCid = -1;
 
-    /** Resolved by username id. */
+    /** Resolved by username id : Compactor ID of user login (principal ID). */
     private int resolvedByUsernameId = -1;
+
     /** Commits hashes involved. */
     private List<CommitCompacted> commits = new ArrayList<>();
 
@@ -161,4 +162,8 @@ public class DefectCompacted {
     public int trackedBranchCid() {
         return trackedBranchCid;
     }
+
+    public void resolvedByUsernameId(int stringId) {
+        this.resolvedByUsernameId = stringId;
+    }
 }
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectsStorage.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectsStorage.java
index 2efb4e2..b57bac5 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectsStorage.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/defect/DefectsStorage.java
@@ -16,6 +16,7 @@
  */
 package org.apache.ignite.tcbot.engine.defect;
 
+import com.google.common.base.Preconditions;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -114,6 +115,8 @@ public class DefectsStorage {
         }
 
         int id = (int)sequence().incrementAndGet();
+        if (id == 0)
+            id = (int)sequence().incrementAndGet();
 
         DefectCompacted defect = new DefectCompacted(id)
             .commits(commitsToUse)
@@ -130,7 +133,7 @@ public class DefectsStorage {
     }
 
     public DefectCompacted processExisting(BiFunction<Integer, DefectCompacted, DefectCompacted> function,
-        IgniteCache<Integer, DefectCompacted> cache, Integer id, DefectCompacted openDefect) {
+                                           IgniteCache<Integer, DefectCompacted> cache, Integer id, DefectCompacted openDefect) {
         DefectCompacted defect = function.apply(id, openDefect);
 
         defect.id(id);
@@ -143,7 +146,7 @@ public class DefectsStorage {
     public List<DefectCompacted> loadAllDefects() {
         List<DefectCompacted> res = new ArrayList<>();
         try (QueryCursor<Cache.Entry<Integer, DefectCompacted>> qry = cache().query(new ScanQuery<Integer, DefectCompacted>()
-            .setFilter((k, v) -> v.resolvedByUsernameId() < 1))) {
+                .setFilter((k, v) -> v.resolvedByUsernameId() < 1))) {
             for (Cache.Entry<Integer, DefectCompacted> next : qry) {
                 DefectCompacted openDefect = next.getValue();
                 openDefect.id(next.getKey());
@@ -152,4 +155,17 @@ public class DefectsStorage {
         }
         return res;
     }
+
+    public DefectCompacted load(Integer defectId) {
+        DefectCompacted defectCompacted = cache().get(defectId);
+        if (defectCompacted != null && defectCompacted.id() == 0)
+            defectCompacted.id(defectId);
+
+        return defectCompacted;
+    }
+
+    public void save(DefectCompacted defect) {
+        Preconditions.checkState(defect.id() != 0);
+        cache().put(defect.id(), defect);
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/user/IUserStorage.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/user/IUserStorage.java
similarity index 94%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/user/IUserStorage.java
rename to tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/user/IUserStorage.java
index 78abbb8..925b245 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/user/IUserStorage.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/user/IUserStorage.java
@@ -14,12 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.ignite.ci.tcbot.user;
+package org.apache.ignite.tcbot.engine.user;
 
 import java.util.stream.Stream;
 import org.apache.ignite.ci.user.TcHelperUser;
 import org.apache.ignite.ci.user.UserSession;
-import org.jetbrains.annotations.Nullable;
+
+import javax.annotation.Nullable;
 
 /**
  * Teamcity Bot User and Sessions storage interface.
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/user/UserAndSessionsStorage.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/user/UserAndSessionsStorage.java
similarity index 97%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/user/UserAndSessionsStorage.java
rename to tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/user/UserAndSessionsStorage.java
index 43a7b7a..78020b2 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/user/UserAndSessionsStorage.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/user/UserAndSessionsStorage.java
@@ -15,10 +15,11 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.tcbot.user;
+package org.apache.ignite.tcbot.engine.user;
 
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
+import javax.annotation.Nullable;
 import javax.cache.Cache;
 import javax.inject.Inject;
 import javax.inject.Provider;
@@ -27,7 +28,6 @@ import org.apache.ignite.IgniteCache;
 import org.apache.ignite.ci.user.TcHelperUser;
 import org.apache.ignite.ci.user.UserSession;
 import org.apache.ignite.tcbot.persistence.CacheConfigs;
-import org.jetbrains.annotations.Nullable;
 
 public class UserAndSessionsStorage implements IUserStorage {
     public static final String USERS = "users";
diff --git a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/creds/ICredentialsProv.java b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/creds/ICredentialsProv.java
index 908abcd..402a582 100644
--- a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/creds/ICredentialsProv.java
+++ b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/creds/ICredentialsProv.java
@@ -19,6 +19,8 @@ package org.apache.ignite.tcignited.creds;
 import com.google.common.base.Strings;
 
 public interface ICredentialsProv {
+    String getPrincipalId();
+
     /**
      * Gets username for particular service
      * @param srvCode Server Id.