我正在运行一个subversion服务器,一个TeamCity服务器和一个Youtrack服务器。 目前这些都是连接的,这意味着每当我提交一些内容时,我会在提交消息中添加一个youtrack问题编号,并且该更改集出现在Youtrack中的问题下,在作为中间人的TeamCity的帮助下。 我现在想要实现的是阻止所有未与youtrack中的开放问题相关联的提交。
我已经看到其他版本控制系统和票证管理系统中存在的类似功能。我注意到Youtrack有一个rest api接口,所以这可能是(解决方案的一部分)解决方案。
答案 0 :(得分:2)
我最终自己实施了一个解决方案。
基本上,预提交钩子是一个很小的程序,要么以0退出(通过这样做,提交被接受),要么以另一个值退出(并且通过这样做,提交被拒绝。
我编写了一个批处理脚本,调用一个可运行的jar,登录到Youtrack rest api并获取提交消息中提到的票证的所有详细信息。如果该票证存在,并且它具有我们希望它具有的状态,则java应用程序以值0退出,从而导致批处理脚本以相同的值退出并接受提交。另一方面,如果某些东西不正确,则java应用程序将以另一个值退出,从而导致提交被拒绝。
我的可视SVN存储库的批处理文件如下:
@set echo off
setlocal enabledelayedexpansion
rem Subversion sends through the path to the repository and transaction id
set REPOS=%1
set TXN=%2
rem get the commit message from svn server
for /f "delims= " %%a in ('"C:\Program Files\VisualSVN Server\bin\svnlook" log %REPOS% -t %TXN%') do (
@set COMMIT_MSG=%%a
rem call the java jar that performs the api call to match the commit message against an open ticket
java -jar C:\Users\Administrator\Desktop\Repositories\MyProject\hooks\preCommitHook-with-dependencies.jar !COMMIT_MSG!
rem if java returns System.exit(0) then we accept the commit. Otherwise print out a failure message and decline it.
echo !COMMIT_MSG! 1>&2
echo !errorlevel! 1>&2
if !errorlevel! gtr 0 (goto err) else exit 0
)
:err
echo ===================================================================== 1>&2
echo Your commit has been rejected. This is because the issue you assigned 1>&2
echo on it does not exist or is not "In Progress" state. Please try again. 1>&2
echo ===================================================================== 1>&2
exit 1
至于Java,有两个有趣的事情:一个是完成所有其余调用的类本身,另一个是pom.xml,我们让JAR包含所有依赖项。
package com.myproject;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
public class JarStart {
private static final String REST_API_LOGIN_URL = "http://yourServerIP:yourServerPort/rest/user/login";
private static final String REST_API_ISSUE_URL = "http:/yourServerIP:yourServerPort/rest/issue/";
private static final String IN_PROGRESS = "In Progress";
private RestTemplate restTemplate;
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
JarStart jarStart = context.getBean(JarStart.class);
try {
jarStart.init(args[0]);
} catch (Throwable e) {
//if anything goes wrong the commit gets declined with an error code of 12
System.exit(12);
}
}
private void init(String issueId) {
restTemplate = new RestTemplate();
String cookies = login();
String responseWithIssueDetails = getIssueDetails(issueId, cookies);
String issueState = getIssueState(responseWithIssueDetails);
decideHowToExit(issueState);
}
private String login() {
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("login", "YourUsername");
map.add("password", "YourPassword");
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<MultiValueMap<String, String>>(map, null);
HttpEntity<String> loginResponse = restTemplate.exchange(REST_API_LOGIN_URL, HttpMethod.POST, entity, String.class);
return loginResponse.getHeaders().get("Set-Cookie").toString();
}
private String getIssueDetails(String issueId, String cookies) {
HttpHeaders headers = createHeadersWithAuthentication(cookies);
HttpEntity newEntity = new HttpEntity(headers);
return restTemplate.exchange(REST_API_ISSUE_URL + issueId, HttpMethod.GET, newEntity, String.class).getBody();
}
private HttpHeaders createHeadersWithAuthentication(String cookies) {
HttpHeaders headers = new HttpHeaders();
headers.add("Cookie", cookies);
headers.add("Accept", "application/json");
headers.add("Cache-Control", "no-cache");
return headers;
}
private String getIssueState(String responseWithIssueDetails) {
Pattern pattern = Pattern.compile(".*State\",\"value\":\\[\"([a-zA-Z ]*)");
Matcher matcher = pattern.matcher(responseWithIssueDetails);
matcher.find();
return matcher.group(1);
}
private void decideHowToExit(String issueState) {
if (IN_PROGRESS.equals(issueState)) {
System.exit(0);
} else {
System.exit(1);
}
}
}
的pom.xml:
http://maven.apache.org/maven-v4_0_0.xsd“&GT;
<modelVersion>4.0.0</modelVersion>
<artifactId>preCommitHook</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<properties>
<spring.version>3.2.5.RELEASE</spring.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>preCommitHook-with-dependencies</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.yourproject.JarStart</mainClass>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>