dotnet / Nerdbank.GitVersioning

Stamp your assemblies, packages and more with a unique version generated from a single, simple version.json file and include git commit IDs for non-official builds.
https://www.nuget.org/packages/Nerdbank.GitVersioning
MIT License
1.38k stars 167 forks source link

NPM/Yarn-only way of versioning packages #232

Open AArnott opened 6 years ago

AArnott commented 6 years ago

In some factions of NPM development, gulp and other build orchestrators are being avoided in favor of simply using yarn build, yarn pack, etc. This makes our gulp-based doc less helpful.

How can NB.GV help versioning for these folks? Preferably yarn pack automatically builds a package with the right version, and without dirtying the source tree. Is that possible? If not, what's the closest we can get?

eberkund commented 5 years ago

I am having this issue with Create React App, I have tried using the nbgv but it's difficult to get working on Windows because of limitations of NPM scripts on Windows.

Ideally we could inject the version number into process.env.VERSION or something similar so that it could be used by the bundled app.

AArnott commented 5 years ago

@eberkund Have you tried the dotnet nbgv tool? It can return raw version variables and/or set environment variables.

eberkund commented 5 years ago

Hi @AArnott, I was trying to use the nbgv tool before was not successful.

The issue I was having was that I could not find a way to assign an environment variable in my NPM script that would work on Windows.

Something like this I found would work if you only use a *nix environment:

"build": "VERSION=$(nbgv get-version -v Version) react-scripts build"

But does not work on Windows. If an environment variable can be set this way then webpack will inject the value so that it will be accessible as process.env.VERSION from code.

eberkund commented 5 years ago

Actually I went back and took another look at it and I think the ideal solution would be to create a package so that users could do something like this:

{
  "dependencies": {
    "nbgv": "^1.0"
  },
  "scripts": {
    "build": "nbgv-helper react-scripts build"
  }
}

"nbgv-helper" would wrap anything you pass it, similar to how cross-env works and be distributed as an NPM package.

I got something partially working (by hard coding my particular use case) but my lack of experience creating node tools slowed me down.

{
  "scripts": {
    "build": "node ./build.js"
  }
}
const child_process = require("child_process");

const version = child_process.execSync('nbgv get-version -v NpmPackageVersion');

process.env.REACT_APP_VERSION = version;

child_process.execSync('react-scripts start', {
  stdio: 'inherit'
});

Any thoughts on this approach @AArnott?

AArnott commented 5 years ago

That's an interesting way to go. I've been looking for ways to create NPM packages that are stamped with the nbgv computed version that didn't require changing sources and it looks like your approach may work.

But what is react-scripts start doing? Is it creating a package, or starting an app? And if starting an app, why does the version as an env var matter?

eberkund commented 5 years ago

react-scripts provides wrappers for webpack that preconfigure it for working with React. It is the recommended scaffolding for creating new React projects. I know Vue.js is very similar with their wrapper scripts being called "vue-cli-service". Even if you are not using one of these tools I think it would work the same way if you were calling webpack directly from your NPM script.

react-scripts start builds the app, starts a development server and watches for changes but there is also a react-scripts build command which just builds the files and outputs them to a folder.

The env var is important because it makes the version number accessible to from the app code. For example, I am using it to display the version number in the footer, so I can just reference process.env.REACT_APP_VERSION. There is some more information on it here.

The default create-react-app template has some scripts like this:

{
    "scripts": {
        "build": "react-scripts build",
        "test": "react-scripts test",
        "start": "react-scripts start"
    }
}

Ideally the installation instructions would just be to prepend the nbgv-helper which would set the env var to the version number:

{
    "scripts": {
        "build": "nbgv-helper react-scripts build",
        "test": "nbgv-helper react-scripts test",
        "start": "nbgv-helper react-scripts start"
    }
}

And then in your app code you would have access to the version through the process.env.VERSION variable.

AArnott commented 5 years ago

It sounds like the nbgv-helper that you're describing wouldn't stamp the version anywhere, but it would allow the app's status bar to show the version. Is that right? But you couldn't ship an app that way, right? Would this only serve to show the version while the app is running from the development console?

eberkund commented 5 years ago

Ah, you are correct. I hadn't thought of that as that wasn't a requirement for my scenario.

Maybe instead of setting an env var, npm version should be used to update the package.json file. It could still be done by a utility provided by nbgv.

const child_process = require("child_process");

const version = child_process.execSync('nbgv get-version -v NpmPackageVersion');

// Sets the version in package.json
child_process.execSync(`npm version ${version}`);
{
    "scripts": {
        "build": "nbgv-helper && react-scripts build",
    }
}
AArnott commented 5 years ago

You have seen my nerdbank-gitversioning NPM package, which gets versions and stamps package.json, right?

eberkund commented 5 years ago

I saw that but I gave up on trying to use it because I wasn't using gulp or a similar tool.

What if nerdbank-gitversioning exposed a CLI so that it could be called directly? And also this line:

https://github.com/AArnott/Nerdbank.GitVersioning/blob/3e036939766bcaed07f153f78340a13336ab4db5/src/nerdbank-gitversioning.npm/ts/index.ts#L73

added the --allow-same-version flag (to prevent errors when the version doesn't change with each build)?

Then it could be used directly from NPM scripts.

{
    "scripts": {
        "build": "nbgv set-version && react-scripts build"
    }    
}
AArnott commented 5 years ago

I saw that but I gave up on trying to use it because I wasn't using gulp or a similar tool.

gulp is just what I sometimes use and what the sample/doc uses. the nerdbank-gitversioning NPM package doesn't have anything that requires that you use gulp IIRC.

What if nerdbank-gitversioning exposed a CLI so that it could be called directly?

The nbgv dotnet CLI tool is already exactly that. The NPM package nerdbank-gitversioning essentially wraps this and adds a small API around it, but if you want the CLI tool itself, it's there for you.

added the --allow-same-version flag (to prevent errors when the version doesn't change with each build)?

I didn't realize it failed in that case. Can you send a PR to fix that?

eberkund commented 5 years ago

The nbgv dotnet CLI tool is already exactly that. The NPM package nerdbank-gitversioning essentially wraps this and adds a small API around it, but if you want the CLI tool itself, it's there for you.

What I'm doing current is I created a script called version.js which calls the nerdbank-gitversioning package to modify my package.json but the problem I'm having right now is the version seems to get loaded at the beginning when the script is started so when I modify the version it doesn't get reflected until the next run. I'm still looking for a solution for that.

"scripts": {
    "build": "node ./version.js && react-scripts build"
}

I didn't realize it failed in that case. Can you send a PR to fix that?

Sure.