当前位置: 首页 > 知识库问答 >
问题:

预提交钩子以检查打开的Youtrack票证

高吉星
2023-03-14

我正在运行一个subversion服务器、一个TeamCity服务器和一个Youtrack服务器。目前,这些都是连接的,这意味着每当我提交某件事情时,我都会在提交消息上添加一个youtrack问题编号,并且在TeamCity的帮助下,变更集会出现在youtrack中的问题下。我现在试图实现的是阻止所有未与YouTrack中的一个开放问题链接的提交。

我在其他版本控制系统和票证管理系统中也看到过类似的功能。我注意到Youtrack有一个rest api接口,所以那可能是(一部分?)解决方案。

共有1个答案

姚鹤龄
2023-03-14

最后我自己实现了一个解决方案。

基本上,预提交钩子是一个小程序,它要么以0退出(通过这样做,提交会被接受),要么以另一个值退出(通过这样做,提交会被拒绝)。

我编写了一个批处理脚本,调用一个可运行的jar,该jar登录到Youtrack rest api,并获得提交消息中提到的票证的所有细节。如果该票证存在,并且它具有我们希望它具有的状态,那么java应用程序以值0退出,导致批处理脚本以相同的值退出并接受提交。另一方面,如果有不对的地方,java应用程序会以另一个值退出,导致提交被拒绝。

visual 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,有两个有趣的东西:一个是执行所有rest调用的类本身,另一个是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“>

<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>
 类似资料:
  • 如果我们在提交配置清单之前能够发现其中的语法错误将会是个好消息。 检查 Puppet 配置清单的语法可以使用 puppet parser validate 命令: # puppet parser validate /etc/puppet/manifests/site.pp err: Could not parse for environment production: Syntax error a

  • 我在顶部有一个,并且肯定在上面使用了。但是,这些似乎是针对没有这样的文件或目录错误时的修复。我的错误只是表示,我无法找出原因。 钩子中的代码:

  • 我刚开始研究Git钩子,但我似乎无法让它们运行。 注意:这是在Windows7电脑上。

  • 我在顶部有一个,并且在上面使用了。但是,当没有这样的文件或目录错误时,这些似乎是修复的。我的错误只是说,我不知道为什么。 挂钩中的代码:

  • 问题内容: 我在Linux上运行SVN。我希望一旦提交就运行自动部署。根据我的搜索,提交后svn似乎可以解决问题。但是我在SVN安装中找不到SVN提交后。所以我想知道这是否是单独安装?我可以下载并安装任何SVN提交后挂钩吗? 问题答案: 这不是单独的安装。在您的存储库目录中,有一个“挂钩”目录。您可以找到post-commit.tmpl,只需修改文件并将其重命名为可执行文件即可。

  • 如何从Jenkins远程触发构建? 如何配置Git post提交钩子?