TypeScript Error TS2304: Cannot find name ‘require’的解决方法

最近在研究ionic framework,在编译项目的时候出现一个报错:

TS2304: Cannot find name 'require'

原因是我们使用了ECharts,在引用它的使用写了这样的一句代码:

// 引入 ECharts 主模块
var echarts = require('echarts/lib/echarts');

require是在ES5的语法里常用的方式,现在我们写typescript了,没有这个玩意儿怎么办?
我找了很久,在github上找到了一个项目:
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/requirejs/require.d.ts
把项目里的require.d.ts放到ionic的app目录下就解决了这个报错。

TypeScript Error TS2304: Cannot find name ‘Set’、’Promise’、’Map’.解决方法

最近在研究ionic framework,希望使用hybrid app开发我们团队的新版app报表模块。

在使用命令:

ionic serve

启动应用的时候,发现www/build目录下没有app.bundle.js这个文件,这个文件是typescript编译之后生成的一个js文件。看了命令行启动日志,发现有大量的typescript编译报错,以下就展示部分典型报错信息:

TypeScript error: /Users/wangzhiang/IdeaProjects/crm-ionic/node_modules/@angular/common/src/directives/ng_class.d.ts(81,35): Error TS2304: Cannot find name 'Set'.
TypeScript error: /Users/wangzhiang/IdeaProjects/crm-ionic/node_modules/@angular/common/src/facade/async.d.ts(34,33): Error TS2304: Cannot find name 'Promise'.
TypeScript error: /Users/wangzhiang/IdeaProjects/crm-ionic/node_modules/@angular/common/src/facade/lang.d.ts(11,17): Error TS2304: Cannot find name 'Map'.

经过stackoverflow和github的指点,我找到的解决方法如下:
先安装angular2依赖,–save-dev目的是把angular2依赖写入到package.json里:

npm install angular2 --save-dev

然后在项目的app目录下找到app.ts文件,在文件顶部加上:

///<reference path="../node_modules/angular2/typings/browser.d.ts"/>

这样之后就解决了typescript报错的问题。

Nginx报错open failed 13: Permission denied while reading upstream的解决方法

今天我们的系统出现了一个很诡异的情况,一个页面里有几个js文件和图片无法读到,Chrome浏览器里的status是:net::ERR_CONTENT_LENGTH_MISMATCH。而同一个页面其他的js、css和图片都没有问题,status是200。

遇到这个问题我第一反应是这个系统的tomcat我们也没有人动过,这几个资源文件在服务上是用的,那就是看看Nginx有没有问题,刚好今天有人动过Nginx,那就就去看看Nginx的access.log和error.log的日志。发现error.log里面有一个报错:

2016/06/05 17:58:06 [crit] 1017#0: *182 open() “/usr/local/nginx/proxy_temp/4/02/0000000024” failed (13: Permission denied) while reading upstream, client: ***.***.***.***, server: *****, request: “GET /idp/resources/images/mitreid-connect.ico HTTP/1.1”, upstream: “https://*****:8444/idp/resources/images/mitreid-connect.ico”, host: “*****”, referrer: “******”

proxy_temp目录是干什么的?我们的Nginx有个配置proxy_temp_file_write_size,当文件超过该参数设置的大小时,Nginx会先将文件写入临时目录,默认为Nginx安装目下/proxy_temp目录。

默认情况下,nginx是以nobody启动的,用ll命令查看proxy_temp目录,我们发现用户和用户组是nobody和root,难怪Permission denied!

我们用

chown -R nobody:nobody proxy_temp

把proxy_temp目录改成nobody的用户组权限,重启Nginx后问题就解决了!

利用gitlab的web hook和钉钉做代码review工作

     还记得在我读大学的时候有一门课叫做计算机安全,我们的教材《信息安全原理与应用(第四版)》中提到代码检查工作每千行代码发现的错误数量是10个,而其他的程序系统检查方法:需求复查为2.5个/1000行、设计复查为5个/1000行、集成测试为3个/1000行,接受测试为2个/1000行。
     那时候看完这个研究结果之后,代码检查的观念就根深蒂固地植入我的脑海里。工作了这么多年,一直不忘记代码review。团队也制定了很多的代码review工作的要求,但总是因为各种各样的原因做不好。最大的问题就是业务工作太忙,没有时间review。
     还记得上高三的时候,准备高考可谓是争分夺秒,我们都随身携带小笔记本,把重要的知识点记录在里面,蹲厕所、排队吃饭的时候掏出来复习,将细碎的时候利用起来也是一笔不小的财富。那我们就可以利用零碎的时间来做代码review工作,将bug扼杀在摇篮之中!
     webhook功能的作用是当开发者向git服务器push代码完成时,git会触发webhook里配置的url,即向我们配置的url用post的方式发送一个json格式的内容,这个内容里包含本次push的所有信息。众所周知,github和oschina这些代码管理的平台的项目设置里都提供webhook功能,我们公司使用的是gitlab来管理我们的代码,gitlab也拥有webhook功能。webhook功能给了我们无限的想象空间,可以用来自动部署代码,可以自动集成测试,当然,还有本文的主题,review提交的代码。
     我在公司里独自一人维护了一个叫做superb的thinkphp项目,这个系统提供项目管理、日报周报、接口文档、运维信息等功能,我觉得这个功能做到superb里是最合适不过了!
实现步骤:
第一步:根据gitlab的文档中描述的web hook post的json格式编写一个接受post内容的http接口。
第二步:接口处理完post的内容之后发送钉钉消息给指定人员。
具体实现:

1.接口代码(thinkphp框架):

<?php
namespace Home\Controller;

use Think\Controller;
use Think\Log;

class GitController extends Controller
{
    public function index()
    {
        $requestBody = file_get_contents('php://input');
        if (empty($requestBody)) {
            echo '发送失败';
            return false;
        }
        $content = json_decode($requestBody, true);

        $message = "";
        if ($content['total_commits_count'] > 0) {
            $message .= $content['user_name'] . '向' . $content['repository']['name'] . '项目的' . $content['ref'] . '分支push了' . $content['total_commits_count'] . '个commit:' . "\n";
            $count = 0;
            foreach ($content['commits'] as $commit) {
                $count++;
                $message .= $count . '. ' . $commit['author']['name'] . '在' . date('Y年m月d日 h:i:s', strtotime($commit['timestamp'])) . ' 提交的:' . $commit['message'] . "\n";
                $message .= '点击 ' . $commit['url'] . ' 查看本次commit diff' . "\n";
            }
            echo $message;
            Log::write($message);
        } else {
            $message .= $content['user_name'] . '在' . $content['repository']['name'] . '项目创建或者删除了一个分支:' . $content['ref'] . "\n";
        }
        echo D('Dingding', 'Service')->sendTextMsg('@all', $message);
    }
}
2.发送钉钉的代码:
<?php
namespace Home\Service;

use \Think\Model;
use \Think\Log;

class DingdingService extends Model
{
    private $_url = 'https://oapi.dingtalk.com/gettoken?corpid=你的&corpsecret=你的';

    public function sendTextMsg($touser, $text, $agentid = 你的)
    {
        $accessToken = $this->_getAccessToken();
        if ($accessToken == null) {
            return '获取accessToken失败';
        }
        $content = array(
            'touser' => $touser,
            'agentid' => $agentid,
            'msgtype' => 'text',
            'text' => array('content' => $text)
        );
        $url = 'https://oapi.dingtalk.com/message/send?access_token=' . $accessToken;
        $result = $this->_sendPost($url, $content);
        Log::write($result);
        return $result;
    }

    private function _getAccessToken()
    {
        $content = $this->_sendGet($this->_url);
        $json = json_decode($content, true);
        if ($json['errcode'] == 0) {
            $accessToken = $json['access_token'];
            return $accessToken;
        } else {
            Log::write('获取accessToken失败');
            return null;
        }
    }

    private function _sendPost($url, $data)
    {
        $ch = curl_init($url);
        $payload = json_encode($data);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

    private function _sendGet($url)
    {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }
}
完成之后,把接口的url配置到gitlab的web hook上就可以坐等你的push消息了。结果是这样的:
HMHAWQ5%}[I]L(${HK6LNI2
点击最下方的diff url就可以打开gitlab的代码diff页面进行代码review工作。
其实这是个非常简单的功能,但是它给我带来的是完全不同的体验:
  1. 团队成员在push代码之后我第一时间收到钉钉的通知,我可以打开diff页面,立刻查看或者等会儿有时间了再看这个网页,我完全可以利用编译代码的零碎时间来做这项工作。记得这个功能上线第一天我就快速review出两个组员的代码bug,他们都万万没想到。
  2. 让团队中的初级程序员养成提交代码的时候自己先diff的习惯,并且写好comment。以前初级程序员常常乱提交代码,对代码分支造成严重的破坏,现在我告诉他们,只要他们提交代码boss就会看到,他们都非常小心谨慎了。
  3. 和其他团队的协作开发变得更加透明,其他团队的同学提交什么代码,功能说明我就可以看到。一起联调代码,他提交后我第一时间知道他接口搞定了;要求对方修改的bug对方提交了代码我就知道代码修复了。这两个体验不是我随口说的,现实中我真的遇到,感觉很爽!
这个功能的未来:
我希望将来在superb里面增加一个订阅功能,所有开发人员可以订阅自己关注的项目,订阅自己关心的人,这样对团队的代码管理将带来非常大的帮助。

Git在实际开发中创建分支与分支合并到master的经验

我们公司一直都使用Git作为我们的代码版本控制工具,我们总结的一些创建分支的经验:
  1. 开发新功能必须在master的基础上拉一个新的dev分支,分支的命名规则:[团队]-dev-[日期yymmdd格式]-[开发者英文名]-[分支的功能]。
  2. 修复bug必须在master的基础上拉一个新的bugfix分支,分支的命名规则:[团队]-bugfix-[日期yymmdd格式]-[开发者英文名]-[分支的功能]。
  3. 测试每天必须在master的基础上拉一个新的test分支,然后合并需要测试的各个分支,分支的命名规则:[团队]-test-[日期yymmdd格式]-[测试人员英文名]。
我们总结开发分支合并到master的经验:
  1. master必须由少数几个人控制,由团队的leader和重要的开发负责人操作。
  2. 上线合并之前,如果当前的master分支没有tag,需要在当前的master上打tag,为了让我们找到合并前的commit,万一有回滚可以用上这个分支Hash值。
  3. 合并的过程中如果遇到conflict的情况,必须要两个代码的负责人现场确认,合并完成之后必须要回归测试相关的功能。
  4. 如果遭遇需要回滚的情况,请按照《Git分支代码回滚流程》操作。
  5. 上线完成之后在当前的master上打上tag。
做到以上几点,团队在开发的时候就可以做到有条不紊。
↓

CSS3 Powered