ramasilveyra/gitpkg

Add a "latest" tag in addition to the versioned tag.

sramam opened this issue · 4 comments

As it stands, the versioned tags are great if the sub-package is relatively stable.
For things like internal framework modules which are used in many places, any
update to the lerna module requires modifications to all downstream usages.

It'd be good to have a ${pkgName}-latest tag, in addition to the versioned tag,
allowing in effect the same npm behaviour as @latest.

Hello @sramam ! Sorry for my long delay answering.

Once I tried adding latest (${pkgName}-latest), major (${pkgName}-1 and minor (${pkgName}-1.2) tags. But It doesn't work with lockfiles, yarn has a yarn.lock lockfile by default and since npm v5 we also have a lockfile called package-lock.json by default. Having lockfiles by default is the right way to go. And those lockfiles lock the git deps by using the git hash/checksum.

For example by installing the git tag gitpkg-v1.0.0-beta.1-gitpkg of the repo https://github.com/ramasilveyra/public-registry with yarn, the yarn.lock file will look similar to this:

// ...
"gitpkg@github:ramasilveyra/public-registry#gitpkg-v1.0.0-beta.1-gitpkg":
  version "1.0.0-beta.1"
  resolved "git+ssh://git@github.com/github:ramasilveyra/public-registry.git#81bca092192e5070f73e1e67d7b01844b9e4c829"
// ...

and with npm v5 the package-lock.json will look similar to this:

// ...
    "gitpkg": {
      "version": "github:ramasilveyra/public-registry#81bca092192e5070f73e1e67d7b01844b9e4c829",
// ...

What is common in both? That the git tag gitpkg-v1.0.0-beta.1-gitpkg is resolved to the git hash 81bca092192e5070f73e1e67d7b01844b9e4c829 that is unique. So by forcing pushing new versions of the git tag gitpkg-v1.0.0-beta.1-gitpkg we kill the old git hash with a new different one, making the lockfiles to fail.

Also if you try to install a new updated forced pushed git tag it will probably break the cache of yarn and npm, causing it to behave erratically.

This also applies to git branch deps.

My ideas on how to ideally solve this problem is by implementing a custom semver definition and custom gitpkg fetching logic natively in yarn/npm. Take a look to #6.

I will close this issue and your pr, I hope that you understand. And in the case that you still want latest/major/minor tags, you can use gitpkg to release a new custom version of gitpkg!

Regards, have a great year!

As I understand the lock files, there are two cases -

  1. adding the module as a dependency, which @latest will get the current latest hash and install the hash in the package.
  2. installing the parent module, in which case, if a later gitpkg version is been published, the install will fail - per the lockfile logic you mentioned.

#1 is desired behavior.
#2 The unstable behavior is exactly what I'd like! It is the only way to detect that the underlying package has an update, since we have bypassed the registry all-together. I think of it as the price to pay for living on the bleeding edge (typically in a dev branch).

With npm/yarn, npm install express@latest adds a specific version to package.json - so it's the latest at the time the dependency was added! To figure if there is an update, there are two mechanisms - npm updated or npm-check. I really prefer the second, but that's just me quibbling. Both are checking with the registry for later versions.

This is the crucial piece that I miss with gitpkg - the ability to automatically detect dependency updates. I have to manually watch and patch.

If we set the #latest gitpkg tag, a periodic build will fail, alerting us to a need to patch. It's perfectly possible to avoid this instability by using any other gitpkg tag. It's only the #latest tag that behaves special. While I'd be reluctant to add more special tags, perhaps others have valid use cases for them.

This was crucial to me as I was considering using lerna. I have since moved on from
such mono-repos for my project, so don't have strong objections to closing the issue.

I did want to document the thinking behind the original PR. At least to me, it still looks like the only sensible thing to do with the #latest tag as it automates and otherwise pesky issue.

But then I do have way too many opinions!

Overall perusing the code of gitpkg, my understanding of git got better and I really enjoyed
the almost declarative code you have within. So thanks much for it. I am likely to copy that
style in the future.

Have a great new year and may the God of open-source smile upon you!

Hi,

I am using lerna for versioning and deferring the publishing task to gitpkg because it allows "Lightweight git tags (only the files needed are included)". This setup works great, however I do agree that it would be nice to also be able to have gitpkg force push to another tag like "${pkg.name}@latest" for reasons already mentioned by sraman.

My package.json looks something like the following currently (these packages do not depend on any other packages):

...
  "devDependencies": {
    "@company/package": "https://xxx:xxx@bitbucket.org/xxx/xxx/get/package@3.0.2.tar.gz"
    }
...

Whereas I could just use package@latest.tar.gz as a moving target that will point to the latest gitpkg release.

...
  "devDependencies": {
    "@company/package": "https://xxx:xxx@bitbucket.org/xxx/xxx/get/package@latest.tar.gz"
    }
...

Then I can use a hook to run npm install @company/package in order for all dependent projects to keep up to date with this package.

I was able to workaround this by adding the following to my package's package.json postversion hook (lerna version calls this hook).

...
  "scripts": {
    "postversion": "gitpkg publish && git fetch origin +refs/tags/$npm_package_name@$npm_package_version:refs/tags/gitpkg-tmp && git push origin gitpkg-tmp:$npm_package_name@latest --force"
  },
...

Explaining the git commands:

Note: $npm_package_name and $npm_package_version are NPM's exposed environment variables that can be used to refer to the package's values, you should update the commands in the hook to match the pattern of your packages names.

git fetch origin +refs/tags/$npm_package_name@$npm_package_version:refs/tags/gitpkg-tmp
^ This creates a temporary local tag "gitpkg-tmp" that points to the commit on remote (that gitpkg just pushed), the "+" means to overwrite local tag with same name.

git push origin gitpkg-tmp:$npm_package_name@latest --force
^ This pushes the gitpkg-tmp local tag to remote as @latest, --force ensures the remote one is overwritten.

Maybe some experienced devs can chime in on some pitfalls with this approach, for some with basic usage this seems to work.