[开源]TFS与微信企业号的通知整合

直接上地址:

https://github.com/lishewen/TFSWebHook

使用方法:

1、修改web.config中的CorpId/Secret/AgentId,为你自己企业号中申请到的key

2、把站点发布到IIS

3、在TFS 服务挂钩 设置中,选择 Web挂钩 ,并填入URL

http://<host>/api/webhooks/incoming/vsts?code=D854DE27C4ED4A10BFC6BE6E21C3A5A1

如果修改了web.config中对应的code这里也要换成自己的

4、我这里只写了签入代码和git push的事件通知,如果需要其他通知 如工作项变更通知,可自行到Webhooks/VstsWebHookHandler.cs 中添加即可

效果图:

让TFS忽略packages文件夹的更改

很多时候我们需要使用 Nuget 进行包管理,这时在我们的解决方案文件夹下便会产生一个名为 package 的文件夹

由于 Nuget 包经常要更新,TFS 会自动把这些包放到 正在挂起的更改 处,这对于强迫症十分不友好(这里面明明不是我写的东西Baring teeth smile

于是,这里提供两种方法让 VS 不监视 签入,package 的更新

1、在 团队资源管理器 –> 正在挂起更改 –> 包含的更改 –> 视图选项 –> 勾上 显示解决方案的更改

2、在解决方案的文件夹下,新建一个文本文件,名为 .tfignore

内容为

\packages

如果需要更复杂的配置,可以参考以下信息修改:

################################################################################
#
# 此文件中与 filespecs 匹配的本地项将不会添加到版本
# 控制中。可签入此文件以便与其他人共享排除内容。
#
# 通配符为 * 和 ?。模式以递归方式匹配,除非
# 该模式使用了 \ 字符作为前缀。
#
# 你可以在模式前面放置路径以使其更加明确。如果添加路径,
# 则在路径部分不允许使用通配符。
#
# 行首的 # 字符指示该行是一条注释。
#
# ! 前缀将使模式无效。在某个项由树中更高级别
# 的 .tfignore 文件或团队项目集合的全局排除列表排除之后,
# 可以使用此前缀来重新包括该项。
#
# / 字符在 Windows 平台上被解释为 \ 字符。
#
# 示例:
#
#  # 排除 Alpha\Beta 及其所有子文件夹中以 .txt 结尾的所有文件。
#  Alpha\Beta\*.txt
#
#  # 仅排除此文件夹中以 .cpp 结尾的所有文件。
#  \*.cpp
#
#  # 排除此文件夹及其所有子文件夹中以 .cpp 结尾的所有文件。
#  *.cpp
#
#  # 如果“Contoso”是文件夹,则排除 Contoso 及其所有子项。
#  # 如果它是文件,则仅排除此文件夹中的“Contoso”。
#  \Contoso
#
#  # 如果 Help.exe 已由更高级别的 .tfignore 文件或团队项目
#  # 集合的全局排除列表排除,则此模式仅在此文件夹
#  # 中重新包括它。
#  !\Help.exe     #
################################################################################

使用TFS2015生成并测试ASP.Net Core项目

在TFS上配置ASP.Net Core所需的DNX环境

这里通过PowerShell实现,在解决方案中增加一个PowerShell脚本,这里名为 Prebuild.ps1

# bootstrap DNVM into this session.
&{$Branch='dev';iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.ps1'))}

# load up the global.json so we can find the DNX version
$globalJson = Get-Content -Path $PSScriptRoot\global.json -Raw -ErrorAction Ignore | ConvertFrom-Json -ErrorAction Ignore

if($globalJson)
{
    $dnxVersion = $globalJson.sdk.version
}
else
{
    Write-Warning "Unable to locate global.json to determine using 'latest'"
    $dnxVersion = "latest"
}

# install DNX
# only installs the default (x86, clr) runtime of the framework.
# If you need additional architectures or runtimes you should add additional calls
# ex: & $env:USERPROFILE\.dnx\bin\dnvm install $dnxVersion -r coreclr
& $env:USERPROFILE\.dnx\bin\dnvm install $dnxVersion -Persistent

 # run DNU restore on all project.json files in the src folder including 2>1 to redirect stderr to stdout for badly behaved tools
Get-ChildItem -Path $PSScriptRoot\分销系统 -Filter project.json -Recurse | ForEach-Object { & dnu restore $_.FullName 2>1 }
Get-ChildItem -Path $PSScriptRoot\MVC6.UnitTest -Filter project.json -Recurse | ForEach-Object { & dnu restore $_.FullName 2>1 }

其中 分销系统 和 MVC6.UnitTest 为我测试的项目,即project.json所在的位置,请自行修改为自己对应的项目

然后登录TFS修改生成定义,添加一个PowerShell的生成步骤,把脚本文件指向 Prebuild.ps1

如果你在TFS上找不到这个文件,请先把这个文件签入TFS

添加XUnit项目

如果你的VS中有XUnit的模板,直接添加就可以了。如果没有,可以先创建一个ASP.Net Core Class Library的项目,然后参照下面的 project.json 内容,来添加xunit package的引用

{
	"version": "1.0.0-*",
	"description": "MVC6.UnitTest Class Library",
	"authors": [ "lishewen" ],
	"tags": [ "" ],
	"projectUrl": "",
	"licenseUrl": "",
	"frameworks": {
		"dnx451": {
			"dependencies": {
				"xunit.runner.visualstudio": "2.1.0"
			}
		},
		"dnxcore50": {
			"dependencies": {
				"Microsoft.CSharp": "4.0.1-beta-23516",
				"System.Collections": "4.0.11-beta-23516",
				"System.Linq": "4.0.1-beta-23516",
				"System.Runtime": "4.0.21-beta-23516",
				"System.Threading": "4.0.11-beta-23516"
			}
		}
	},
	"dependencies": {
		"xunit": "2.1.0-*",
		"xunit.runner.dnx": "2.1.0-*"
	},
	"commands": {
		"test": "xunit.runner.dnx"
	}
}

在单元测试中添加一个简单的测试方法

		[Fact]
		public void PassingTestDnx()
		{
			Assert.Equal(1, 1);
		}

写一个运行xunit单元测试的PowerShell脚本,RunDnxTest.ps1

Set-ExecutionPolicy unrestricted -Scope CurrentUser -Force
dnx -p $PSScriptRoot\MVC6.UnitTest test -xml $PSScriptRoot\MVC6.UnitTest\testresults.xml

最后参照 Prebuild.ps1的步骤,在生成定义中,再加一项PowerShell的生成步骤,并指向脚本 RunDnxTest.ps1

此步骤完成后,我们还需要添加一项 发布测试结果 的步骤,已便将XUint的结果与原来Visual Studio 的单元测试结果合并

具体参照下图配置:

至此,ASP.Net Core的自动生成和测试的配置就完成了,我们可以运行下生成定义来看看测试结果

不懂技术的人不要对懂技术的人说这很容易实现

英文原文:I'm Sure It Will Only Take You A Few Days To Code

“这个网站相当简单,所有你需要做的就是完成X,Y,Z。你看起来应该是技术很好,所以,我相信,你不需要花费太多时间就能把它搭建起来。”

我时不时的就会收到这样的 Email。写这些邮件的人几乎都是跟技术不沾边的人,或正在研究他们的第一个产品。起初,当听到人们这样的话,我总是十分的恼怒。他们在跟谁辩论软件开发所需要的时间?但后来我意识到,即使我自己自己的项目预测要花去多少开发时间,我也是一筹莫展。如果连我自己都做不好,我何必对那些人恼怒呢?

真正让我郁闷的不是他们预估的错误。问题在于他们竟然认为自己可以做出正确的估计。作为开发人员,我们经常会发现,在软件开发的问题上,一个外行人会很自然的把复杂的事情估计的很简单。

这并不是为我们的愤怒找借口。但这引起了另外一个有趣的问题:为什么我们天生的预测复杂性的能力在遇到编程问题时会失灵?

为了回答这个问题,让我们来认识一下我们的大脑如何估计事情的。有些事情对于一些没有经验的人也很容易预估正确,但有些事情则不然。

我们来想想观看一个人弹吉他。即使你从来没有弹过吉他,在观看了一场弹奏《玛丽有只小羊羔(Mary had a Little Lamb)》的吉他表演后,你也能大概推测出这很简单,一个人不需要太高的技术就能演奏出来。同样,当观看了有人演奏D大调的《卡农(Pachabel’s Canon)》后,你也很容易推测出,这很复杂,需要很长时间的练习才能演奏的出来。

为什么我们能够很迅速准确的预估这两首曲子的复杂性呢?这是跟我们用来判断一个事情简单和还是复杂的方法有关的。我们的大脑有一些现成的模式来完成这些事情,首先一个就是根据速度。这种情况下,大脑会辨别每秒钟演奏的东西。根据每秒钟演奏了多少东西,我们很容易有一个直观的判断曲子的复杂度。因为用吉他演奏一首歌是一种物理过程,一种感官上的活动,我们的大脑很容易依此来推测速度,继而转换成复杂度。

我们还有另外一个天生的推测依据:体积。想想把一个帐篷和一栋公寓放在一起对比。即使一个人从来没有学过建筑学,他也能告诉你通常设计和建造一个帐篷会比设计和建造一栋公寓要简单。为什么?因为我们天生的会使用物理体积作为事物复杂性的一个指标。

当然。上面说的这两种逻辑分析并不是总是 100% 的有效。但大多数情况下,人们就是这样干,而且很成功。大多数情况中,我们在对物理过程评估时,我们的大脑会对物理事物进行有效的关联,不需要依赖之前的经验。

现在让我们来谈谈软件。当一个不懂技术的人试图对软件开发时间进行评估时,有两个很基本的直观指标在辅助他们:以体积为指标的复杂度和以速度为指标的复杂度。但他们没有意识到,软件跟他们想象的不一样。软件本质上不是有形物质。没有体积和速度。它的极小的组成部分可能会时不时的在电脑屏幕上闪现。正因为如此,当面对开发一个 web 应用时(或任何类型的软件),我们的基本直观感觉失效了。

这第一点,速度,很显然根本不可能被外行人拿来对软件进行评估。于是很自然的,他们倾向于使用体积指标进行评估。要么是根据描述文档的页数,要么是根据软件的功能用例数或特征数。

有时候,这种评估手段确实有效!当面对一个静态网站,没有特别的设计要求,外行人很容易用这种方法估计出开发时间。但是,通常情况下,对于软件开发,体积并不能真实有效的反映复杂度。

不幸的是,对于软件的复杂度,唯一有效的推测方法是依据经验。而且还不是时时都好用。作为一个程序员,我知道,根据我之前开发过的相似的功能特征,我可以估计出现在的这些功能特征各自要多少开发时间。然后,我把总时间加起来,这就得到了完成整个项目需要的大致时间。然而,事实情况中,每个项目在开发过程中都遇到二、三个瓶颈。这些瓶颈会肆意的消耗程序员的大量时间,你在遇到它们之前根本不会有所预见。它们会拖住整个项目,致使工期延后数周甚至数月。

这些是没有经验的人在评估复杂度时不会理解的。他们不明白在其他事情上都很灵的方法,为什么放到软件开发上就不灵了。所以,下一次当你听到有人说“我想你几天时间就能把它开发出来”时,不管是谁说的,都不要懊恼。深呼吸一下,告诉他这篇文章的地址,自己该干什么还干什么。