I am looking for a good process to manage the version number of my project when my master branch has GitHub branch protection turned on.
In an ideal world, when you merge to your 'release' branch your continuous integration server would run its tests then automatically increment the version number of your project and commit back to your SCM system.
However, with branch protection, you cannot commit to your branch without a Pull Request, so you have a catch-22 where your CI server cannot push to your protected branch when it tries to update the version number.
I can think of a few work arounds, all of which are sub optimal:
Rig up a system so your CI server would make a PR to update the version. I'm not sure if you can even do that with GitHub, but even if it is that ends up creating two Pull Requests for every one 'real' PR, which is awkward.
Remove Branch Protection - now anyone can push anything to the branches, and you have to manage your developers through a manual process
Update the version manually before the pull request. this is slightly better than #2, but it opens the door for developers to make mistakes when choosing the new version number, or merging the right version number to the wrong branch.
I'm hoping there are other options I haven't thought of.
We are using Javascript and npm, but I believe the problem is language agnostic, certainly the same problem would exist with Java and Maven for example.
I used git tags to automate versioning using Jenkins. So every time the job ran it took the last tag and incremented it. Since tags are different than commits, adding a tag doesn't conflict with Branch Protection.
# get last tag
last=$(git describe --abbrev=0 --tags)
# increment and tag again
git tag $(($last + 1))
git push origin $(($last + 1))
This script is for a simple integer version number but you could follow semver if you like. This was for a Android project so I added a gradle function that would take out the last tag and use if for version number while building.
/*
* Gets the version name from the latest Git tag
*/
def getVersionName = { ->
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'describe', '--tags'
standardOutput = stdout
}
return stdout.toString().trim()
}
I am sure you could use a similar setup with Javascript.
Related
I want to accomplish following via teamcity in my CI box.
Master branch commit : Build and Release
Beta branch commit: Build and Release to Crashlytics
All other commits to any other branch: Build
(side note since most of our development branches may or may not contain a prefix, it makes it difficult to use "feature-*" branch naming)
Following this question Select Git branch for TeamCity Build
I have created a Configuration Parameters in my project settings
and then
my VCS root settings
Then I created a build template
When I created builds I made sure branch name is correct
I have also tried to edit Triggers
How ever this is not working because when I push a commit to Beta branch
I think because of ref/heads/* default build is running all the branches
and Beta and Master displays "Pending"
How can I correct this?
I solved the problem by talking to other developers and making sure that all development branches uses a prefix, in this case XAAI-
then in my VCS root settings
for triggers in each build configuration I make sure it only is triggered when that branch is checked in.
for example for QA (Betabuild)
this is the tricky part , for Development branches I had to give an empty parameter, I dont know why (maybe because something needs to check default branch which is supposed to be ref/heads/) but whatever the reason it is working.*
and then finally whole thing looks like this
That pending thing is still annoying but , I think at least it is working as I envisioned now.
If you want your builds to only trigger automatically when the default branch is pushed to, you can add a branch filter to the trigger like so +:<default>.
This is dependent on the assumption that you have setup the %BranchName% parameter in each build configuration correctly. IE, for your Default build, make the %BranchName% parameter = master.
As a side note, you will still see all pending changes for each branch, but the trigger will only run when you push to your default build if you add the branch filter. If you want to get rid of the pending changes for each branch, you'll need to setup your vcs root specfic for each configuration to filter out the branches all together.
there's an "issue" (actually a nuisance, but a major one) with our development process.
We've setup a good continuous integration-deployment-delivery pipeline; basically, our process is like that:
New development happens on the default branch (we use Mercurial, but git would have the same issue); usually we develop just one small improvement there;
Once the improvement is ready and tested (something that usually happens twice or three times a week, our cycle is pretty short), it's merged into the release branch (which actually stands for release candidate), it's tested again in a production-like environment and if it passes all our testing it's pushed to the production environment.
If we need to make a bugfix, we do it on the release branch, we test it and then push it to the production env.
An artifact (usually an RPM package) is built from each branch; when there's a release in production, the very artifact from the release branch is promoted to our public repository. There's no branch for the production environment, because we usually don't need it (there's a very short timespan when something it's on the release branch but it's not in production; code doesn't linger there unattended).
In this context, there's a small issue for us.
In order to distinguish packages, we usually set version to 1 for packages on the release branch, and 2 to packages on the default branch. Our CI system then adds its build number, so we've got packages like oursoftware-1.0-build37 for release and oursoftware-1.0-build902 for default. Such version is written either in our .spec file or in our pom.xml files (or other files for different softwares, like .gemspec or simila)
Whenever we want to put something in release candidate, we merge the default branch to the release branch.
What happens there? the version gets merged as well. So after each merge we need to get back at the file containing the version and put the old version in them. We should need to do it just once (Mercurial does not try to re-merge things that were already merged) but whenever we need to do a merge from release from default (e.g. in order to merge a fix done on release to the dev branch) the problem rises again.
I'd like some advice on how to prevent this problem completely; how do I set versions outside of my branches? I sometimes actually need to change them (e.g. I want to change from 1 to 2 on release and from 2 to 3 on default) and I wouldn't like to hardcode them in our CI system, I'd like some system which is "outside" the scope of branches and it's kind of "global" for a repository. Or I would need something like "ignore modification for some files".
In many situations I actually need versions in my files as well; for example I cannot omit version info from a Maven pom.xml file or from a .gemspec, otherwise it won't work when developing.
Thanks,
Well, I see 3 4 a lot of possible solution, more or less "native" (random order without priorities and own personal preferences)
Instead of "Monolitic $DEVEL branch" you can use "Branch Per task": in this case file with (hardcoded) version-info will not appear as mergeable file (TBT!)
Branch-specific version change can be moved from (permanent) changeset of branch into patch of MQ (as results - versions /and files/ are identical across branches, permanent default changes have to appear as result of applying patch)
Files with version-info doesn't contain hardcoded versions, they are more "templates", than "data", and real data appear as result of some preprocessing inside build process (you know transformation-rules and can code it)
You can change nothing in developent|deploy process and if version-info files are unique inside repository, you can use trick, similar to merging hgtags (special mergetool for only some files in repo - in your case in must be internal:local special mergetool)
Maybe using just merge-patterns will be OK for you, check Mercurial - Exceptions to internal:local merge-patterns? and Default to trunk version for Mercurial merges? for details and some additional notes+discoveries
I try to understand the right approach for managing hotfixes with TFS /source-control.
Say I have a small project to contains only two file (app.js and util.js). Both files are under source control (Team Foundation Server).
Assuming I applied two weeks ago a label that indicates the "milestone-1" that was deployed to the server. Since then I applied several other modifications (extended app.js and added another files).
Today I found a bug so I get the version with the label "milestone-1" from the server, modify the util.js and deploy this version to the server. The goal is that on the server only the version "milestone-1" including the hotfix-1 is deployed but not the modification I applied the last two weeks.
The question is: How /where do I check-in the hotfix to the TFS? Because I might find another bug tomorrow so I have to get the version "milestone-1" and the hotfix-1 base base for appling the second hotfix.
Is there a way to check-in a version of my code into the TFS that "sits" between label "milestone-1" and my latest version?
With branching and merging!
We have the following development cycle:
The initial project is created, permissions assigned, and imported in to TFS under branch name of "Main".
Because this is the initial iteration of development, we branch "Dev" from main, and that's where the developers work. Note at this point there is no official release.
When development is complete, it is merged back in to Main. No Dev work happens on the Main branch.
We branch "Release" from main, and that is the point at which the code is actually deployed, and version numbers are updated.
Ok, so, further down the line, we have to make some amendments. Once again, "Main" is branched out again and the development work continues down the Dev Branch. All is well. Then a user reports a bug that needs fixing, and it needs fixing fast. But we're half-way through our other development!! What to do?
At this point, we branch from main again. We'll call it "HotFix". The bug is fixed, and then HotFix is merged back in to main. We can then merge it in to our release branch, and the update is sent out. Our current dev work is not interrupted, and none of the work we have been doing up to this point exists on Main).
We finally finish our dev work, and we merge that back in to the main branch, and then in to release. Because our Hotfix branch got merged in to main, our new development work also contains the hotfix we did on the fly earlier.
You should use branching. Check out the "Rangers'" guidance.
I have successfully used the Advanced Branch Plan in the past, but you can customize it to your needs. You need to be disciplined with branching, merging, checking in, etc. Also consider shelvesets for code changes that aren't ready to be committed even to the DEV branch.
http://vsarbranchingguide.codeplex.com/
Let me know if you want more information.
I am wondering what the best way might be to use Mercurial to create a release revision that includes artifacts that provide evidence of process execution. For example, we'd like to attach system test results, check lists, release notes, etc. so that if we are audited by a customer we can easily show that we performed our process. This is important to us due to the safety aspects of our product.
Our release management process will go something like the drawing below. All developers are developing in local repos and periodically pushing to main. Main is the latest and greatest but not necessarily safe for even internal engineering purposes outside of the dev team.
When we want to create a release for the customer or for other internal engineering departments, we start with a release candidate branch (e.g. RC1). If any fixes are required, we commit to the RC branch. Testing occurs on this branch. When the RC is determined to be good, the changes are merged back to main.
We think that what we would like to do is merge into a Releases branch. However, we have a chicken and an egg problem related to the artifacts: The artifacts that we would like include in the release revision contain, among other things, the hash for the revision. This provides clear traceability that the testing and other process steps were performed on this precise revision. But, to add these items, I need to create a new revision and I obviously can't know what the hash for that revision will be before I create it. I am wondering if there is some way to "amend" a revision without changing the hash?
The only way to do this, that I can think of, would be, for example, in the drawing below, to create a revision RC2.3 that contains the necessary process artifacts but actually merge RC2.2 to Releases.
Then, of course, I have another problem and that is that the merge of RC2.2 into Releases will generate a new hash. So, my artifacts are out of date again. So the next question is whether there is some way to have the Release branch "point to" RC2.2.
BTW, we're open to changing this process if necessary. Our reasons for using this methodology are:
CI system is monitoring main and kicks off a series of builds and performs automated unit testing on each push. There are frequent changes to main and we don't want people using it.
Development can continue on main with no impact to the release.
Any revision on the Releases branch kicks off a different set of tasks on our CI platform, including the creation of a distribution of a field flash utility and the required images (we're developing firmware). This is how we provide releases to outside entities.
Main A--B--C--D--E--F--G--H--I--J--K--L---------M-------------N
\ / \ /
RC1 RC1.0--RC1.1 \ /
\ \ /
RC2 \ RC2.0--RC2.1--RC2.2
\ \
\ \
Releases ER1.0-----------------------------------PR1.0
To answer your question:
I am wondering if there is some way to "amend" a revision without changing the hash?
No, that's impossible by design. The changeset hash is a cryptographic checksum derived from the content of the commit — this is why the changeset hash uniquely identifies the content of all the files in the changeset.
The Mercurial wiki has a page with a standard branch setup. I'll describe how it works with pictures below.
What people normally do in your situation is to create a branch for release candidates like you suggest. If you're about to release version 2.0 of your firmware, then I would call the branch 2.x. The commits on the branch are release candidates for your version 2.0:
Main A--B--C--D--E--F--G--H--I--J--K--L---------M-------------N
\ /
2.x 2.0-RC1--2.0-RC2
Bugfixes are committed on the branch as needed and merged back into Main regularly. You should always be able to merge the bugfixes back since they are by their nature bugfixes and stability improvements that you want to have on Main too. In other words, commit I above has the bugfixes in 2.0-RC2 plus the new features in D to H.
You can work on the release candidate branch as much as you want and keep fixing bugs:
Main A--B--C--D--E--F--G--H--I--J--K--L-------M-------------N
\ / /
2.x 2.0-RC1--2.0RC2 -- ... --2.0-RC8
All bugfixes are merged back since the rule is that you can only do fixes on the release candidate branch that are safe. Here you had 8 release candidates on the release branch.
When you like the status of the release candidate, you can tag it and run the more comprehensive tests on the revision you tagged. The output of a succesfull test is committed on the branch and you then tag that commit as the final released version:
Main A--B--C--D--E--F--G--H--I--J--K--L-------M-----------N
\ / / /
2.x 2.0-RC1--2.0RC2 -- ... --2.0-RC8 -- T -- 2.0
Here T has the test output for 2.0-RC8 included. Commit T is the one you tag as version 2.0 of your software and the one you package and ship to your customers.
Should you need to create a version 2.1 with a bugfix to 2.0 (but no new features), then you continue with the same scheme:
Main A--B--C--D--E--F--G--H--I--J--K--L-------M-----------N
\ / / /
2.x 2.0-RC1--2.0RC2 -- ... --2.0-RC8 -- T -- 2.0 -- 2.1-RC1
That is why I called the branch 2.x.
Your usage of mercurial seems a bit complicated with all those merges all over the place and will be painful to handle.
You are using the branches feature of mercurial, but seems to overlook 2 other important features:
Tags
Cherry Pick
I'll describe below our general usage of mercurial to highlight those features:
Note that the following only applies to projects for which different versions need to be maintained over time.
The main branch (called default in mercurial) is dedicated as you to the current development of the application.
Every time a developer complete the development/modification/update of a functionality, he/she pushes their change into default, which is then available to everybody and to our CI (jenkins) which will ensure nothing is broken.
When we reach a stage where a new version is about to be released a branch is created. In reference to your schema, the branch could be named MY_PRODUCT_1_0
Developers will continue to work on the default branch, and any time a commit need to be in the coming release, the related changeset will be copied to the MY_PRODUCT_1_0 branch via the command hg graft REV_CHANGESET (cherry pick) (note you can also copy from MY_PRODUCT_1_0 branch to default).
So you basically select which changesets from the default branch will make it to the current release, without having to merge the 2 branches.
This requires developers to push clean and atomic changesets, which is how things should be done in mercurial in the first place.
As your commits evolve in the MY_PRODUCT_1_0 you can tag it multiple times along the way as your schema from MY_PRODUCT_1_0_RC_1, MY_PRODUCT_1_0_RC_2,...
When the final changeset is made on this branch you just need to tag it MY_PRODUCT_1_0_PR_1_0
You then get only 2 branches at first, default (the dev branch) and MY_PRODUCT_1_0 (your first release), and as time goes on when you need to release a new version of your product, you create a new branch MY_PRODUCT_2_0 and restart the cycle as described above.
With this approach you are sure that you only have the required changes in your releases, and not extra ones that you would get when merging branches.
I hope I was clear enought, if not let me know.
Is there a way in GitHub to change a commit message if I've committed with a message that has a typo or something dumb written in it?
I know you can do the ammend commit thing (which replaces the previous commit) from the CLI, but is there a way to just edit the commit message from the GitHub.com site interface?
If the problem commit is more than one commit ago, you have to fall back to interactive rebase. For example, if you notice a misspelling three commits ago, you would type something like this:
git rebase -i HEAD~4
Then rebase would open up your default editor with a view that looked something like this:
pick c5052cb Updated the workshop instructions
pick 6d6cd60 Upgraded to the plugin 0.6.1
pick c6d0921 Upgraded wrapper to Gradle 1.2
pick 7a111da Upgraded to 0.7 of the Liquibase Gradle Plugin.
# Rebase 097e6b2..7a111da onto 097e6b2
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
You'd want to edit the third line (the one referring to commit c6d0921) to start with the word "reword" instead of "pick." Once you save and exit from the editor, you'll find yourself right back in the editor with that commit's message in front of you. Correct your misspelling, save and exit, and all is well.
Note that doing this or doing a commit --ammend is dangerous business if you've already pushed these commits to an upstream repo. This is why there's no way to do this on GitHub.com directly. If you want to change commits you've already pushed, that's a separate matter entirely. :)
There isn't a way to do it directly on the site.
You could:
git commit --amend
git push --force origin master
One of the main reasons we don't want to allow people to do this on the site is because it'd change the entire structure of the commit (basically just think of this as changing the commit hash). This isn't a problem when it's only you, but for the sake of a community of people working with you, this is a problem because no one else will have that commit, and when they try to pull they run into issues.
This is the same as doing the ammend on the command line AFTER you've pushed, then force pushing to github.com. Usually a major no-no for workflows unless you take care with a lot of extra communication.