.net持续集成sonarqube篇之 sonarqube触发webhook

系列目录html

WebHook近些年来变得愈来愈流行,github,gitlab等代码托管平台都提供webhook功能.关于webhook这里不作详细介绍,你们能够参阅读相关互联网书籍或者材料来更深了解.能够把它简单理解为某一事件完成之后的一个回调.git

在持续集成环境里,咱们能够使用Sonarqube的webhook功能来实现持续发布和发布包归档功能.大体思路是当项目构建成功后咱们能够经过webhook通知服务器构建任务已完成,接下来web 服务器能够根据webhook传递的参数决定要处理的包是哪一个项目的包(经过项目的key来判断),如何对包进行归档以及如何把包发布到远程服务器(经过http,ftp等方式).github

Web服务器搭建

要想实现webhook,必须有一个预先设计好的web服务器供回调.咱们预先建好了一个web项目(新建一个mvc项目便可)web

因为是测试,咱们这里就用Visual的模板生成一个mvc项目,而后在Home控制器下新建一个Action,代码以下:数据库

public IActionResult HookTest([FromBody]SonarQubeVm sonar)
        {
            return new EmptyResult();
        }

因为Sonarqube webhook是经过post方式提交,所以action必须支持Post方式请求.服务器

参数sonar是SonarQubeVm类型的参数,是根据Sonarqube请求规格文档构建的,代码以下:mvc

public class SonarQubeVm
    {
        public DateTime? AnalysedAt { get; set; }
        public SonarProjectInfo project { get; set; }
        public string ServerUrl { get; set; }
        public string Status { get; set; }
        public string TaskId { get; set; }
    }

    public class SonarProjectInfo
    {
        public string Key { get; set; }
        public string Name { get; set; }
    }

注意以上参数并不彻底包含Sonarqube返回的全部参数,咱们只取了部分.关于Sonarqube webhook完整请求参数请查看http://localhost:9000/documentation/webhooks,localhost:9000是默认的服务器的端口号,若是你更改了端口号或者从外网请求,则要更改成实际的ip地址(或者域名)加上指定的端口号.ide

WebHook调用

在Sonarqube里能够经过两种方式调用webhook,全局模式和项目模式.全局模式每当一个构建成功后就会触发.项目模式则只有指定的项目构建之后才会触发.gitlab

全局模式

avatar

如上图示,咱们点击全局Administration而后点击configuration在出现的下拉列表里选择WebHooks,此时右上角有一个create按钮,点击后出现一个弹出框,要求输入名称和url,而后点击肯定.post

avatar

咱们以调试模式启动web项目,而后执行一个Sonarqube项目构建,执行完成后看看是否有请求到达web服务器.

MSBuild.SonarQube.Runner.exe begin /k:"mytest" /n:"mytest" /v:"v3.0" /d:sonar.cs.opencover.reportsPaths="%CD%\testcover.xml"

msbuild.exe

"E:\personalproject\newTest2018\ConsoleApp1\packages\OpenCover.4.6.519\tools\OpenCover.Console.exe" -output:"%CD%\testcover.xml" -register:user -target:"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe" -targetargs:"%CD%\bin\Debug\NunitTest.dll"

MSBuild.SonarQube.Runner.exe end

以上是咱们上一节讲单元测试的时候执行的代码只修改了版本号.咱们执行它.

等等以上代码都执行完成,稍等片刻咱们就能够看到http请求击中断点

avatar

经过serverurl是来自localhost:9000,咱们能够肯定是Sonarqube发来的请求.项目的key和name都是咱们设定的mytest

以上仅是个示例程序,没有有用代码,实际项目中咱们能够根据webhook请求的key来获取到构建的是哪一个项目,而后根据预先设定的逻辑决定把它归档到哪里,以及把它发布到哪些web服务器下的哪些目录里(前面咱们讲过经过ftt方式发布web项目,能够在这里使用)

项目模式

项目模式与全局模式设置彻底同样,只是入口不一样,项目模式须要进入项目的Administration标签里进行设置.仍然以mytest项目为例子,咱们打开mytest项目,进入到Administration标签里选择webhooks便可.

avatar

设置和全局设置同样,这里再也不赘述.

请求认证

经过以上配置,咱们成功搞好了webhook功能,然而以上代码根本没法使用到生产环境中,由于没有对请求进行认证,若是任何人均可以调用构建服务器地址则后果不堪设想.咱们必须对请求进行认证,而后再决定是否执行相应逻辑.

因为sonaqube不支持设置header,所以咱们没法使用复杂的请求认证.只能使用基本的http认证

咱们在服务端增长如下类

public class BasicAuthenticationAttribute: ActionFilterAttribute
    {
        protected string Username { get; set; } = "sto";
        protected string Password { get; set; } = "sto";

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var req = filterContext.HttpContext.Request;
            var auth = req.Headers["Authorization"].ToString();
            if (!String.IsNullOrEmpty(auth))
            {
                var cred = System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
                var user = new { Name = cred[0], Pass = cred[1] };
                if (user.Name == Username && user.Pass == Password) return;
            }
            filterContext.Result = new UnauthorizedResult();
        }
    }

以上代码中,咱们经过硬编码方式指定了用户名和密码,实际生产环境中咱们能够经过查询数据库来获取用户名和密码. 在OnActionExecuting重写方法中咱们经过头信息Authorization获取加密的Base64字符串,而后经过:分割获取到用户名和密码.而后和真实用户名密码作对比而后决定下一步动做.

咱们把这个filter加到请求方法上.

改造后的代码以下:

[BasicAuthentication]
        public IActionResult HookTest([FromBody]SonarQubeVm sonar)
        {
            return new EmptyResult();
        }

咱们把webhook的url更新为以下:

http://sto:sto1@localhost:49442/home/HookTest

实际上服务端逻辑要求帐户和密码都必须是sto能请求,咱们故意把密码改成sto1看看请求是否能成功.

咱们仍然执行前面的构建代码,只是把版本号增长一下.

咱们再进入webhook管理界面,能够看到请求失败了

avatar

咱们点击失日期后面的四框图标,能够看到失败的状态是401

avatar

咱们把请求地址更改成以下

http://sto:sto@localhost:49442/home/HookTest

这里sto1改成服务器期待的sto,请求就能成功了.