Shippable / support

Shippable SaaS customers can report issues and feature requests in this repository
100 stars 28 forks source link

shippable suddenly fail to build (gulp related) #2663

Closed osumampouw closed 8 years ago

osumampouw commented 8 years ago

Description of your issue:

Here's my project: https://app.shippable.com/projects/552c7ec75ab6cc1352c300d8

Starting from this build https://app.shippable.com/runs/574c3733e77e550d00fadf81 Our build script always failed to build.

This is the last healthy build https://app.shippable.com/runs/574be82c8d819e0d00ab8d97

When we revert the failing build, shippable is still failing to build the reverted commit. We also tried running the build on our local machine and it worked. Then we also tried rebuilding the last healthy build, and that also fail to build. So we decided to clear the build cache and retry again, but that also failed. So from the experiments above, we concluded there's something wrong with shippable build. Can you help investigate?

'use strict';

var async = require('async');
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var less = require('gulp-less');
var util = require('gulp-util');
var minifyCSS = require('gulp-minify-css');
var minify = require('gulp-minifier');
var gulpImage = require('gulp-image');
var livereload = require('gulp-livereload');
var template = require('gulp-template-compile');
var del = require('del');
var imageMin = require('gulp-imagemin');
var jpegRecompress = require('imagemin-jpeg-recompress');
var pngQuant = require('imagemin-pngquant');
var bump = require('gulp-bump');
var git = require('gulp-git');
var webpackStream = require('webpack-stream');
var autoprefixer = require('gulp-autoprefixer');
var spawn = require('child_process').spawn;

require('dotenv').load({path: '.env'});

/*
 * Create variables for our project paths so we can change in one place
 */
var paths = {
  src: ['./models/**/*.js', './routes/**/*.js', 'keystone.js', 'package.json'],
  watch: {
    files: [
      './public/styles/*.less',
      './public/styles/site/**/*.less'
    ]
  },
  less: ['./public/styles/*.less'],
  vendorCss: [
    './public/js/vendor/jquery-ui/jquery-ui.min.css',
    './public/js/vendor/jquery-ui/jquery-ui.pips.css',
    './public/js/plugins/bootstrap/css/bootstrap.min.css',
    './public/js/plugins/font-awesome/css/font-awesome.css'
  ],
  widgetFiles: [
    './public/dist/widget/scripts/',
    './public/dist/widget/styles/',
    './public/dist/widget/*.js'
  ],

  // TODO: Can't move this to dist easily. i have to update all css reference for each plugin
  cssOutput: './public/styles/',
  cssOutputFilePattern: '*.css',
  cssOutputFileName: 'all.min.css',
  vendorCssOutputFileName: 'vendor.min.css',
  images: ['./public/images/**/*'],

  // TODO: the dist/image is not used for now and it is ignore in the .gitignore. We need to update a bunch of css.
  // will do this when we update the css
  imageOutput: './public/dist/images/',
  requireJsConfig: './public/js/config.js',
  mainScript: 'main',
  clientScriptOutput: './public/dist/js/',
  clientScriptOutputFileName: 'main.js',

  // OLX Partnership page gulp
  partnershipOLXPath: './partnershipPage/olx-cnaf',
  partnershipOLXOutput: './public/dist/partnership/olx'
};

// You can use multiple globbing patterns as you would with `gulp.src`
gulp.task('cleanCss', function (cb) {
  del([
    paths.cssOutput + paths.cssOutputFilePattern
  ], cb);
});

// You can use multiple globbing patterns as you would with `gulp.src`
gulp.task('cleanClientScript', function (cb) {
  del([
    paths.clientScriptOutput
  ], cb);
});

gulp.task('cleanImages', function (cb) {
  del([
    paths.imageOutput
  ], cb);
});

gulp.task('less', ['cleanCss'], function () {
  var prefixerPipe = autoprefixer({
    browsers: '> 1%',
    cascade: false
  });

  return gulp.src(paths.less)
    .pipe(less({compress: true}).on('error', util.log))
    .pipe(concat(paths.cssOutputFileName))
    .pipe(prefixerPipe)
    .pipe(minifyCSS())
    .pipe(gulp.dest(paths.cssOutput))
    .pipe(livereload());
});

gulp.task('css', ['less'], function () {
  return gulp.src(paths.vendorCss)
    .pipe(concat(paths.vendorCssOutputFileName))
    .pipe(minifyCSS())
    .pipe(gulp.dest(paths.cssOutput))
    .pipe(livereload());
});

gulp.task('clientScript', [ 'cleanClientScript'], function () {
  return webpackStream(require('./webpack.config'))
  .pipe(gulp.dest(paths.clientScriptOutput));
});

// Copy all static images
gulp.task('images', ['cleanImages'], function () {
  return gulp.src(paths.images)

    // Pass in options to the task
    .pipe(imageMin({
      optimizationLevel: 6,
      progressive: true
    }))
    .pipe(pngQuant({quality: '65-80', speed: 2})())
    .pipe(jpegRecompress({
        quality: 'medium',
        loops: 3,
        min: 50,
        max: 70
      })())
    .pipe(gulpImage({
      pngquant: true,
      optipng: true,
      zopflipng: true,
      advpng: true,
      jpegRecompress: true,
      jpegoptim: true,
      mozjpeg: true,
      gifsicle: true,
      svgo: true
    }))
    .pipe(gulp.dest(paths.imageOutput));
});

gulp.task('cleanWidget', function (cb) {
  del(paths.widgetFiles, cb);
});

gulp.task('widgetTemplates', ['cleanWidget'], function (cb) {
  return gulp.src('./public/widget/src/templates/*.html')
      .pipe(template())
      .pipe(concat('cermati-widget.templates.js'))
      .pipe(uglify())
      .pipe(gulp.dest('./public/dist/widget/'));
});

gulp.task('widgetScript', ['cleanWidget'], function () {
  return gulp.src('./public/widget/src/scripts/*.js')
    .pipe(uglify())
    .pipe(gulp.dest('./public/dist/widget/scripts/'));
});

gulp.task('widgetStyles', ['cleanWidget'], function () {
  return gulp.src('./public/widget/src/styles/widget.style.less')
    .pipe(less({compress: true}).on('error', util.log))
    .pipe(minifyCSS())
    .pipe(gulp.dest('./public/dist/widget/styles/'));
});

gulp.task('widgetImages', ['cleanWidget'], function () {
  return gulp.src('./public/widget/src/styles/*.png')

    // Pass in options to the task
    .pipe(imageMin({
      optimizationLevel: 6,
      progressive: true
    }))
    .pipe(pngQuant({quality: '65-80', speed: 2})())
    .pipe(jpegRecompress({
      quality: 'medium',
      loops: 3,
      min: 50,
      max: 70
    })())
    .pipe(gulpImage({
      pngquant: true,
      optipng: true,
      zopflipng: true,
      advpng: true,
      jpegRecompress: true,
      jpegoptim: true,
      mozjpeg: true,
      gifsicle: true,
      svgo: true
    }))
    .pipe(gulp.dest('./public/dist/widget/styles/'));
});

gulp.task('uglifyWidget', ['widgetScript', 'widgetStyles', 'widgetImages', 'widgetTemplates'], function () {
  return gulp.src('./public/widget/src/*.js')
      .pipe(uglify())
      .pipe(gulp.dest('./public/dist/widget/'));
});

gulp.task('widget', ['uglifyWidget', 'widgetScript', 'widgetStyles', 'widgetImages', 'widgetTemplates'], function () {
  return gulp.src([
    './public/dist/widget/cermati-widget.templates.js',
    './public/dist/widget/cermati-widget.main.js'
    ])
    .pipe(concat('cermati-widget.build.js'))
    .pipe(gulp.dest('./public/dist/widget/'));
});

gulp.task('olx-clean', function (cb) {
  del([
    paths.partnershipOLXOutput
  ], cb);
});

gulp.task('olx-build', ['olx-clean'], function () {
  process.chdir(paths.partnershipOLXPath);
  var tasks = ['build'];
  var child = spawn('gulp', tasks);

  // Print output from Gulpfile
  child.stdout.on('data', function (data) {
    if (data) {
      // Colorize log for fun
      data = data.toString();
      data = data.replace(/^\[(.*)\]/, '');
      data = data.replace(/(.*)\:/, util.colors.styles.green.open + '$1:' + util.colors.styles.green.close);
      data = data.replace(/\'(.*)\'/, util.colors.styles.cyan.open + '\'$1\'' + util.colors.styles.cyan.close);
      data = data.replace(/(\d{0,3}\.?\d{0,3}? s|ms)/, util.colors.styles.yellow.open + '$1' + util.colors.styles.yellow.close);
      util.log(data);
    }
  });

  process.chdir('../../');
});

// Inspired from:
// http://ponyfoo.com/articles/my-first-gulp-adventure

// Bump the patch version of the package.json & bower.json
gulp.task('bump-patch', function () {
  return gulp.src(['./package.json', './bower.json'])
    .pipe(bump({type: 'patch'}))
    .pipe(gulp.dest('./'));
});

gulp.task('bump-minor', function () {
  return gulp.src(['./package.json', './bower.json'])
    .pipe(bump({type: 'minor'}))
    .pipe(gulp.dest('./'));
});

gulp.task('bump-major', function () {
  return gulp.src(['./package.json', './bower.json'])
    .pipe(bump({type: 'major'}))
    .pipe(gulp.dest('./'));
});

// Ensure ci tasks are run inside ci environment
gulp.task('ciSafeguard', function (callback) {
  if (!process.env.SHIPPABLE) {
    return callback(new Error('This task should only be run inside continuous integration (CI)'));
  }
  return callback();
});

// This task should only be run inside ci environment
gulp.task('ciGitPrepare', ['ciSafeguard'], function (callback) {
  var username = process.env.ROBOT_USERNAME;
  var email = process.env.ROBOT_EMAIL;
  var password = process.env.ROBOT_PASSWORD;
  var repoSlug = process.env.REPO_NAME;
  var branch = process.env.BRANCH;
  var gitUrl = 'https://' + username + ':' + password + '@github.com/cermati/' +
    repoSlug + '.git';

  async.series([
    git.checkout.bind(git, branch),
    git.exec.bind(git, {args: 'config --global user.name ' + username}),
    git.exec.bind(git, {args: 'config --global user.email ' + email}),
    git.exec.bind(git, {args: 'remote set-url origin ' + gitUrl})
  ], callback);
});

// This task should only be run inside ci environment
gulp.task('ciRevert', ['ciGitPrepare'], function (callback) {
  git.exec({args: 'log -n 1 --pretty=format:"%ce"'}, function (err, stdout) {
    if (err) {
      return callback(err);
    }

    // Prevent reverting commit by ci
    if (stdout === process.env.ROBOT_EMAIL) {
      return callback();
    }

    git.exec({args: 'revert --no-edit HEAD'}, function (err) {
      if (err) {
        return callback(err);
      }
      git.push('origin', process.env.BRANCH, callback);
    });
  });
});

// This task should only be run inside ci environment
gulp.task('ciTag', ['ciGitPrepare'], function (callback) {
  var pkg = require('./package.json');
  var buildNumber = process.env.BUILD_NUMBER;
  var version = pkg.version + '+build' + buildNumber;
  git.tag(version, 'Auto-generated tag version ' + version, function (err) {
    if (err) {
      return callback(err);
    }
    git.push('origin', process.env.BRANCH, {args: '--tags'}, callback);
  });
});

// ------------------------------------
// Watch tasks
// ------------------------------------
gulp.task('watch-less', function () {
  livereload.listen();
  gulp.watch(paths.watch.files, ['css']);
});

// In the CI we want to run the client script and build css
gulp.task('build', ['clientScript', 'css', 'widget', 'images'], function () {
  if (process.env.SHIPPABLE) {
    // This is needed because keystone.mongoose.disconnect sometimes didn't kill the process
    // so in CI environment, the process can be running forever
    process.exit(0);
  }
});

// Default task for local environment
gulp.task('default', ['build', 'images']);
manishas commented 8 years ago

@a-murphy can you take a look?

a-murphy commented 8 years ago

It looks like this was occurring at the same time that we were having a problem caching (https://github.com/Shippable/support/issues/2664), and your builds started failing when the cache wasn't available. The last successful build was the last one to use the cache. It's quite likely that npm install installed a different version of something without the cache.

abhijitkini commented 8 years ago

@osumampouw With the "problem caching" issue resolved, you should have healthy builds now. Do let us know if it is otherwise.