Skip to content

Fremdbloggen

Lange nichts Neues hier im Blog.

Das liegt unter anderem daran, dass unsere Development-Abteilung inzwischen ein eigenes Blog hat, welches ich verstärkt als mein persönliches Dev-Blog benutzt hab: https://blog.hmg.dev/

Alle interessanten Software-Themen der letzten Zeit sind quasi da rein gewandert. Unter anderem über Zertifikatmanagement oder wie man Wordpress in Kubernetes betreibt ohne auf Skalierung zu verzichten.

Mal schauen wann mir mal wieder unterhaltsame Sachen für das Blog hier ein- oder auffallen.


p.s.: das überladene und langsame Theme war nicht meine Idee! Da wurde ich überstimmt.

Think like a proton and stay positive

Oder: nehmt mir nicht meinen Galgenhumor! (Denn als Softwareentwickler bin ich darauf angewiesen!)

Auslöser für diesen Beitrag sind im Prinzip zwei Dinge. Zum einen natürlich die Corona-Pandemie. Zum Zweiten allerdings die vielen Leute, die mir inzwischen sagen "es ist echt nicht mehr lustig."

Als Hörer des Aufwachen-Podcast, tendiere ich natürlich dazu, zu erwidern "Warum sind Sie so mega negativ?" (Stammhörer werden das Zitat erkennen)
Wer geschäftstüchtig ist, kann natürlich auch versuchen, die gehamsterten Klopapiervorräte zu Wucherpreisen auf eBay zu verticken.
Aber es gibt tatsächlich auch positive Effekte, die zumindest zum Nachdenken anregen sollten.
Hier also eine Liste, ohne Anspruch auf Vollständigkeit:



Wer sich jetzt fragt: "Hätte man das nicht auch ohne Pandemie erreichen können?" Dem sei gesagt: das versuchen Wissenschaftler seit über 40 Jahren - ohne Erfolg!

Ich wünschte, ich könnte wenigstens sagen, dass unsere Politiker halt "zum Jagen getragen" werden wollen. Aber das wäre IMO zuviel des Lobes. Die verhalten sich lieber wie kleine Kinder im Sandkasten, und klauen anderen Ländern ihr bestelltes medizinisches Equipment.
Nach 20 Jahren neoliberaler Politik des "weiter so", kann man seine eigentliche Aufgabe halt schon mal vergessen ...sogar als selbsternannte "Pro-Europäer", die die "Bazooka" raus geholt haben (Oder weiß schon jemand, wie kleine Unternehmen davon jetzt konkret profitieren sollen?)!

Ach, jetzt bin ich doch schon wieder zum Antiproton mutiert (eigentlich eine ordentliche Leistung, wenn man bedenkt, was Physiker unternehmen müssen, um Antimaterie zu erzeugen ^^)
Aber um das nicht ganz so negativ enden zu lassen, mache ich es mir einfach, und verweise einfach auf Yanis Varoufakis' Meinung zu dem Thema:

Unsere Microservices sind die größten...

Es ist soweit. Ich reihe mich ein, bei denen, die schon die ganze Zeit auf Microservices, Docker, Kubernetes und Konsorten herum hacken.
Ich war ja bislang immer der Meinung, dass die Idee dahinter doch eigentlich völlig nachvollziehbar ist. Und dass es durchaus vorteilhaft und fortschrittlich ist.
Aber da kannte ich die konkrete Umsetzung und "best practises" ja auch noch nicht näher.

Das fängt schon bei den Docker-Images an.
Eigentlich ist die Idee ja, dass eine Applikation schön abgekapselt in ihrem Container läuft und sich nicht darum sorgen muss, in welcher Umgebung usw. sie läuft.
Nun braucht so eine Applikation nur zumeist eine Laufzeitumgebung und diese wiederum ein Betriebssystem.
Und was kommt dann dabei heraus? Naja, ein Docker-Image, wo das komplette OS + Runtime schon mit drin ist.

Wir haben also eine vielleicht 2MB große Applikation ...plus eine 100MB Runtime und ein 700MB OS. Daraus bauen wir ein ca. 800MB fettes Docker-Image und nennen das ganze dann "Microservice" oO
Das erinnert mich ein wenig an die alten Witze über Robotron in der DDR.

"Robotron - unsere Mikroelektronik ist die größte!"

"Robotron - unsere Mikroelektronik ist einfach nicht klein zu kriegen!"


Das ganze packen wir dann mit Hilfe von Kubernetes in "die Cloud" - z.B. MS Azure.
Denn wir wollen ja mehrere von diesen "schlanken" Applikationen laufen lassen um die Last bewältigen zu können.

Über Kubernetes schreibe ich hier jetzt nicht mehr viel, denn folgender Beitrag von Fefe sagt eigentlich alles dazu:
https://blog.fefe.de/?ts=a3b25963


Nun stellen wir uns vor, wir wollen eine Konfiguration für die App ändern. Zum Beispiel einen String von "Wert-1" auf "Wert-2".
Früher hätte man vermutlich die Konfiguration irgendwo abgelegt (Shared Storage oder Datenbank) und die Applikation hätte sich die Config von dort gezogen.

Aber in Zeiten von Docker und Co. ist es natürlich total "old school", dass sich die Applikation darum kümmern soll. Wir wollen ja die armen Entwickler entlasten!!!!111elf
Also packen wir die Konfiguration als Dateien oder Umgebungsvariablen in das Docker-Image! Und wenn wir die ändern wollen? Ganz genau!
Wir bauen in Azure eine Pipeline, der wir den neuen Wert übergeben und die baut dann ein komplett neues, 800MB großes Docker-Image, dass komplett identisch zum alten Image ist, mit Ausnahme dieser Umgebungsvariablen. Und dann wird das ganze via Kubernetes ausgerollt. Also ein neuer POD mit dem neuen Image gestartet und dann die alten sukzessive "durchgetauscht" - was schon mal seine Zeit dauern kann.
Und die Leute finden das nicht etwa verschwenderisch oder ineffizient, sondern normal. Kommentar eines Kollegen dazu: "So macht man das heute! In Zukunft werden wir ganze Rechenzentren weg schmeißen und neu bauen!"
Und wenn man sich die "Möglichkeiten" von Kubernetes so anschaut, stellt man fest: das ist so gewollt! Es gibt kein Feature, mit dem man so Kleinigkeiten mal eben auf alle Instanzen propagieren und ggfs. ein Reload/Restart der Applikation triggern kann! Ein Reload ist immer gleichzusetzen mit einem kompletten Deployment der Applikation. Also wieder: ein neuer POD mit dem neuen Image gestartet und dann die alten sukzessive "durchtauschen".

Da passt es ja dazu, dass man - zumindest in Azure - die Volumes, die man in die Container mounten kann, nicht kleiner als 1GB machen kann.
Du brauchst ein shared Volume für 720KB Config? Pech. Weniger als 1GB geht nicht.

Und so dauert eine Konfigurationsänderung von eigentlich wenigen Sekunden schon mal eine viertel Stunde oder mehr. Aber dafür verbrauchen wir dabei auch um Größenordnungen mehr Speicher und Rechenzeit!
Das muss dieser Fortschritt sein, von dem alle reden!
"Nehmt Docker, Kubernetes und die Cloud!", haben sie gesagt. "Damit wird alles besser, größer und schneller!", haben sie gesagt!
Nun zumindest größer wird der ganze Scheiß auf jeden Fall.


Passend dazu, zum Schluss noch einen Robotron-Witz:

Robotron hat einmal einen Draht entwickelt, der so dünn war, dass kein Messinstrument in der DDR genau genug war, um seine exakte Dicke zu bestimmen.
Also schickte man den Draht per Post nach Japan. Dummerweise hatte man vergessen den Brief beizulegen, was die Japaner mit dem Draht eigentlich machen sollten.
Ein paar Wochen später kam der Draht per Post aus Japan zurück. Anbei lag ein Schreiben der Japaner:
"Leider wussten wir nicht, was wir mit dem Draht machen sollten. Also haben wir ein Innen- und Außen-Gewinde rein geschnitten!"

Establishing a semi-automated gitflow/versioning-process with a maven-project

Foreword

Hey, Francisco :-) As promised: here is a description of what I implemented. With you as the primary audience, I decided to write it in English.

The Situation

We have a maven-project with lots of sub-modules. We like to call it "Klotz" (German for chunk)! There is a VCS (namely mercurial) and all the development happens in the branch "default". Every now and then a release-branch is created from the current default-status.
The version in the default-branch is updated once a year, and for the release-branches the versions are changed as follows:
find -name pom.xml -exec sed -i "s/19.0.0-SNAPSHOT/19.2.2.0-SNAPSHOT/g" {} \;

The Issues

  1. The default-branch is unstable from time to time, as every developer commits its work-in-progress to this branch.
  2. Working with branches in mercurial is a pain, especially as branches are global - so feature-branches are rarely used. (The bookmark-extension might be good enough for local work, but its not an adequate replacement)
  3. Bug-fixes are committed directly into the release-branch - without changing its version. So the version that's deployed on production might not be what you expect.

The Target

It is 2019! So it should be possible to do better!
We want:
  • a cleaner branching-model and workflow.
  • creating releases, hot-fixes and updating versions with the press of a button
  • enforce working with pull-requests

The Challenges

Due to the combination of maven and git(flow) several challenges arise.
The first being: having your code in well defined branches will not automatically update your versions in the pom.xml files. So we need a tool for that.
The second is: having different versions/pom.xml in the different branches makes merging quite difficult. So we need tool-support for this as well.
The third challenge is due to the deployment-process we have. The application is deployed based on the maven-artifacts in the company repository, and not the code itself.
So if you want to deploy the changes in a feature-branch, the version in the pom.xml files in this branch must be changed accordingly. But doing so prevents you from creating a simple Pull-Request from this feature-branch to development-branch. So - you guess it - we need tool-support for this case as well.

And speaking of Pull-Requests: of course the developers need to keep in mind the different versions in the branches when creating them. A PR from a branch based on a hotfix-branch against the development-branch for example might not be a good idea.

Implementing a Solution

The Tools...

As mentioned above, we need tool-support, and luckily there is one: gitflow-maven-plugin
The official repo/version still contains some bugs/short-comings. I created a fork with corresponding changes and fixes - hopefully they get merged upstream soon: https://github.com/Iridias/gitflow-maven-plugin/tree/current-status

Whats different:

  • pull dev-branch before pushing to avoid rejection due to remote-changes
  • support the option to not merge the release-branch into dev-branch
  • support processAllModules of versions-maven-plugin (important for child-modules without parent specified)
  • support separate additional merge-options on hotfix-finish and release-finish, for merging into production-branch and dev-branch respectively

With this plugin at hand, we're prepared to face the first requirement.

The "release with a press of a button"-requirement can be solved with JenkinsCI. If you're not using Jenkins, your alternative should provide similar capabilities for configuring freestyle-jobs. If not: why are you using it anyway?

To enforce the usage of pull-requests, we make use of the branching-restrictions of Bitbucket - because we already have Bitbucket available. But other alternatives, e.g. gitlab, rhodecode or azure devops have similar features - at least in the paid versions.

Now that we have our tools together...

Lets start!

Migration

First we need to setup the git-repository. To migrate the mercurial-repository to git, we use https://github.com/frej/fast-export
Then we need a development-branch: git branch development
And finally we add the Bitbucket repository as remote and push everything:
git remote add origin ssh://user@yourgitrepo/project.git
git push -u origin --all

Permissions

Now that the project is in the new git-repository, we can configure the branch-permissions: ..as well as the merge-checks: As you can see, we need an account for an ci-user. Because someone has to have the right to merge the changes into the corresponding branches, when using the gitflow-maven-plugin.
And maybe you, as admin, want to have such permissions too - in order to fix things that might go wrong.

Jenkins Jobs

For the next step, we need several Jenkins-Jobs.
To verify the application itself, we need jobs for building Pull-Request and the various branches:
  • Build-PR
  • Build-Develop
  • Build-Master
  • Build-Hotfix
  • Build-Feature
  • Build-Release
Next we need jobs to invoke the gitflow-maven-plugin:
  • Version-Create-Feature-Branch
  • Version-Finish-Feature-Branch
  • Version-Create-Hotfix-Branch
  • Version-Finish-Hotfix-Branch
  • Version-Create-Release-Branch
  • Version-Finish-Release-Branch
For the "Build-PR" Job, you'll need to use the bitbucket-pullrequest-builder-plugin (https://github.com/nishio-dens/bitbucket-pullrequest-builder-plugin) if you're using Bitbucket-Server!
This is due to a bug in Bitbucket-Server, that won't send/trigger a web-hook when a pull-request is updated: https://jira.atlassian.com/browse/BSERV-10279

For the following Jobs, you must use wildcards in the branch-specifier of the jenkins-git-plugin:
  • Build-Hotfix
  • Build-Feature
  • Build-Release
That's due to the fact, that the corresponding branches always have the same prefix, but the actual name differs and can't be known beforehand.
It's not a big deal, as it can be specified like follows: */hotfix-*
But the important thing is, that you must not delete the workspace after the build (Post-Build action)! You can, on the other hand, delete it before build! That's because Jenkins can't check for changes in the matching branches without the project being checked out in the workspace!

Deploy the maven artifacts

As we're using Sonatype Nexus Repository for our maven repository, I decided to also introduce nexus-staging-maven-plugin. It replaces the default deploy-maven-plugin and makes the process more robust, as it ensures, that all artifacts are deployed or none.
So if something horrible happens during the upload-process, you won't end up with an inconsistent state. The downside is: to have that feature also for release-artifacts (and not just snapshots) you'll need the paid professional version of Nexus Repository.
Use -DskipStaging=true as parameter for mvn deploy in the job that creates your release-artifacts - otherwise the build will break.
But, well, it's an improvement anyway, so it might be worth considering it.

The Jenkins-Jobs in detail:

Version-Create-Feature-Branch

Parameter:

Type: Text
Name: FeatureName

Shell Build-Step:

echo "Checking Feature-Name...";
if [[ ! "${FeatureName}" =~ ^[a-zA-Z0-9_\-]*$ ]]; then 
   echo "Invalid Feature-Name specified! Aborting!";
   exit 1;
fi

echo "Fetching repository...";
git clone ssh://USER@yourgitrepo:9999/prj/repo-name.git
cd repo-name

# gitflow:feature-start checks for existing branch in refs/heads/ instead of refs/remotes/origin
git branch -r | grep -v '\->' | grep -v 'master' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
git pull --all
git checkout staging

echo "Starting feature-branch...";
mvn -U -B gitflow:feature-start -DversionProcessAllModules=true -DinstallProject=false -DskipFeatureVersion=false -DallowSnapshots=true -DpushRemote=true -DfeatureName="${FeatureName}"
We're doing the git clone in the shell-script, because we have to do some additional git operations. If we'd use Jenkins' git-plugin, this would lead to an error like:
fatal: could not read Username for 'https://yourgitrepo'

As stated in the comment, the loop to create local tracking-branches is necessary, due to how the gitflow-plugin works. This applies to the following jobs as well - but I won't mention it again.

Version-Finish-Feature-Branch

Parameter:

Type: Extensible Choice
Name: FeatureName
Groovy Script:
def p = "/path/to/fetch-feature-branches.sh".execute()
p.waitFor()
File versions = new File("/path/to/git-feature-branch-names.txt")
return versions.readLines()
fetch-feature-branches.sh:
#!/bin/bash

cd /path/to/copy/of/your/repo-name
git pull --rebase --all
git remote prune origin
# dfb == deployable feature branch
git branch -r | grep "dfb-" | sed -e 's/.*dfb-//gi' > /path/to/git-feature-branch-names.txt

Shell Build-Step:

echo "Checking Feature-Name...";
if [[ ! "${FeatureName}" =~ ^[a-zA-Z0-9_\-]*$ || -z "${FeatureName}" ]]; then 
   echo "Invalid Feature-Name specified! Aborting!";
   exit 1;
fi

echo "Fetching repository...";
git clone ssh://USER@yourgitrepo:9999/prj/repo-name.git
cd repo-name
git branch -r | grep -v '\->' | grep -v 'master' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
git pull --all

echo "Finish feature-branch...";
mvn -U -B gitflow:feature-finish -DversionProcessAllModules=true -DinstallProject=false -DadditionalMergeOptions="-Xours" -DskipTestProject=true -DskipFeatureVersion=false -DallowSnapshots=true -DpushRemote=true -DfeatureName="${FeatureName}"

FIXME: merge-options need to be adapted according to Version-Finish-Hotfix-Branch

The Extensible Choice plugin and the script to fetch the existing feature-branches is not required - but its definitely more convenient for your users!
They can simply select the right feature-branch instead of determining the name them-self and struggle with typos - and trust me: they're always struggling with typos!

Version-Create-Hotfix-Branch

Shell Build-Step:

echo "Fetching repository...";
git clone ssh://USER@yourgitrepo:9999/prj/repo-name.git
cd repo-name
git branch -r | grep -v '\->' | grep -v 'master' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
git pull --all

echo "check for existing hotfix-branch..."
amount=`git branch -r |grep -i "hotfix-" | wc -l`
if [ $amount -gt 0 ]; then
   echo "Found $amount existing hotfix-branche(s)! Aborting...";
   exit 2;
fi

echo "creating hotfix branch..."
mvn -B gitflow:hotfix-start -DversionProcessAllModules=true -DuseSnapshotInHotfix=true
git push -u origin --all
Exit code to set build unstable: 2

Maybe you want to also use the Slack Notification Plugin.
There shall be only one hotfix-branch at a time - so no parameters needed.

Version-Finish-Hotfix-Branch

Parameter:

Type: Select
Name: MergeStrategy
Values:
AUTO
HOTFIX
STAGING
MANUAL

Shell Build-Step:

echo "Fetching repository...";
git clone ssh://USER@yourgitrepo:9999/prj/repo-name.git
cd repo-name
git branch -r | grep -v '\->' | grep -v 'master' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
git pull --all

echo "check for existing hotfix-branch..."
amount=`git branch -r |grep -i "hotfix-" | wc -l`
if [ $amount -eq 0 ]; then
   echo "No existing hotfix-branch found! Aborting...";
   exit 2;
fi

hotfixBranchVersion=`git branch -r |grep -i "hotfix-" | sed -e 's/.*hotfix-//gi'`

skipMergeDevBranch="false"
keepHotfixBranch="false"
devBranchMergeOptions="";

if [ "${MergeStrategy}" == "HOTFIX" ]; then
	devBranchMergeOptions="-Xtheirs";
elif [ "${MergeStrategy}" == "STAGING" ]; then
	devBranchMergeOptions="-Xours";
elif [ "${MergeStrategy}" == "MANUAL" ]; then
	skipMergeDevBranch="true";
	keepHotfixBranch="true";
fi

echo "releasing hotfix branch..."
mvn -U -B gitflow:hotfix-finish -DversionProcessAllModules=true -DskipTestProject=true -DallowSnapshots=true -DuseSnapshotInHotfix=true -DproductionBranchMergeOptions="-Xtheirs" -DdevBranchMergeOptions="${devBranchMergeOptions}" -DkeepBranch="${keepHotfixBranch}" -DskipMergeDevBranch="${skipMergeDevBranch}" -DhotfixVersion="${hotfixBranchVersion}"
Exit code to set build unstable: 2

Now things get a little tricky.
This operation has to merge changes into two branches: the master and the development-branch. Merging into the master is easy! There is just no way any conflicting changes could have gotten into the master-branch! So its save to enforce to always take changes from the hotfix-branch!

With the development-branch on the other hand, its not so easy!
The longer the hotfix-branch is open, the more likely it is, that there will be merge-conflicts - and we have to handle them!

The default-value of the MergeStrategy-parameter is AUTO. With this, the gitflow-plugin tries to merge the branches without any special treatment.
If that fails, then its the turn of the developers to decide how to solve the merge-conflicts - after all, they've produced them in the first place.
To make things easier, they have 3 options:
  • ignore the conflicting changes in the development-branch and just merge the changes from the hotfix-branch
  • vice-versa: ignore the conflicting changes in the hotfix-branch and just keep the changes in the development-branch
  • do not merge into development-branch at all and keep the hotfix-branch!
In the first two cases, you can just re-run the Job, with the MergeStrategy-parameter set to the corresponding option, and thats it.
In the last case ..well, you also re-run the Job, with the MergeStrategy-parameter set to the corresponding option - but one (or more) of the developers have to take care of merging the changes into the development-branch and deleting the hotfix-branch afterwards!
That's a little bit more work, as the developers have to respect the different versions in the pom.xml files (in the jenkins-job, the gitflow-maven-plugin will take care of this). But as mentioned before: they're responsible for the merge-conflicts they've introduced.

Version-Create-Release-Branch

Parameter:

Type: Extensible Choice
Name: ReleaseVersion
Groovy Script:
def p = "/path/to/fetch-git-version.sh".execute()
p.waitFor()
File versions = new File("/path/to/git-current-version.txt")
return versions.readLines()
fetch-git-version.sh:
#!/bin/bash

credentials=`cat ~/.bitbucket_user`
curl -u "$credentials" "https://yourgitrepo/projects/PRJ/repos/repo-name/raw/pom.xml?at=refs%2Fheads%2Fmaster" > /tmp/repo-pom.xml
grep -m 1 "" /tmp/repo-pom.xml | sed -e 's/.*version>\(.*\)<\/version>/\1/gi' > /path/to/git-current-version.txt

Parameter:

Type: Text
Name: DevelopmentVersion

Shell Build-Step:

echo "Checking target release-version...";
if [[ ! "${ReleaseVersion}" =~ ^[0-9]{2}\.[0-9]{1,2}\.[0-9](\.[0-9]+)?$ ]]; then 
   echo "Invalid Release-Version specified! Aborting!";
   exit 1;
fi

echo "Enforcing SNAPSHOT for dev-version...";
if [[ ! "${DevelopmentVersion}" =~ ^.*-SNAPSHOT$ ]]; then 
	DevelopmentVersion="${DevelopmentVersion}-SNAPSHOT"
fi

echo "Checking target dev-version...";
if [[ ! "${DevelopmentVersion}" =~ ^[0-9]{2}\.[0-9]{1,2}\.[0-9](\.[0-9]+)?-SNAPSHOT$ ]]; then 
   echo "Invalid Development-Version specified! Aborting!";
   exit 1;
fi

echo "Fetching repository...";
git clone ssh://USER@yourgitrepo:9999/prj/repo-name.git
cd repo-name
git branch -r | grep -v '\->' | grep -v 'master' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
git pull --all

echo "Starting release-branch...";
mvn -B gitflow:release-start -DversionProcessAllModules=true -DpushRemote=true -DuseSnapshotInRelease=true -DallowSnapshots=true -DcommitDevelopmentVersionAtStart=true -DreleaseVersion="${ReleaseVersion}" -DdevelopmentVersion="${DevelopmentVersion}" -DversionDigitToIncrement=2
In our company the colleagues want high flexibility regarding the version-numbers.
But to make things a bit easier and give them some support, we use the extensible choice plugin, to show the current version.
I'm sure, you can do the same thing completely in groovy, without a separate shell-script - but I found this solution shorter, more easy and especially more quick to implement!

In the build-step, the important part is, to check and enforce SNAPSHOT-version for development-branch! You can not rely on you users to get this right! Really!
For the release-branch the gitflow-plugin will take care of this (via parameter -DuseSnapshotInRelease=true)

Version-Finish-Release-Branch

Parameter:

Type: Select
Name: MergeStrategy
Values:
AUTO
HOTFIX
STAGING
MANUAL

Shell Build-Step:

echo "Fetching repository...";
git clone ssh://USER@yourgitrepo:9999/prj/repo-name.git
cd repo-name
git branch -r | grep -v '\->' | grep -v 'master' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
git pull --all

echo "check for existing release-branch..."
amount=`git branch -r |grep -i "hcf-" | wc -l`
if [ $amount -eq 0 ]; then
   echo "No existing release-branch found! Aborting...";
   exit 2;
fi

skipMergeDevBranch="false"
keepReleaseBranch="false"
devBranchMergeOptions="";

if [ "${MergeStrategy}" == "HOTFIX" ]; then
	devBranchMergeOptions="-Xtheirs";
elif [ "${MergeStrategy}" == "STAGING" ]; then
	devBranchMergeOptions="-Xours";
elif [ "${MergeStrategy}" == "MANUAL" ]; then
	skipMergeDevBranch="true";
	keepReleaseBranch="true";
fi

echo "Finish release-branch...";
mvn -B gitflow:release-finish -DversionProcessAllModules=true -DpushRemote=true -DuseSnapshotInRelease=true -DskipTestProject=true -DallowSnapshots=true -DcommitDevelopmentVersionAtStart=true -DproductionBranchMergeOptions="-Xtheirs" -DdevBranchMergeOptions="${devBranchMergeOptions}" -DkeepBranch="${keepReleaseBranch}" -DskipMergeDevBranch="${skipMergeDevBranch}" -DversionDigitToIncrement=2

Much like the "Version-Finish-Hotfix-Branch" - except that it'll check for existing release-branch and use the corresponding gitflow-plugin goal.
The concerns regarding merge-conflicts apply to this job as well.

Conclusion

With this Tools and Jenkins-Jobs at hand, you can leave release-management to a non-technical person in most cases. And even for the developers, things get a lot easier and more convenient.
And more important: your repository and releases will be in a consistent and reproducible state!

Any comments and improvements welcome!

Föderalismus der Streaming-Anbieter

Nachdem vor kurzem schon die Ministerpräsidenten der Bundesländer das Hohelied auf den Föderalismus gesungen haben, und dafür zu Recht kritisiert wurden, machen es die großen Contentproduzenten jetzt nach. Konzerne wie Disney verabschieden sich von Netflix und machen ihre eigene Abo-Platform auf. Der geneigte Zuschauer/Konsument muss also in Zukunft immer mehr Abos abschließen um seine Lieblingsfilme und Serien sehen zu können. Das dass kein guter Trend ist, muss sicher nicht noch extra betont werden. Aber erschreckend daran ist nicht nur die allgemeine Tendenz, sondern auch die Reaktionen darauf. Die beschränken sich nämlich weitestgehend auf “Dann saug’ ich halt Illegal. Dann merken die schon was sie davon haben!” Und während die Analyse, warum diese Tendenz schlecht ist, richtig ausfällt sind Schlussfolgerungen wie die eben genannte nicht nur kurzsichtig sondern gehen grundlegend in die verkehrte Richtung.

Abgesehen davon, dass es überaus unwahrscheinlich ist, dass die Anbieter “merken, was sie davon haben” – wäre es nicht viel sinnvoller, wenn es Leute gäbe, die Gesetze erlassen könnten, die die Anbieter zur Interoperabilität zwingen würden? Nennen wir diese Leute spaßeshalber “Politiker”. Diese könnten ein Gesetz erlassen, dass alle Anbieter verpflichtet, eine offene API anzubieten, über die man ihren Content kaufen oder leasen kann, und mit allen anderen Anbietern, die das wünschen, entsprechende Verträge/Peerings einzugehen. Und bei der Gelegenheit kann man gleich noch eine äquivalente Verpflichtung für die Socialmedia-Anbieter mit rein schreiben!

Alle FDP-Wähler und Teile der CDU (dazu zählt auch die SPD) werden jetzt schreien: “So eine Regulierung geht zu weit! Das schadet unserer Wirtschaft!” Halt das Standardargument derer, die erst den Mund aufmachen bevor sie denken. Sonst würden sie ja vielleicht merken, dass alle großen Socialmedia- und Contentanbieter in den USA sitzen und “unsere Wirtschaft” davon eigentlich nur profitieren könnte! Und für alle anderen, die ebenfalls immer noch der Meinung sind, dass das nicht geht, machen wir jetzt ein kleines Gedankenexperiment!

Wir stellen uns vor, dass es im Internet kein Peering zwischen den einzelnen Netzen und ISPs gäbe. Dann müsste ein Telekomkunde auch noch einen Vertrag mit Vodafone machen, wenn er Inhalte von Servern in deren Netz abrufen will. Und wenn der Betreiber dieser Server plötzlich zu Unitymedia wechselt, braucht der gebeutelte Telekomkunde auch noch einen Vertrag (mithin also ein Abo) mit Unitymedia!
Klingt absurd? Wäre es wohl auch. So absurd, dass die Netzbetreiber – in den meisten Fällen – gar nicht erst dazu gezwungen werden müssen, Peerings einzugehen.

Wenn also die Contentanbieter dazu gezwungen werden müssen – warum nicht? Ist ja nicht so, als gäbe es ein Naturgesetz, dass diese Anbieter machen dürfen, was sie wollen. Viele Leute scheinen sich schon so daran gewöhnt zu haben, in einer Demokratie zu leben, die bestimmte Strukturen aufweist, dass ihnen nicht (mehr) bewusst ist, dass Demokratie sich nicht darauf beschränkt alle vier Jahre zwei Kreuze auf einem Wahlzettel zu machen!
Demokratie meint “Herrschaft des Staatsvolkes”! Und wenn das Staatsvolk sich nicht länger von den Socialmedia- und Contentanbietern gängeln und ausbeuten lassen will, dann ist es nicht nur legitim, sondern vielmehr angebracht – ja, erforderlich – das zu fordern und letztlich in Gesetzesform zu gießen!

Und was den Faible unserer Ministerpräsidenten für Föderalismus angeht, so sollten sich diese mal klar machen, dass das Staatsvolk aus mehr besteht als nur den Einwohnern ihres jeweiligen Bundeslandes. Und das “Konkurrenzfähigkeit” beim Thema Bildung – und darum geht es denen augenscheinlich nämlich – nicht nur absurd ist, sondern zum Schaden für alle Bürger.
Der Föderalismus – nicht nur im Bildungssektor – wurde von den Alliierten (wieder) eingeführt, als Lehre aus der Nazizeit. Es sollte damit eine “zu Missbrauch verleitende Machtkonzentration” verhindert werden. Nun ist aber diese Gefahr heute nicht mehr gegeben. Unter anderem, weil der (Rechts)populismus heute dank der Digitalisierung, mehr Möglichkeiten hat, als ein Bildungssystem unter Kontrolle des Bundes jemals bieten könnte. Wir haben also keinen Vorteil mehr vom Bildungsföderalismus, dafür aber jede Menge Nachteile!
Aber dazu wollte ich eigentlich gar nicht so viel schreiben. Denn das hat Richard David Precht schon getan, der ein ganzes Buch zu dem Thema heraus gebracht hat: “Anna, die Schule und der liebe Gott

Also: statt illegal zu saugen, beschwert euch mal lieber bei eurem Abgeordneten darüber! Die meisten von denen sind durchaus offen für Argumente und bei weitem nicht so abgehoben und ignorant wie die Spitzen der etablierten Parteien!