仅当 src 发生更改时才运行构建

Posted

技术标签:

【中文标题】仅当 src 发生更改时才运行构建【英文标题】:Run build only if there are changes in src 【发布时间】:2015-07-02 18:30:45 【问题描述】:

故事:

我们有一个测试人员团队致力于使用量角器为我们的内部 AngularJS 应用程序自动化端到端测试。以下是他们通常为“本地”测试运行的任务:

grunt.registerTask('e2e:local', [
    'build:prod',
    'connect:test',
    'protractor:local'
]);

它运行“构建”任务,启动网络服务器并针对本地构建运行 e2e 测试。

build:prod 任务本身定义为:

grunt.registerTask(
    'build:prod', [
        'clean',
        'copy:all',
        'copy:assets',
        'wiredep',
        'ngtemplates',
        'useminPrepare',
        'concat',
        'ngAnnotate',
        'autoprefixer',
        'uglify',
        'cssmin',
        'copy:cssfix',
        'usemin',
        'copy:html',
        'bowercopy',
        'template:setProdVersion'
    ]
);

这里我们有很多子任务(肯定可以改进,但现在看起来是这样)。

问题:

目前,构建完成大约需要 25 秒。而且,每次有人运行端到端测试时,都会执行构建任务。

问题:

如果src 目录发生变化,如何才能运行build:prod 任务?


请注意,这里的要求是使其对运行测试的测试人员透明。我不希望他们记住什么时候需要执行构建,什么时候不需要。

换句话说,这个过程应该是自动化的。目标是自动检测是否需要构建。

请注意,理想情况下,我希望将构建任务保持原样,这样如果通过grunt build:prod 直接调用它,它将重新构建,而不管先前构建的日期戳。


想法和尝试:

有密切相关的grunt-newer package,但是,由于我们有一个相当复杂的构建,一开始有一个clean 任务,我不确定如何在我的情况下应用它

我还在考虑的是,在e2e:local 任务中,手动检查distsrc 中文件的时间戳,并据此决定是否需要build:prod被调用。我认为这就是grunt-newer 在内部所做的事情

我们开始使用有助于提高性能的jit-grunt

【问题讨论】:

grunt-newer 的手册页 (grunt-tasks.com/grunt-newer) 似乎支持您的第二个项目符号,创建一个检查 src 文件日期的任务并在它们发生更改时触发(不知道你为什么检查dist,这不是构建的结果吗?) @KevinDTimm 是的,grunt-newer 的想法非常接近我的问题。第二个要点/想法是关于比较dist 中的时间戳,这是构建的结果,以及src 中的时间戳。如果src 中的文件较新,则运行构建。可能这不是我应该做的,更好地比较当前和以前运行之间的src 文件戳..谢谢。 我的建议是在 ~/.cshrc 中设置一个别名,以便仅在 diff 命令返回 true 时运行构建命令。 为什么clean 任务在构建的最开始?? @Louis 这是我们继承的某种“遗留”构建任务。 "clean" 清理 build 和 dist 目录。谢谢。 【参考方案1】:

如果你使用 git,这里有一个想法:

使用类似grunt-gitinfo 并使用 HEAD 中的最后一次提交作为基础怎么样?

想法是:

您创建了一个新的 grunt 任务来检查最新的提交哈希 您应该将此提交哈希保存在添加到 gitignore 的文件中(并且不在 clean 文件夹中,通常可以在 repo 的根目录中) 在保存到文件之前,它会检查其中已经存在的值(标准节点fs 模块可以轻松进行读/写) 如果哈希不匹配,运行build:prod 任务然后保存新的提交哈希 测试人员的构建将取决于您的新任务,而不是直接依赖build:prod

另一种选择(仍在使用 git):

您可以使用grunt-githooks 之类的东西并创建一个在 pull 之后运行的 git 挂钩并调用 git build:prod,然后您可以将其从测试人员运行的 grunt 任务的依赖项中删除。

你可能有另一个代码来检查 gitook 并在需要时安装它,这对于测试人员来说可能是一次性的额外步骤,或者可能会融入他们调用的 grunt 任务中。

【讨论】:

总的来说,这是一个非常有趣的想法!良好的开箱即用思维。感谢帮助。谢谢!【参考方案2】:

我很惊讶还没有人提到grunt-contrib-watch(它在gruntjs.com 示例文件中,我认为它是众所周知的!)。来自 github:“只要添加、更改或删除监视的文件模式,就运行预定义任务。” - 这是一个示例 grunt 文件,只要在 src/ 或 test/ 中修改任何 .js 文件,或者如果修改了 Gruntfile,它将运行您的任务。

var filesToWatch = ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'];
grunt.initConfig(
    watch: 
        files: filesToWatch,
        tasks: ['build:prod',
                'connect:test',
                'protractor:local']
    
);
grunt.loadNpmTasks('grunt-contrib-watch');

您让您的开发人员在开始修改文件之前打开终端并运行grunt watch,每次修改这些文件时,任务将自动运行(不再每次都返回终端运行grunt build:prod) .

这是一个很棒的包,我建议你去看看。 -- github -- npmjs.org

npm install grunt-contrib-watch --save-dev

【讨论】:

"我不想让他们记住什么时候需要执行构建,什么时候不需要。换句话说,这个过程应该是自动化的。目标是自动检测是否需要构建。” - 这不仅检测何时需要构建(通过查看src/ 中的文件),而且在检测到需要构建时自动编译构建。这既可以自动化流程,也无需他们知道何时构建,并在需要构建时进行构建。 是的,“手表”可能是最简单的选择。它仍然需要测试人员记住运行任务并使其处于活动状态,但这绝对有助于使其透明。现在我们可以从 e2e 任务中删除构建任务调用。非常感谢!【参考方案3】:

grunt 不是您要寻找的答案,但使用 gulp 会很容易。

var fs = require('fs');
var gulpif = require('gulp-if');

var sourceChanged = fs.statSync('build/directory').mtime > fs.statSync('source/directory').mtime;

gulp.task('build:prod', function() 
  if (!sourceChanged) 
    return false;
   
  return gulp.src('./src/*.js')
    .pipe(.... build ....)
    .pipe(gulp.dest('./dist/'));
);

【讨论】:

【参考方案4】:

以下是我们为构建完成一些 Git HEAD sha 工作的方式。我们使用它来确定当前将哪个版本部署到我们的生产环境中 - 但我很确定您可以重新处理它以返回布尔值并在真实情况下触发构建。

Gruntfile.js

function getHeadSha() 
  var curr, match, next = 'HEAD';
  var repoDir = process.env.GIT_REPO_DIR || path.join(__dirname, '..');
  try 
    do 
      curr  = grunt.file.read(path.join(repoDir, '.git', next)).trim();
      match = curr.match(/^ref: (.+)$/);
      next  = match && match[1];
     while (next);
   catch(ex) 
    curr = 'not-found';
  

  return curr;


grunt.initConfig(
  replace: 
    applicationVersion: 
      src:  '<%= config.dist %>/index.html',
      overwrite: true,
      replacements: [
        from: 'APPLICATION_VERSION',
        to:   getHeadSha
      ]
    
  
);

grunt.registerTask('build', 
  'replace:applicationVersion',
  /** other tasks **/
);

grunt.registerTask('e2e:local', 
  'check_if_we_should_build',
  /** other tasks **/
);

index.html

<html data-version="APPLICATION_VERSION">
  <!-- -->
</html>

还有git-info 包可以简化整个过程,我们正在考虑自己切换到那个。

edit; 我刚刚注意到@meligy 已经为您指出了 git-info 的方向。信用到期。

【讨论】:

【参考方案5】:

我不确定它是否有用,但我们在项目中使用 GULP framework 所做的事情相同。我们在 gulp 中编写了一个监视程序,它不断检查源代码更改并运行一个快速函数来构建项目。它是一个量角器测试用例。

gulp.task('dome', function () 


    gulp.src(["maintest.js"])
        .pipe(notify("Change Found , Executing Scripts."))
        .pipe(protractor(

            configFile: "conf.js",
            args: ['--baseUrl', 'http://127.0.0.1:8000']


        )).on('error', function (e) 
        throw e
    );
)


gulp.task('default', function () 


    gulp.watch('./webpages/*.js', ['dome']);
    gulp.watch('maintest.js', ['dome']);
    gulp.watch('conf.js', ['dome']);
);

Link to repo.

【讨论】:

【参考方案6】:

我没有量角器方面的经验,但从概念上讲,我认为这可行。

我的建议是在您的 ~/.cshrc 中设置一个别名,以便仅在 diff 命令返回 true 时运行构建命令。

#./cshrc

alias build_on_diff 'diff -r branch_dir_1 branch_dir_2\
if ( $status == 1 ) then\
build:prod\
endif'

只需用 git 使用的任何命令替换 diff 命令,它应该可以工作,只要它返回 1 状态以检测到差异。我们在我的工作场所采用了类似的方法来避免重建未更改的文件。

【讨论】:

以上是关于仅当 src 发生更改时才运行构建的主要内容,如果未能解决你的问题,请参考以下文章

仅当两个依赖项都更改时才运行效果挂钩

仅当页面的某个部分发生更改时才运行角度编译

仅当 pr 目标为 master 时才运行 GitHub 操作

仅当宽度和高度都更改时才更改图像大小

仅当从下拉列表中选择选项时才附加到 iframe src

仅当子目录中的文件已更改时,才运行VSTS构建任务以运行“npm build”