Skip to content

Commit d662685

Browse files
committed
Provide Git and git-gc stats in support api (#2578)
1 parent 6643ba7 commit d662685

File tree

4 files changed

+159
-58
lines changed

4 files changed

+159
-58
lines changed

config/config-server/src/com/thoughtworks/go/service/ConfigRepository.java

Lines changed: 79 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@
2626
import org.eclipse.jgit.api.*;
2727
import org.eclipse.jgit.api.errors.GitAPIException;
2828
import org.eclipse.jgit.diff.DiffFormatter;
29-
import org.eclipse.jgit.lib.ObjectId;
30-
import org.eclipse.jgit.lib.ObjectLoader;
31-
import org.eclipse.jgit.lib.ObjectReader;
32-
import org.eclipse.jgit.lib.Repository;
29+
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
30+
import org.eclipse.jgit.errors.MissingObjectException;
31+
import org.eclipse.jgit.lib.*;
3332
import org.eclipse.jgit.revwalk.RevCommit;
3433
import org.eclipse.jgit.revwalk.RevTree;
3534
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
@@ -42,7 +41,8 @@
4241
import java.io.ByteArrayOutputStream;
4342
import java.io.File;
4443
import java.io.IOException;
45-
import java.util.Iterator;
44+
import java.util.List;
45+
import java.util.Properties;
4646

4747
/**
4848
* @understands versioning cruise-config
@@ -63,7 +63,7 @@ public class ConfigRepository {
6363
private Repository gitRepo;
6464

6565
@Autowired
66-
public ConfigRepository(SystemEnvironment systemEnvironment) throws IOException{
66+
public ConfigRepository(SystemEnvironment systemEnvironment) throws IOException {
6767
this.systemEnvironment = systemEnvironment;
6868
workingDir = this.systemEnvironment.getConfigRepoDir();
6969
File configRepoDir = new File(workingDir, ".git");
@@ -79,13 +79,13 @@ public Repository getGitRepo() {
7979
public void initialize() throws IOException {
8080
if (!gitRepo.getDirectory().exists()) {
8181
gitRepo.create();
82-
}
83-
else {
82+
} else {
8483
cleanAndResetToMaster();
8584
}
8685
}
8786

88-
@Deprecated // used in test only
87+
@Deprecated
88+
// used in test only
8989
Git git() {
9090
return git;
9191
}
@@ -144,7 +144,7 @@ public GoConfigRevision call() throws GitAPIException {
144144
}
145145

146146
public RevCommit getRevCommitForMd5(String md5) throws GitAPIException {
147-
if(md5 == null)
147+
if (md5 == null)
148148
throw new NullArgumentException("md5");
149149

150150
final String expectedPart = GoConfigRevision.Fragment.md5.represent(GoConfigRevision.esc(md5));
@@ -157,14 +157,14 @@ public RevCommit getRevCommitForMd5(String md5) throws GitAPIException {
157157
throw new IllegalArgumentException(String.format("There is no config version corresponding to md5: '%s'", md5));
158158
}
159159

160-
RevCommit getRevCommitForCommitSHA(String commitSHA) throws GitAPIException {
161-
for (RevCommit revision : revisions()) {
162-
if (revision.getName().equals(commitSHA)) {
163-
return revision;
164-
}
165-
}
166-
throw new IllegalArgumentException(String.format("There is no commit corresponding to SHA: '%s'", commitSHA));
167-
}
160+
RevCommit getRevCommitForCommitSHA(String commitSHA) throws GitAPIException {
161+
for (RevCommit revision : revisions()) {
162+
if (revision.getName().equals(commitSHA)) {
163+
return revision;
164+
}
165+
}
166+
throw new IllegalArgumentException(String.format("There is no commit corresponding to SHA: '%s'", commitSHA));
167+
}
168168

169169
public GoConfigRevision getCurrentRevision() {
170170
return doLocked(new ThrowingFn<GoConfigRevision, RuntimeException>() {
@@ -191,25 +191,25 @@ public RevCommit getCurrentRevCommit() throws GitAPIException {
191191
}
192192
}
193193

194-
public GoConfigRevisions getCommits(final int pageSize, final int offset) throws Exception {
195-
return doLocked(new ThrowingFn<GoConfigRevisions, RuntimeException>() {
196-
public GoConfigRevisions call() {
197-
GoConfigRevisions goConfigRevisions = new GoConfigRevisions();
198-
try {
199-
LogCommand command = git.log().setMaxCount(pageSize).setSkip(offset);
200-
Iterable<RevCommit> revisions = command.call();
201-
for (RevCommit revision : revisions) {
202-
GoConfigRevision goConfigRevision = new GoConfigRevision(null, revision.getFullMessage());
203-
goConfigRevision.setCommitSHA(revision.name());
204-
goConfigRevisions.add(goConfigRevision);
205-
}
206-
} catch (Exception e) {
207-
// ignore
208-
}
209-
return goConfigRevisions;
210-
}
211-
});
212-
}
194+
public GoConfigRevisions getCommits(final int pageSize, final int offset) throws Exception {
195+
return doLocked(new ThrowingFn<GoConfigRevisions, RuntimeException>() {
196+
public GoConfigRevisions call() {
197+
GoConfigRevisions goConfigRevisions = new GoConfigRevisions();
198+
try {
199+
LogCommand command = git.log().setMaxCount(pageSize).setSkip(offset);
200+
Iterable<RevCommit> revisions = command.call();
201+
for (RevCommit revision : revisions) {
202+
GoConfigRevision goConfigRevision = new GoConfigRevision(null, revision.getFullMessage());
203+
goConfigRevision.setCommitSHA(revision.name());
204+
goConfigRevisions.add(goConfigRevision);
205+
}
206+
} catch (Exception e) {
207+
// ignore
208+
}
209+
return goConfigRevisions;
210+
}
211+
});
212+
}
213213

214214
private GoConfigRevision getGoConfigRevision(final RevCommit revision) {
215215
return new GoConfigRevision(contentFromTree(revision.getTree()), revision.getFullMessage());
@@ -249,31 +249,31 @@ public String configChangesFor(final String laterMD5, final String earlierMD5) t
249249
public String call() throws GitAPIException {
250250
RevCommit laterCommit = null;
251251
RevCommit earlierCommit = null;
252-
if(!StringUtil.isBlank(laterMD5)) {
252+
if (!StringUtil.isBlank(laterMD5)) {
253253
laterCommit = getRevCommitForMd5(laterMD5);
254254
}
255-
if(!StringUtil.isBlank(earlierMD5))
255+
if (!StringUtil.isBlank(earlierMD5))
256256
earlierCommit = getRevCommitForMd5(earlierMD5);
257257
return findDiffBetweenTwoRevisions(laterCommit, earlierCommit);
258258
}
259259
});
260260
}
261261

262-
public String configChangesForCommits(final String fromRevision, final String toRevision) throws GitAPIException {
263-
return doLocked(new ThrowingFn<String, GitAPIException>() {
264-
public String call() throws GitAPIException {
265-
RevCommit laterCommit = null;
266-
RevCommit earlierCommit = null;
267-
if (!StringUtil.isBlank(fromRevision)) {
268-
laterCommit = getRevCommitForCommitSHA(fromRevision);
269-
}
270-
if (!StringUtil.isBlank(toRevision)) {
271-
earlierCommit = getRevCommitForCommitSHA(toRevision);
272-
}
273-
return findDiffBetweenTwoRevisions(laterCommit, earlierCommit);
274-
}
275-
});
276-
}
262+
public String configChangesForCommits(final String fromRevision, final String toRevision) throws GitAPIException {
263+
return doLocked(new ThrowingFn<String, GitAPIException>() {
264+
public String call() throws GitAPIException {
265+
RevCommit laterCommit = null;
266+
RevCommit earlierCommit = null;
267+
if (!StringUtil.isBlank(fromRevision)) {
268+
laterCommit = getRevCommitForCommitSHA(fromRevision);
269+
}
270+
if (!StringUtil.isBlank(toRevision)) {
271+
earlierCommit = getRevCommitForCommitSHA(toRevision);
272+
}
273+
return findDiffBetweenTwoRevisions(laterCommit, earlierCommit);
274+
}
275+
});
276+
}
277277

278278
String findDiffBetweenTwoRevisions(RevCommit laterCommit, RevCommit earlierCommit) throws GitAPIException {
279279
if (laterCommit == null || earlierCommit == null) {
@@ -384,7 +384,7 @@ void cleanAndResetToMaster() throws IOException {
384384
}
385385

386386
public void garbageCollect() throws Exception {
387-
if (!systemEnvironment.get(SystemEnvironment.GO_CONFIG_REPO_PERIODIC_GC)){
387+
if (!systemEnvironment.get(SystemEnvironment.GO_CONFIG_REPO_PERIODIC_GC)) {
388388
return;
389389
}
390390
doLocked(new VoidThrowingFn<Exception>() {
@@ -404,8 +404,31 @@ public void run() throws Exception {
404404
public long getLooseObjectCount() throws Exception {
405405
return doLocked(new ThrowingFn<Long, GitAPIException>() {
406406
public Long call() throws GitAPIException {
407-
return (Long) git.gc().getStatistics().get("numberOfLooseObjects");
407+
return (Long) getStatistics().get("numberOfLooseObjects");
408408
}
409409
});
410410
}
411+
412+
public Properties getStatistics() throws GitAPIException {
413+
// not inside a doLocked/synchronized block because we don't want to block the server status service.
414+
return git.gc().getStatistics();
415+
}
416+
417+
public Long commitCountOnMaster() throws GitAPIException, IncorrectObjectTypeException, MissingObjectException {
418+
// not inside a doLocked/synchronized block because we don't want to block the server status service.
419+
// we do a `git branch` because we switch branches as part of normal git operations,
420+
// and we don't care about number of commits on those branches.
421+
List<Ref> branches = git.branchList().call();
422+
for (Ref branch : branches) {
423+
if (branch.getName().equals("refs/heads/master")) {
424+
Iterable<RevCommit> commits = git.log().add(branch.getObjectId()).call();
425+
long count = 0;
426+
for (RevCommit commit : commits) {
427+
count++;
428+
}
429+
return count;
430+
}
431+
}
432+
return Long.valueOf(-1);
433+
}
411434
}

config/config-server/test/com/thoughtworks/go/service/ConfigRepositoryTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,13 @@ public void shouldGetLooseObjectCount() throws Exception {
386386
}
387387

388388

389+
@Test
390+
public void shouldReturnNumberOfCommitsOnMaster() throws Exception {
391+
configRepo.checkin(goConfigRevision("v1", "md5-1"));
392+
configRepo.checkin(goConfigRevision("v2", "md5-2"));
393+
assertThat(configRepo.commitCountOnMaster(), is(2L));
394+
}
395+
389396
private GoConfigRevision goConfigRevision(String fileContent, String md5) {
390397
return new GoConfigRevision(fileContent, md5, "user-1", "13.2", new TimeProvider());
391398
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2016 ThoughtWorks, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.thoughtworks.go.server.service.support;
18+
19+
import com.thoughtworks.go.service.ConfigRepository;
20+
import org.eclipse.jgit.api.errors.GitAPIException;
21+
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
22+
import org.eclipse.jgit.errors.MissingObjectException;
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.stereotype.Component;
25+
26+
import java.util.LinkedHashMap;
27+
import java.util.Map;
28+
29+
@Component
30+
public class ConfigRepositoryProvider implements ServerInfoProvider {
31+
32+
private final ConfigRepository configRepository;
33+
34+
@Autowired
35+
public ConfigRepositoryProvider(ConfigRepository configRepository) {
36+
this.configRepository = configRepository;
37+
}
38+
39+
@Override
40+
public double priority() {
41+
return 6.5;
42+
}
43+
44+
@Override
45+
public void appendInformation(InformationStringBuilder infoCollector) {
46+
infoCollector.addSection(name());
47+
try {
48+
infoCollector.append("Number of commits :" + configRepository.commitCountOnMaster()).append("\n");
49+
50+
infoCollector.addSubSection("GC Statistics");
51+
infoCollector.append(configRepository.getStatistics().toString());
52+
} catch (Exception e) {
53+
throw new RuntimeException(e);
54+
}
55+
}
56+
57+
@Override
58+
public Map<String, Object> asJson() {
59+
LinkedHashMap<String, Object> json = new LinkedHashMap<>();
60+
try {
61+
json.put("Number of commits", configRepository.commitCountOnMaster());
62+
json.put("GC Statistics", configRepository.getStatistics());
63+
} catch (GitAPIException | IncorrectObjectTypeException | MissingObjectException e) {
64+
throw new RuntimeException(e);
65+
}
66+
return json;
67+
}
68+
69+
@Override
70+
public String name() {
71+
return "Config Git Repository";
72+
}
73+
}

server/src/com/thoughtworks/go/server/service/support/ServerStatusService.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@
1616

1717
package com.thoughtworks.go.server.service.support;
1818

19-
import com.fasterxml.jackson.databind.ObjectMapper;
2019
import com.thoughtworks.go.i18n.LocalizedMessage;
2120
import com.thoughtworks.go.server.domain.Username;
2221
import com.thoughtworks.go.server.service.SecurityService;
2322
import com.thoughtworks.go.server.service.result.LocalizedOperationResult;
2423
import com.thoughtworks.go.serverhealth.HealthStateType;
2524
import com.thoughtworks.go.util.DateUtils;
26-
import org.apache.commons.collections.OrderedMap;
2725
import org.apache.log4j.Logger;
2826
import org.springframework.beans.factory.annotation.Autowired;
2927
import org.springframework.stereotype.Component;

0 commit comments

Comments
 (0)