如何检索我的 Java 网络应用程序的更改列表?

How can I retrieve a list of changes for my Java web app?

我有一个 spring 启动应用程序,我希望有一个页面列出最近的内部版本号,以及它包含的更改列表。我使用 Rally、git 和 Jenkins,但没有手动更新 HTML 或数据库 table,我想知道是否有更自动化的方法来检索这些信息?

任何人都可以分享他们在应用程序内的网页上列出此信息的方法吗?

如果您在 Jenkins 中将 /api/json?pretty=true 附加到作业 URL 的末尾,您可以看到作业本身的 JSON 输出,这可以引导您找到最新的内部版本号.此外,这将引导您进入最新构建的 URL,它(再次附加 /api/json?pretty=true)可以引导您进入 JSON 变更集列表(以及相应的提交消息)。

您甚至可能不需要使用 Rally! :-)

您可以使用 JSON 封送处理和 RestTemplate Spring class.[=13 从 Spring 应用程序中使用 JSON =]

您可以通过使用 Git connector and Jenkins plugin 从 git 跟踪成功和失败的 Jenkins 构建提交到关联的 CA AgileCentral (Rally) 工件,只要两者都指向同一个存储库,并且在 git 提到相关工件的 FormattedID。

这是一个基于 Rally API Toolkit For Java. Regardless of the choice of toolkit, language, etc. it is the underlying WS API 对象模型的 Java 示例,它提供了对此数据的访问。我通过 CreationDate 限制了构建查询。在 Build 对象的其他字段中,我获取 Changesets 集合。该集合的每个元素都是对 Changeset 对象的引用。 Git 连接器在 CA Agile Central(Rally) 中创建变更集对象。每个 Changeset 对象都有 Artfacts 集合字段和 Changes 集合字段。 Artifacts 集合的每个元素都是对 Rally 神器的引用,例如用户故事,缺陷。通过在每个 Change 对象上获取 PathAndFilename,您可以获得关联的源文件。 现在我们可以将失败的构建跟踪到特定的提交、文件和用户故事。

这是由下面的 Java 代码创建的控制台输出的屏幕截图。最终您可能希望以更具视觉吸引力的方式呈现数据。此示例仅显示构建和提交可以通过 WS API 追踪到用户故事或缺陷。

通常需要单独请求来补水 collections in WS API。由于 Build 和 Cangesets 数据可能很大,因此通过某些标准绑定这些查询,例如CreationDate 将使它更快。

public class GetBuildData {

    public static void main(String[] args) throws Exception {

        String host = "https://rally1.rallydev.com";
        String apiKey = "_abc123"; 
        String applicationName = "NickM:GetBuildData";
        String workspaceRef = "/workspace/12345";
        String projectRef = "/project/1346";

        RallyRestApi restApi = null;
        try {
            String dateString = "2016-05-12";
            restApi = new RallyRestApi(new URI(host),apiKey);
            restApi.setApplicationName(applicationName);
            QueryRequest buildRequest = new QueryRequest("Build");
            buildRequest.setFetch(new Fetch("Status,Message,Start,Uri,Changesets"));
            buildRequest.setQueryFilter(new QueryFilter("CreationDate", ">", dateString));
            buildRequest.setWorkspace(workspaceRef);
            buildRequest.setProject(projectRef);
            QueryResponse buildResponse = restApi.query(buildRequest);
            for (int i=0; i<buildResponse.getTotalResultCount();i++){
                JsonObject buildObj = buildResponse.getResults().get(i).getAsJsonObject();
                System.out.println("Build Status: " + buildObj.get("Status") +
                        "\n Build Message: " + buildObj.get("Message") +
                        "\n Build Start:   " + buildObj.get("Start") +
                        "\n Build Uri:     " + buildObj.get("Uri"));
                JsonObject changesetsCollection = buildObj.get("Changesets").getAsJsonObject();
                QueryRequest changesetsRequest = new QueryRequest(changesetsCollection);
                changesetsRequest.setFetch(new Fetch("Artifacts","Changes", "Revision"));
                changesetsRequest.setLimit(1000);
                QueryResponse changesetsResponse = restApi.query(changesetsRequest);
                for (int j=0; j<changesetsResponse.getTotalResultCount();j++) {
                    JsonObject changesetObj = changesetsResponse.getResults().get(j).getAsJsonObject();
                    System.out.println("\nChangeset Revision: " + changesetObj.get("Revision"));
                    JsonObject artifactsCollection = changesetObj.get("Artifacts").getAsJsonObject();
                    QueryRequest artifactsRequest = new QueryRequest(artifactsCollection);
                    artifactsRequest.setFetch(new Fetch("FormattedID"));
                    QueryResponse artifactsResponse = restApi.query(artifactsRequest);
                    for (int k=0; k<artifactsResponse.getTotalResultCount();k++) {
                        JsonObject artifactObj = artifactsResponse.getResults().get(k).getAsJsonObject();
                        System.out.println("\nArtifact FormattedID: " + artifactObj.get("FormattedID"));
                    }
                    JsonObject changesCollection = changesetObj.get("Changes").getAsJsonObject();
                    QueryRequest changesRequest = new QueryRequest(changesCollection);
                    changesRequest.setWorkspace(workspaceRef);
                    changesRequest.setProject(projectRef);
                    changesRequest.setFetch(new Fetch("PathAndFilename"));
                    QueryResponse changesResponse = restApi.query(changesRequest);
                    for (int l=0; l<changesResponse.getTotalResultCount();l++) {
                        JsonObject changeObj = changesResponse.getResults().get(l).getAsJsonObject();
                        System.out.println("Change PathAndFilename: " + changeObj.get("PathAndFilename"));
                    }

                }
                System.out.println("--------------------------------");
            }
        } finally {
            if (restApi != null) {
                restApi.close();
            }
        }
    }
}

如果要在 Agile Central (Rally) 中显示构建数据 AppSDK2.1 javascript 可以在自定义页面中部署应用程序。这是开始的快速示例:

    <!DOCTYPE html>
<html>
<head>
    <title>Builds by Date</title>
    <script type="text/javascript" src="/apps/2.1/sdk.js"></script>
    <script type="text/javascript">
        Rally.onReady(function () {
                Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',
    launch: function() {
        this.add({
            xtype: 'component',
            itemId: 'datepick',
            html: 'pick a date:',
            width: 100,
            margin: 10
        },
        {
            xtype: 'rallydatepicker',
            showToday: false,
            contentEl: Ext.ComponentQuery.query('#datepick')[0],
            margin: 10,
            handler: function(picker, date) {
                this.getBuilds(date);
            },
            scope:this
        },
        {
            xtype: 'container',
            itemId: 'gridContainer'
        });
    },
    getBuilds:function(date){
        var formattedDate = Rally.util.DateTime.formatWithDefault(date, this.getContext());
        Ext.ComponentQuery.query('#datepick')[0].update((formattedDate) + '<br /> selected');
        if (this.down('rallygrid')) {
            Ext.ComponentQuery.query('#gridContainer')[0].remove(Ext.ComponentQuery.query('#buildsGrid')[0], true);
        }
        this.down('#gridContainer').add({
            xtype: 'rallygrid',
            itemId: 'buildsGrid',
            columnCfgs: [
                'Status',
                'Message',
                'Start',
                'Uri',
                'Changesets'
            ],
            storeConfig: {
                model: 'build',
                filters:[
                    {
                        property: 'CreationDate',
                        operator: '>=',
                        value: Rally.util.DateTime.toIsoString(date,true)
                    }
                ]
            }
        });
    }
});
            Rally.launchApp('CustomApp', {
                name:"Builds by Date",
                parentRepos:""
            });
        });
    </script>
    <style type="text/css">
        .app {
  /* Add app styles here */
}
    </style>
</head>
<body>
</body>
</html>