0

I have a problem with a pipeline which is used to increase a npm lib version (a storybook project with some react components). I didn't find a perfect way to increase the version automatically being one-to-one with each Pull Request. So, for each completed PR, I want to increase the version (patch): 0.0.1 -> 0.0.2 -> 0.0.3 ...

So, the principal pipeline is triggered on main branch. When somebody complete a PR, because the main branch receive updates will trigger the pipeline, which build and deploy the lib to a private registry. There, we can not deploy a new lib with an existing name, so we need to increase the version for each deploy:

lib-app-0.0.3 (current version)
lib-app-0.0.2
lib-app-0.0.1

for thix example, we should deploy the lib-app-0.0.4. So, I created another pipeline, which only increase the version of the project, which contain a script:

git config --global user.email "alex@company.com"
git add . 
$BranchName = $(Build.SourceBranch)" -replace "refs/heads/"
npm version patch
git push origin HEAD:$BranchName --force

This will works perfect if is triggered manually or after each commit (which I don't want, because a PR can contains 10 commits, so a lot of version numbers will be skipped). But I need it to be triggered only when I create the PR, or better, only when the PR is completed.

Problem: I can not trigger it when PR is completed, because in that time, the changes are already on main and the principal pipeline will be fired (build & deploy main branch !!! without increasing the version - because we can not push code directly into main)

So I thought of something: use the increase version pipeline as a Build Validator for this repository. So I just create a PR and then the pipeline will be executed. Partially correct, but here I found another problem: the pipeline will COPY (using mirroring I think) the repository, increase the version, but not push the package.json with updates to the repository because have limited permissions)

! [remote rejected] HEAD -> refs/pull/13554/merge (The current action can only be performed by the system)
error: failed to push some refs to 'https://dev.azure.com/org/repo'

Oh, I already set all permissions in repo settings (for both, source & target branches) for the organization.

I'm not sure if there is a solution ... how you solve something like that? thanks

AlleXyS
  • 2,476
  • 2
  • 17
  • 37

2 Answers2

2

Background:

Here are 4 general types of solutions to the versioning issue (there are likely others):

  1. Store the version in code, and require the developers to update the version themselves on their feature branch. (PR status checks are useful here to validate the version is changing properly.)
  2. Store the version in code, but have the pipeline increment the version automatically on the target branch (in your case, main) after PR completion.
  3. Store the version in code, but not on the shared target branch. The pipeline would "know" the version some other way (perhaps a DB or counter in the build pipeline, or the latest tag), and then create the build commit detached from any branch and tag that commit with the build version.
  4. Don't store the version in code at all. This is the same as 3 but without creating a new detached commit and tagging it.

Your scenario:

I think you're leaning towards #2, and it sounds like you just need some tweaks to your setup. You already have a pipeline that fires on merges into main. You could add some steps at the beginning of the pipeline to:

  • Checkout main.
  • Update the version number.
  • Commit the version number change.
  • Push main. (Explained below...)
  • Do the rest of your pipeline.

How to push main:

Since main is protected, you must adjust the security permissions to allow the user running the pipeline to push directly to main. In AzDO, the way to do this is to adjust the security of the branch for each user that should be able to bypass a PR. Simply set "Allow" for both "Contribute" and "Bypass policies when pushing." All other permissions are typically not required and could be left as "Not set".

To set permissions, you must know which user the pipeline is running as. For example, in my case, if I search for a user and start typing "Project Collection Build Service", my org's user shows up (with a GUID underneath) which I can select and set permissions for just like any other user.

Additional Notes:

  1. You should strive to always avoid force pushing a shared branch. In your case the amount of time it takes your pipeline to change the version number, commit it, and push it, will probably be just a few seconds, but it's still possible that another PR could be completed during that time, in which case the pipeline's push will fail. Perhaps this isn't a big deal as that second PR will just trigger the pipeline again and that one should work. But if you need a build for every completed PR, then you could look into using the API to temporarily lock and unlock the main branch for those few seconds.
  2. Make sure to update your pipeline trigger to exclude the version file changes. Otherwise you'll end up in an infinite loop which triggers itself by pushing a new commit to the branch.
TTT
  • 22,611
  • 8
  • 63
  • 69
  • Thank you man. you described the problem exactly. I've already tested with the `Project Collection Build Service` and added a build step to the main pipeline. Looks as the best solution. But here is another problem. Since the pipeline is triggered every time the main branches are updated, it will throw a loop because when I push a new version, it will trigger the pipeline again and again. – AlleXyS Jul 17 '23 at 06:55
  • I need to specify somehow that the pipeline should be triggered only by a PR completion, or to use a condition. Right now, to increase the version, I use a condition (`variables['Build.Reason']` to be `'IndividualCI'` and `variables['Build.SourceBranch']` to be `'refs/heads/main'`) – AlleXyS Jul 17 '23 at 06:56
  • I can condition stages based on `Build.SourceVersionMessage`, to skip it if they are x.x.xx format. Is not perfect, but works, the pipeline will be triggered 2 times, first by the PR complete, then by the increase version commit (where all stages will be skipped). Anyway, we found that is not allowed to push directly into main branch (bypassing it even for the organization's user) – AlleXyS Jul 17 '23 at 08:32
  • @AlleXyS Looks like my last sentence was relevant- hehe. Take a look at [this question and answers](https://stackoverflow.com/q/62172468/184546) for how to exclude certain paths on the trigger. – TTT Jul 20 '23 at 21:49
0

I would suggest, instead of running npm patch after PR is completed, run the script when PR is merged. Apart from that, here is detailed article you might be looking for

https://luke-pammant.medium.com/auto-increment-npm-package-version-in-azure-build-pipelines-279a1a493f47

  • but ... when the PR is completed, the source branch is already deleted and the target branch (main) is inaccessible for changes. and this step: `# if we find out that the version we're trying to publish already exists in the feed, then let's increment patch version for that package and publish` is not possible at least on main branch. Or the version is just incremented on the deployed file (taking the latest version from `registry`), but this means that we will ignore the future versions of `package.json` – AlleXyS Jul 14 '23 at 14:32
  • ok. can u confirm 1 thing? is it absolutely definite, that, you would want new version on every PR merge or PR completed? – Mohitsinh Chavda Jul 15 '23 at 20:34
  • to be fully automatic... yes – AlleXyS Jul 17 '23 at 08:33