0

I am a beginner with BASH I am trying to automate the following process:

  • get release version --> file "release"
  • increase it
  • save it again in the same file "release"
  • git add all
  • git commit "releaseX"
  • git push

I will call this file releaseit.sh

for that I start with some code I got from: Extract version number from file in shell script

BASH:
read version < release
echo $version
echo ${version%.*}.$((${version##*.}+1)) 

How do I pass the last line to a variable and save it again into release file?

Desired result: if release contains 0.1.34 a new release file will contain 0.1.35 will be added committed and pushed.

JFerro
  • 3,203
  • 7
  • 35
  • 88
  • 2
    You can write output to a file using `>`, so if your last `echo` print looks correct in the console you can just add `> release` to the end of that line (and then `git commit -am "release" && git push`). – ades Jan 05 '22 at 15:38
  • 1
    Don't do this. Do *NOT* store the release number in a file. (Despite the fact that so many project do this, it is a terrible practice.). Instead of storing the version number in a file, you should derive it from the VCS. (eg. via `git describe`) – William Pursell Jan 05 '22 at 15:39
  • but it does not let me overwrite the file – JFerro Jan 05 '22 at 15:39
  • @WilliamPursell this is not in my hands, I am working in a system where the release is controlled by the number stored in release file and ONLY when this number changes then the version of the library will be deployed to everyone. – JFerro Jan 05 '22 at 15:41
  • 1
    @JFerro. You need to convince the people working on this system that the system is broken. Storing the version in a file like this is a land-mine. It's a recipe for disaster. It's a floating iceberg waiting to sink your ship. The project is doomed! – William Pursell Jan 05 '22 at 15:43
  • @WilliamPursell The context is: Jupyter hub environement, when release file changes it fires jenkins to build a pyhton package that then can be import by anyone. all the commits without changing release are stored in althasian repository but dont generate the python package. – JFerro Jan 05 '22 at 15:54
  • @WilliamPursell That seems to rely on the VCS. What happens if you release a library that needs to have its version known from a class? Or a command-line or GUI tool where the version needs to be queried. – konsolebox Jan 05 '22 at 16:34
  • @WilliamPursell I can somewhat agree with you if you meant that the release file is forced to be only updated during a release commit, probably through some VCS rules, although I don't really see the difference. – konsolebox Jan 05 '22 at 16:43
  • @konsolebox That's why you have a build system. If a version comes from a class, or some component of your system requires that the version be stored in a file, then you build that file dynamically at build time. You do not store it in the repo. – William Pursell Jan 05 '22 at 16:43
  • @WilliamPursell And where do you store the version when it's packaged? – konsolebox Jan 05 '22 at 16:45
  • What do you mean by "store the version". You build an artifact (eg, a tarball, or an rpm, or a .deb) and you put it in some distribution mechanism. (eg, on a public ftp server). I think a big part of the problem lies with projects that attempt to use the git repo as a distribution tool. It's not a distribution tool, and shouldn't be used as such. – William Pursell Jan 05 '22 at 18:41
  • @WilliamPursell "What do you mean by "store the version"" Read again above. This is not about declaring the version in the package but how to actual product would present its version itself and you would need it recorded somewhere when the files are exported away from the VCS. – konsolebox Jan 06 '22 at 14:23
  • @konsolebox, that's not really an issue. You simply use the build system to store it however you want. If you want to have a static file with the version number in it, you create it at build time and place the file in the artifact. If the version number is a hard-coded string in a .c or .java or .* file, you build the necessary file with the build system (or refactor your code so that it can be in a config file which is generated at run time). Again, this is only difficult if you are trying to use `git` as a distribution tool instead of building artifacts. – William Pursell Jan 06 '22 at 15:49
  • Git is first a distribution tool and second the latter. When has it been a norm that has to be a dependency to build packages? I'm simply trying to point out that your idea of "not storing version numbers in a file" does not apply everywhere. See in the end you suggested a rule where the version number is stored in a file. This forces two ways on extracting the version number. One is to detect if the source code is currently stored as a tree in git, another is to detect if it is part of a lone package, which just makes things complicated. – konsolebox Jan 06 '22 at 16:12
  • The only unifying way to do it is simply store the version in a single place, which is a single file, which puts us back to what I said earlier that it doesn't make much of a difference. You still store the version in a file, only that you apply strict control. Still that in plain form no longer agrees with your idea "not to store the release number in a file". Your point simply doesn't apply generally. – konsolebox Jan 06 '22 at 16:15

3 Answers3

2

Disregarding the discussion of whether you should do it or not, you could do this:

#!/bin/bash

read version < release
echo $version
nextversion=${version%.*}.$((${version##*.}+1))
echo "$nextversion" >release

Same as Stanislav's answer above, just storing it in a variable, if you ever need it later in the script.

Nic3500
  • 8,144
  • 10
  • 29
  • 40
  • @Williampusel actually that is exactly the desired functionality. Again the context: we are talking about python, not compiled. Second in a jupyter environement. So one single coder is pushing to a repo in altasian (on premises of course) at the most there might be two coders working together. I am not talking about profesional CS background people. People who "hack" around and want to serve the solution to other colleagues through a python Module. The coder pushes many many times before he decides the next commit is ready for a new version. – JFerro Jan 06 '22 at 18:55
  • Only then Jenkins is fired to pass all the tests and from that moment anyone else in the office installing the library will get the new version. People have often very very little knowledge of git. Pushing cloning commit and not much more. This is the situation. – JFerro Jan 06 '22 at 19:13
2

You really don't want to do this. The release number should not be stored in a file in the repo, since doing this will lead to multiple commits in the repo that all share the same version. This is a recipe for disaster. However, if you do want to do this, you might want something like:

#!/bin/sh

version_file=release

if test "$1" != "-f" && git rev-parse HEAD > /dev/null 2>&1 \
        && ! git diff-index --quiet HEAD; then
    echo 'Repo is dirty.  Aborting' >&2
    exit 1
fi

IFS=. read maj min patch < "$version_file"

if { ! test "$maj" -ge 0 || ! test "$min" -ge 0 || ! test "$patch" -gt 0; } 2>/dev/null; then
    echo "Invalid version in $version_file.  Aborting" >&2
    exit 1
fi
case $1 in
maj) : $(( maj += 1 ));;
min) : $(( min += 1 ));;
*) : $(( patch += 1 ));;
esac

ver="$maj.$min.$patch"
echo "$ver" > "$version_file" || exit
git add "$version_file" || exit
git commit -m "Increment version to $ver" || exit
git push || exit
William Pursell
  • 204,365
  • 48
  • 270
  • 300
1

Just use > to overwrite the file content:

read version < release
echo ${version%.*}.$((${version##*.}+1)) > release

But I'd agree with the comments - you shouldn't store your build version in Git, read this.

Stanislav Bashkyrtsev
  • 14,470
  • 7
  • 42
  • 45
  • This is driving me nuts. what/where is the right place to change version number? – JFerro Jan 05 '22 at 15:55
  • 1
    Added a link. The version should be added during the build and it should come from your build server. – Stanislav Bashkyrtsev Jan 05 '22 at 15:57
  • 2
    @JFerro You don't change the version number. The git repo stores the version number in a tag. Making a new release should involve tagging a commit. If you need a number, you should derive it from git with `git describe`. – William Pursell Jan 05 '22 at 15:57
  • 1
    @WilliamPursell, even putting it into a tag seems excessive for most cases. Just keep it out of Git's knowledge. – Stanislav Bashkyrtsev Jan 05 '22 at 15:57
  • So following your advice how should I find out the version of a package in the terminal? above all if it is not even a tag in git? – JFerro Jan 05 '22 at 16:12
  • 1
    @JFerro, I can't come up with a reason to do so. Usually I want to find the commit _of the built binary_. And that commit is usually stored inside of the built binary. Ideally it should be exposed in UI/REST endpoint of the app. – Stanislav Bashkyrtsev Jan 05 '22 at 16:17
  • 1
    Why do you say putting it into a tag seems excessive? FWIW, that's the most common technique I've seen. The [Git project itself](https://github.com/git/git) does exactly that: releases are tagged `vX.Y.Z`. As @WilliamPursell says, tagging releases integrates nicely with `git describe`, which generates labels for arbitrary commits based on the nearest tag, so the labels are semantically meaningful and also unique like SHA-1 hashes. – John Kugelman Jan 05 '22 at 16:38
  • 1
    @JohnKugelman, because this isn't usually useful. The major use case to match versions with commits - you have a binary used somewhere, you'd like to find out which commit it's built from. The most robust way of doing this is keeping the version inside binary - getting the commit from there. But I don't consider using tags a bad practice. I don't find it helpful, but it doesn't harm either. NB: I'm coming from an angle of enterprise/web software. Building libraries is a bit different. Also, I can't recommend Git Project as example of how to run a project. Especially an enterprise project. – Stanislav Bashkyrtsev Jan 05 '22 at 16:58
  • 1
    @JohnKugelman, as for `git describe` - it finds the most recent version _in the past_. You need the most recent version _in the future_ to find out in which binary version it was introduced. – Stanislav Bashkyrtsev Jan 05 '22 at 17:11
  • 1
    For executables, the git hash is sufficient as a version number. But for libraries, semantic versioning can be essential so adding a `x.x.x` tag and releasing packages that incorporate the x.x.x as well as the hash can be useful. And for human consumption, numbers are nice. `2.34.1` is more meaningful than `e9d7761bb9`. (`2.34.1` is clearly newer than `2.34.0`, but it's difficult to compare `cd3e606211` and `e9d7761bb`) – William Pursell Jan 05 '22 at 20:05
  • 1
    @WilliamPursell, for executables the order of versions is equally important. But since it's a runnable program, it can tell you its commit. While library can't do that. You need an additional step to associate version with commit - so it's either looking inside of the file (which is awkward, especially in case of compiling languages like c/c++), or.. well, using tags/commit messages. So yea, I agree that for libraries tags make sense. – Stanislav Bashkyrtsev Jan 05 '22 at 23:36