Freitag, 5. Oktober 2018

Use Gulp to release a Javascript project to git the Maven way

What I like about the way Maven makes a release is, the version number in git is for development always extended with SNAPSHOT. This keeps you from using a development build for productive use. If you are using CI/CD you might not need this. But in other cases a solution like this can help, specially when using a CI tool like Jenkins, this is a step towards automating a release.

First of all, I wanted to have the following steps performed by this gulp task:
  1. bump the version in package.json to the next one (1.3.21)
  2. commit this change
  3. tag the change with this version (1.3.21)
  4. bump the version in package.json to the next pre-release (1.3.22-0)
  5. commit this change
  6. push all commits to git


          Next thing I wanted to solve: when testing this feature, I did not want to have all the test commits in the git repo. So want to add a different repository to my project, you know, git is a distributed version control system, so it supports multiple repositories.

          So I created another repo in a folder right next to my project, initialized that folder as a bare git repo, added it to my project and used a different push mechanism to add my commits. Btw. VSCode has menu support for this, use "push to".
          mkdir bare-repo cd bare-repo git --bare init cd .. git clone http://my-remote-repo cd my-work-folder git remote add reltest ../bare-repo/ git remote git push reltest master

          Now I can make changes, commit and push them without messing up my origin repository with all those test commits.


          Next, make gulp do it's magic. I want to use semantic versioning, so I'm basically fine with options for major, minor and patch. But I want pre-release versions also being built by this task. And maybe one day I would also like to directly set the version.

          var gulp = require('gulp'); /** * bump the version in package.json to the next value */ var bump = function (options) { var gulpBump = require('gulp-bump'); if (!options) options = {type:"prerelease"}; return gulp.src(['./package.json']) .pipe(gulpBump(options)) .pipe(gulp.dest('./')); } /** * do the release */ gulp.task('release-do', function (done) { // --bump.version=1.2.3 : bumps 1.2.3 // --bump.type=major : bumps 1.0.0 // --bump.type=minor : bumps 0.1.0 // --bump.type=patch : bumps 0.0.2 // --bump.type=prerelease : bumps 0.0.1-2 (default) const git = require('gulp-git'); const tagVersion = require('gulp-tag-version'); const argv = require('yargs').argv; var options; if (argv.bump) { options = {};
          if (argv.bump.version) {
          options.version = argv.bump.version;
          } else if (argv.bump.type) {
          options.type = argv.bump.type;
          }
          } return bump(options) // set release version .pipe(git.add()) // add to staging area .pipe(gulp.dest('./')) // write .pipe(git.commit('gulp release')) // commit release version .pipe(tagVersion()); // tag }); /** * prepare for next prerelease */ gulp.task('release-next', function (done) { const git = require('gulp-git'); return bump({type:"prerelease"}) .pipe(git.add())
          .pipe(gulp.dest('./'))
          .pipe(git.commit('gulp release'))
          }); /** * push all changes to git */ gulp.task('release-push', function (done) { // --repository=origin // --branch=master const git = require('gulp-git'); const argv = require('yargs').argv; var repository = argv.repository ? argv.repository : 'origin'; var branch = argv.branch ? argv.branch : 'master'; return git.push(repository, branch, done); }); gulp.task('release', gulp.series('release-do', 'release-next', 'release-push'));



          Now by simply typing
          gulp release
          I get a new pre-release in git.

          If I want to do a major, minor ot patch release
          gulp release --bump.type=minor
          will do.

          Directly setting a version:
          gulp release --bump.version=1.3.21

          There is also support for the repository and the branch (refspec):
          gulp release --bump.type=patch --repository=origin --branch=master

          Freitag, 13. Juli 2018

          Building a library from javascrpt and typescript with gulp using require

          When building typescript with tsc you usually end up in a folder structure representing the structure of the source files. If all of the code needs to go in one library, the folder structure will be lost and this must be reflected in the require dependencies. I have a lot of older javascript code that I want to combine with new typescript code into one library.

          I ended up with a solution, that allows me to build the code with tsc for review only into a file structure and gulp packing everything together in a single lib.

          The tsconfig.json: nothing special except for that I needed to set the moduleResolution to "Node" so tsc finds the type definitions that I installed by npm.
          {
          "compilerOptions": {
          "target": "es5",
          "module": "AMD",
          "outDir":"./src/built",
          "sourceMap": true,
          "moduleResolution": "Node",
          "typeRoots":[
          "node_modules/@types"
          ]
          },
          "include": [
          "src/**/*"
          ],
          "exclude": [
          "node_modules"
          ]
          }


          One thing getting used to is, that tsc creates all typescript code with relative dependencies from the file that starts the whole dependency tree, usually the file index.ts. So wherever this file is, all files that are imported there have relative dependecies to that file. So putting it into a folder one or more levels higher than the other files creates a nice naming structure.

          In the gulpfile.js this will create the source from the typescript code
          var buildTs = function () {
          const ts = require("gulp-typescript");
          const tsProject = ts.createProject('tsconfig.json', { outFile: "uiTs.js" } );

          return gulp
          .src('src/**/*.ts')
          .pipe(tsProject());
          }

          Another thing special: I do not use  tsProject.src()  because actually I build more than one library and set the folder by using  gulp.src()   instead.

          The final task
          gulp.task('build', function () {
          return merge(
          gulp.src(srcUi),
          buildTs(),
          getTemplates()
          )

          // common preparation
          .pipe(concat('mylib.js'))
          .pipe(injectVersion())
          .pipe(banner(comment, { pkg: pkg }))
          // source file
          .pipe(gulp.dest(pkg.config.paths.dist))
          // source maps
          .pipe(sourcemaps.init())
          .pipe(sourcemaps.identityMap())
          .pipe(uglify(uglifyOptions))
          .pipe(rename('mylib.min.js'))
          .pipe(sourcemaps.write('./'))
          .pipe(gulp.dest(pkg.config.paths.dist))
          });


          Whenever I want to check the code created I do "tsc", whenever I build the full thing I go "gulp build".