Table of Contents
When setting up a new Sesam project there are several tasks that needs to be done in order to ensure a good working environment for the project and its team. One thing is the Sesam installation itself, but in every software development project, concepts such as version control, continuous integration (CI) testing and automatic deployment are key factors for a successful project.
As a product, Sesam in itself does not contain any features that supports versioning of its configuration, local or automated CI testing and automatic deployment, but it provides a set of features (mostly through its API) that can be used in regular development tools or scripts for this purpose. This is flexible in terms of requirements set by the various customer, whose development platforms might vary. It does, however, mean that some time must be spent at the beginning of the project. In this document we will go through how to setup a Sesam project with these features, with examples and links to more in-depth documents.
Sesam will always store the previous version of a pipe or system that has been uploaded to the node, in the same way it stores the previous data for an updated entity in a dataset. These entities can be found in the ''system:config'' dataset, remember to check 'system' under 'Origin' to display the system datasets. However, this only lets you view the versions of the uploaded configurations, there is nothing you can do with these entities. As so, this cannot be regarded as a proper version control of the configuration (although you can always use this dataset to retrieve the current or a previous configuration of a pipe or system).
A Sesam configuration should hence always be stored in a separate version control system such as Git, Concurrent Versions System (CVS), Subversion, TeamCity, Mercurial or other. Git is the most commonly used and will be used in the examples in this document, but in terms of a project, the overall handling should be the same.
We will describe how to set up a version control repository for Sesam with Git in mind, but the overall way of how to work with branches and flows in another version control system should be the same.
Given that you already have a directory with a Sesam configuration that you want to put into a repository, there are some additional files and folders that needs to be added in order to add it to a Git repository.
The optimal directory structure of a Sesam Node project in Git should look like this:
my-project-directory
├ node
| ├ expected
| ├ pipes
| ├ systems
| └ variables
├ README.md
├ LICENSE
├ .gitignore
└ ++
In a normal workflow you should test your local changes before committing them to a repository. For setting up local testing of a Sesam configuration we recommend using the Sesam client, which is a command line tool for interacting with a Sesam service instance. To install and configure the Sesam client, read this document.
Testing a Sesam configuration should be done by running all the pipes in your local node until no pipes has any entities left in their queues, except the output pipes (which should either be disabled or unable to send data to their respective systems). Doing this manually could hence be a tedious job, especially if your configuration consists of numerous pipes, having to repeatedly start all or several pipes. The output of the endpoint pipes should then be verified against the expected output of the pipes. The Sesam client includes a nifty feature for this, both for running the pipes to their conclusion and verifying the end result.
However, for this to work, you have to configure your Sesam configuration with a test-file for each endpoint pipe. In the same directory as you have your 'pipes' and 'systems' folders, you need to add a new folder named 'expected', this will be the folder that contains the test files and the expected result for each pipe.
For each endpoint pipe in your Sesam configuration, you need to add two files (replace <name_of_pipe> with the name of the pipe):
- <name_of_pipe>.json
- <name_of_pipe>.test.json
The file with the .json extension is the file that shall contain the expected result. The file with the .test.json extension should contain the test configuration for that pipe, the available settings for this file are listed below:
Property | Description | Type | Required | Default |
---|---|---|---|---|
_id |
Name of the test.
|
string |
No
|
Name of the
.test.json file |
type |
Config type so that this later can just be part of the rest of the config.
|
string |
No
|
Test
|
description |
A description of the test.
|
string |
No
|
|
ignore |
If the output should be ignored during tests.
|
boolean |
No
|
false |
endpoint |
If the output should be fetched from a published endpoint instead.
|
string |
No
|
By default the json is grabbed from
/pipes/<my-pipe>/entities |
stage |
In which pipe stage to get the entities (source/before-transform/after-transform/sink).
|
string |
No
|
By default the stage is
sink |
file |
File that contains the expected results.
|
string |
No
|
Name of the .test.json file without .test (e.g. foo.test.json looks for foo.json).
|
pipe |
Pipe that contains the output to test.
|
string |
No
|
Name of the .test.json file without .test (e.g. foo.test.json looks for foo.json).
|
blacklist |
Properties to ignore in the output.
|
Array of strings |
No
|
[] |
parameters |
Which parameters to pass as bound parameters. Note that parameters only works for published endpoints.
|
Object |
No
|
{} |
Example:
{
$ cat foo.test.json
{
"_id": "foo",
"type": "test",
"file": "foo.json"
"blacklist": ["my-last-updated-ts"],
"ignore": false
}
}
If you need to pass various variations of bound parameters to the DTL, you just create multiple .test.json files for each combination of parameters.
Example:
{
$ cat foo-A.test.json
{
"pipe": "foo",
"file": "foo-A.xml",
"endpoint": "xml",
"parameters": {
"my-param": "A"
}
}
$ cat foo-B.test.json
{
"pipe": "foo",
"file": "foo-B.xml",
"endpoint": "xml",
"parameters": {
"my-param": "B"
}
}
}
This will compare the output of /publishers/foo/xml?my-param=A
with the contents of foo-A.xml
and /publishers/foo/xml?my-param=B
with the contents of foo-B.xml
.
All internal properties except _id
and _deleted
are removed from the output. Entities that has _deleted
set to false
will also be removed.
By default the entities are fetched from /pipes/<my-pipe>/entities
, but if endpoint is set it will be fetched from
/publishers/<my-pipe>/<endpoint-type>
based on the endpoint type specified. Note that the pipe needs to be configured to publish to this endpoint.
Example:
{
"_id": "foo",
"type": "test",
"endpoint": "xml",
"file": "foo.xml"
}
This will compare the output of /publishers/foo/xml
with the contents of foo.xml
.
Example:
{
"_id": "foo",
"type": "test",
"endpoint": "json",
"stage": "source"
}
This will compare the output of /pipes/foo/entities?stage=source
with the contents of foo.json
, useful when the pipe's sink strips away the "_id" property for example.
To test your Sesam configuration locally, run the following commmand:
sesam -vv test
If you haven't configured up the tests correctly or there are endpoint pipes that doesn't have any corresponding test file, you will be notified. If so, fix the missing tests and then run the commmand again. If the tests runs ok, you will get a message that all the tests has passed. If any test failed, you will be notified which test / pipe that failed and get a comparision of the expected result and the received result.
Automatic tests are needed to verify that your pull request does not break any existing pipes/flows inside sesam. To perform these types of tests we need to set up automatic tests. Since there are a few different CI/CD tools, we are going to explain a few of the most common ones.
In order to fully be able to have an automated CI test of your Sesam configuration, you need to have a designated CI node. The only purpose of the CI node is to provide an environment to test changes to the configuration so that it doesn't break.
When setting up automatic CI testing for a Sesam project, the following check should be required for the test to pass:
Another check that should be considered is:
In order to be able to test your Sesam configuration across the project team, you need to have a CI node. This node's sole purpose is to provide a Sesam environment to test changes to the configuration against. Tests will be run in the same way as you will test your configuration locally, except that it should be initiated from your automatic CI testing system instead.
It is important that when running testing against the CI node, only one test should run at the same time. When running a test against a CI node with the Sesam client, the configuration will be overwritten, which will cause a running test to fail or not to finish. Setting up your automatic CI testing, you need to have this in mind.
The CI node should be unable to write any data to another system, bear this in mind when configuring up the node. As the least safety regarding this, the node should not contain any variables or secrets necessary to connect to a system that the Sesam configuration usually will send data to.
Usually, the CI node could be a smaller instance than the production node, as the data used in the tests should not be of a considerable size.
This section describes how to set up Jenkins build with GCloud.
Jenkins is a CI/CD tool that does not support single build pipeline. The reason for the need of single build pipeline is that we upload the node config to a single node, if there are mulitple builds running at the same time there will be pushed multiple configs to the one node, which will result into tests not completing.
To set up builds in jenkins, you will need to add a few file to your repository my-project-directory
my-project-directory
├ deployment
| ├ jenkins
| | └ jobs
| | └ build
| | ├ dm-pod.yaml
| | └ Jenkinsfile
| └ sesam
| ├ cloudbuild.yaml
| ├ Dockerfile
| └ Readme.md
├ node
| └ ++
└ ++
dm-pod.yaml:
Describes what type of container that should be used in the build process.
apiVersion: v1
kind: Pod
spec:
containers:
- name: sesam-ci-container
image: eu.gcr.io/<your_gcr_repo>/sesam:<version_of_sesam_client>
tty: true
command:
- cat
resources:
limits:
memory: 6Gi
cpu: 1.7
Jenkinsfile:
The Jenkinsfile contains the stages that are supposed to run when the tests are running. The three default stages are:
#!groovy
pipeline {
options {
disableConcurrentBuilds()
}
agent {
kubernetes {
label "dm-${BRANCH_NAME}-${BUILD_ID}"
defaultContainer 'jnlp'
yamlFile 'deployment/jenkins/jobs/build/dm-pod.yaml'
}
}
environment {
Sesam_CI_node_jwt = credentials('Sesam_CI_node_jwt')
}
stages {
stage('Set Sesam env vars') {
steps {
script {
env.Sesam_CI_node = "datahub-****.sesam.cloud"
}
}
}
stage("Verify Sesam version") {
steps {
dir('') {
container('sesam-ci-container') {
sh "/./sesam -version"
}
}
}
}
stage("Run Sesam tests") {
steps {
dir('') {
container('sesam-ci-container') {
sh "export NODE='${env.Sesam_CI_node}'; export JWT='$Sesam_CI_node_jwt'; cd node && /./sesam -vv test -print-scheduler-log"
}
}
}
}
}
}
The files under the sesam folder here describes the files that should exist in the repository where jenkins is configured. Usually you do not have access to this repository, but you will need to provide these files.
cloudbuild.yaml:
cloudbuild.yaml A build config file defines the fields that are needed for Cloud Build to perform your tasks. You'll need a build config file if you're starting builds using the gcloud command-line tool or build triggers. You can write the build config file using the YAML or the JSON syntax.
steps:
- name: 'gcr.io/cloud-builders/docker'
args: [
'build',
'-t', 'eu.gcr.io/<your_gcr_repo>/sesam:latest',
'-t', 'eu.gcr.io/<your_gcr_repo>/sesam:1.16.1',
'.'
]
images:
- 'eu.gcr.io/<your_gcr_repo>/sesam'
tags:
- '1.16.1'
- 'latest'
Dockerfile:
The dockerfile describes the contianer that should run when the build process is executed. This container should be deployed to the repository that is used
FROM debian:9.9-slim
MAINTAINER [Your name] "your.email.address@domain.no"
ARG SESAM_CI_VERSION=1.16.1
SHELL ["/bin/bash", "-c"]
RUN apt-get update
RUN apt-get install -y wget
RUN set -x
RUN wget -O sesam.tar.gz https://github.com/sesam-community/sesam-py/releases/download/$SESAM_CI_VERSION/sesam-linux-$SESAM_CI_VERSION.tar.gz
RUN tar -xf sesam.tar.gz
RUN rm sesam.tar.gz
This dockerfile builds a container with the sesam client that is needed to execute the build. Replace [Your name] with the name of the person responsible for the build process, alongside his or hers email-address.
Azure DevOps is a bit easier to set up with single build pipeline. You will need to add the following config to your Azure DevOps setup under Pipelines
# Sesam AzureDevops Pipeline
trigger: none
pool:
vmImage: 'ubuntu-latest'
steps:
- script: |
wget -O sesam.tar.gz https://github.com/sesam-community/sesam-py/releases/download/$(sesam_cli_version)/sesam-linux-$(sesam_cli_version).tar.gz
tar -xf sesam.tar.gz
rm sesam.tar.gz
displayName: 'Download Sesam CLI'
- script: ./sesam -version
displayName: 'Verify Sesam CLI version'
- script: |
export NODE='$(node)'
export JWT='$(node_jwt)'
cd node
.././sesam -vv test -print-scheduler-log
displayName: 'Run Tests'
You will also have to add variables
sesam_cli_version = 1.16.1 (version of the CLI used in your project)
node = datahub-***.sesam.cloud (the node url to the CI server used in your project)
node_jwt = bearer ****** (jwt for the CI server used in your project)
Branch permissions are also needed to not be able to merge a Pull Request unless the tests have completed successfully. These permissions needs to be set under
Repos->Branches->More->Branch Policies->Add Build Policy
Use the default settings.
You will also need to turn on Require a minimum number of reviewers
, and set it to 1
and Check for linked work items
. This makes it Easier to trace and close the tasks/issues for the Pull Request.
These settings are required for your main branches develop
and master
.
Since the trigger
parameter is set to none
, the build process will only trigger on PR's. There is no need to build master
and develop
after merge.
Note if there is support for parallel builds on the agent pool you will need to disable this so that only one build process runs and the second build is queued up. This can be done by adding capability on the build agent. You will also need to add a this in the yaml file to enable this. Add user capabilities in the agent pool (key value pair), key = Limit and value = DisAbleParallel
Your yaml file:
pool:
name: {agent pool name}
demands: Limit -equals DisAbleParallel
Your configuration will end up being in your repository under the main directory:
my-project-directory
├ node
| ├ pipes
| ├ systems
| ├ expected
| └ ++
└ azure-pipelines.yml
Whether setting up automatic deployment of a Sesam configuration is a disputed theme. In normal usecases, you would like to have more control of when a release is deployed to a production environment, especially in larger or business critical installations. But if you decide upon setting up automatic deployment of your Sesam configuration, it can be done in several ways.
One way to easy set up automatic deployment of your Sesam configuration is to use the GitHub Autodeployer microservice. This is a microservice that you can configure in your Sesam node that at given intervals will check the configured Git repository for changes. If any changes to the repo is found, it will read the configuration from the repo and deploy it to the node.
In the configuration you can either specify a branch or a tag. Use tags when deploying a release branch with a version number (which should be a tag in the repo). If no tag is specified, the autodeployer will use the branch variable, which defaults to "master" if not set. Depending on the specified branch or tag, the autodeployer will compare the current Sesam configuration against the configuration in the repository, if any changes are found, the deployer will read the updated configuration from the repository and deploy it to the node.
WARNING! Any existing pipes and systems will be overwritten when the autodeployer deploys a new version to the node. Any pipe or system configuration in the node not existing in the branch will be removed.
Also note that the autodeployer only deploys a configuration, it does not do any other actions on the node, such as starting or resetting pipes. If any pipes need to be reset as part of the deployment for instance, the autodeployer will not perform any such task and this must be done manually.
Information on how to configure the GitHub Autodeployer microservice can be found at its corresponding GitHub page: https://github.com/sesam-community/github-autodeployer.
Automatic deployment could also be done using the same tools you use for your automatic CI testing, like Jenkins or Azure DevOps. For this, you need to change the step for testing with a step for deploying the given branch. See the document about the Sesam client for the correct parameters to use.
Remember to add parameters to your configuration for which release version to deploy.
The initial repository should contain two main branches with an infinite lifetime. Parallel to the master branch, another branch should exist, called develop.
master
develop
We consider origin/master to be the main branch where the source code always reflects a production-ready state. We consider origin/develop to be the main branch where the source code always reflects a state with the latest delivered development changes for the next release. Some would call this the “integration branch”.
When the source code in the develop branch reaches a stable point and is ready to be released, all of the changes should be merged back into master branch and then tagged with a release number.
Therefore, each time when changes are merged back into master, this is a new production release by definition. We follow this practice very strictly.
Supporting branches
Next to the main branches master and develop, our development model uses a variety of supporting branches to aid parallel development between team members, ease tracking of features, prepare for production releases and to assist in quickly fixing live production problems.
Unlike the main branches, these branches always have a limited life time, since they will be removed eventually.
The different types of branches we may use are:
Feature branches
Release branches
Hotfix branches
Each of these branches have a specific purpose and are bound to strict rules as to which branches may be their originating branch and which branches must be their merge targets.
Branch Type | May branch off from | Must merge back into | Branch naming convention |
Feature | develop | develop | Aything except master, develop, release-, or hotfix- |
Release | master | develop and master | release-* |
Hotfix | master | develop and master | hotfix-* |
One exception to the rule here is that, when a release branch currently exists, the hotfix changes need to be merged into that release branch, instead of develop.
For information on how to set up the master branch in Git, read here. For information on how to set up the development branch in Git, read here.
You should use semantic versioning for any of your releases to production.
Given a version number MAJOR.MINOR.PATCH, increment the:
Based on the structure described above you should navigate to the project root (my-project-directory) and run the following command:
git init
Then your directory will become a Git repository (repo). After you've done this, go to your source control website (i.e. github.com). Here you will need to create a new repo under your organisation. Make sure that you don't initialize the repo from the website. When the repo has been created you should be presented with a url to use. (i.e. git@github.com:my_org/my_repo.git) Connect the Git repo to your local repo:
git remote add origin git@github.com:my_org/my_repo.git
Push your local repo to Git:
git push -u origin master
(Tip: Sometimes you need to first add and commit README.md file, to make your first push to remote repo.)
Since we want to use the master branch as the production branch, we need to setup a new branch called develop to use for development. To do this we need to type the following in terminal:
git checkout -b develop
This creates a new branch called develop that mirrors master. To push it to Git:
git push --set-upstream origin develop
Now you should have two branches in Git. Before we go forward you should go to your repository settings (in Github or equal) and configure the default branch to be develop. After that you should set both master and develop branches as protected. This means that you won't be able to directly push commits to these branches. We want to force users to do that by creating pull requests.
More information about pull requests can be read in this document https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request.
Creation:
$ git checkout -b myfeature develop
Switched to a new branch "myfeature"
Incorporating a finished feature on develop :
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop
Tip: The --no-ff flag causes the merge to always create a new commit object, even if the merge could be performed with a fast-forward. This avoids losing information about the historical existence of a feature branch and groups together all commits that together added the feature.
Creation :
$ git checkout -b release-1.0.0 master
Switched to a new branch "release-1.1.0"
$ ./bump-version.sh 1.1.0
Files modified successfully, version bumped to 1.1.0
(Here, bump-version.sh is a fictional shell script that changes some files in the working copy to reflect the new version. (This can of course be a manual change—the point being that some files change.) Then, the bumped version number is committed.))
$ git commit -a -m "Bumped version number to 1.1.0"
[release-1.2 74d9424] Bumped version number to 1.1.0
1 files changed, 1 insertions(+), 1 deletions(-)
Finishing a release branch:
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff release-1.1.0
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2
The release is now done, and tagged for future reference. To keep the changes made in the release branch, we need to merge those back into develop, though:
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.1.0
Merge made by recursive.
(Summary of changes)
This step may well lead to a merge conflict (probably even, since we have changed the version number). If so, fix it and commit. Now we are really done and the release branch may be removed, since we don’t need it anymore:
$ git branch -d release-1.1.0
Deleted branch release-1.1.0 (was ff452fe).
Creation:
$ git checkout -b hotfix-1.1.1 master
Switched to a new branch "hotfix-1.1.1"
$ ./bump-version.sh 1.1.1
Files modified successfully, version bumped to 1.1.1.
$ git commit -a -m "Bumped version number to 1.1.1"
[hotfix-1.1.1 41e61bb] Bumped version number to 1.1.1
1 files changed, 1 insertions(+), 1 deletions(-)
Finishing a hotfix branch:
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff hotfix-1.1.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.1.1
Next, include the bugfix in develop too:
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.1.1
Merge made by recursive.
(Summary of changes)
Important: The one exception to the rule here is that, when a release branch currently exists, the changes in the hotfix needs to be merged into that release branch, instead of develop.
$ git branch -d hotfix-1.1.1
Deleted branch hotfix-1.1.1 (was abbe5d6).
When you want to start working on a new feature, you should start by creating a new feature branch. When checking out the new branch, make sure that you have the latest version of the source branch. Generally new feature branches should be checkout out from the develop branch. Generally we want feature branches to be named after the relevant task/issue id. You can read more about how to name the branches correctly in Branch naming.
git checkout master
git pull
git checkout -b <issue_id>
Now you have a feature branch to start working on. Next you should proceed to read about how to write commit messages.
There are some simple rules to follow. A properly formed Git commit subject line should always be able to complete the following sentence:
If applied, this commit will <your subject line here>
For example, a commit message like "update the rdf:type in proarc-document pipe" will result in:
If applied, this commit will update the rdf:type in proarc-document pipe
Try to avoid having commit messages like: "Fixed bug with Y". This is a non-imperative form and when we apply the imperative mood to the text "Fixed bug with Y" the sentence will result into:
If applied, this commit will Fixed bug with Y.
An example of a commit message with a task/issue id:
AB-123: Update requirements to fix deprecation error
In this example AB-123 is the issue id. When this pattern is utilized, it makes it much easier to determine why a commit where applied regardless of branch.
At this point you should have a feature branch with some changes that you would like to merge into your develop branch. If you've been working on your feature branch for a while, it might be a good idea to merge the develop branch back into your feature branch before creating the pull request.
git fetch develop
git merge develop
When doing this, you might encounter conflicts. To resolve these, go to the mentioned files and look to see what version of the code is the one that should be kept. Edit out the code that shouldn't be kept and add the files:
git add <my_file_with_conflict>
git merge --continue
When this is done, you should push your latest changes to github or similar and create a pull request with their GUI.
Release branches contain production ready new features and bug fixes that come from a stable develop branch. In most cases, the master branch is always behind the develop branch as new features will first be pushed to that branch. After finishing release branches, they get merged back into develop and master branches so that both of these branches eventually will match each other.
We can split a release into two different categories, minor releases and major releases. These two different release types are defined by how big the change to master is.
Usually you would have feature releases as minor releases, while major releases would include big changes like restructuring pipe-combinations and merge rules.
Hotfixes are used to deploy critical changes to production. It also includes small fixes to pipes (as long as it is something that already is deployed to production*). When creating a hotfix you should branch off from master branch, merge into master and back to develop so that both of the main branches gets the update.
*Small fixes will often be forgotten and end up in the develop branch without being added to a release. This validates having small fixes/changes to pipes/systems as a hotfix and not only beeing added as a part of a release.
Tags are a simple aspect of Git, they allow you to identify specific release versions of your code. You can think of a tag as a branch that doesn't change. Once it is created, it loses the ability to change the history of commits.
In a Sesam perspective we add tags if we need to revert to a previous version, if we figure out that a release or hotfix is not working as expected.
Tags are also a good way to have different versions of config in different environments. A good example of this is if multiple releases are done, but one version has not been tested to the full extent. You can run one tag in the staging environment, and another in the production environment.
For tags we use semantic versioning. You can read more about semantic versioning here semantic versioning.
Variable files are often added to Git so that we are able to track and keep control of existing environment variables. Environment variables should exist in the repository under the folder nodevariables. You should have 3 files:
-variables-dev.json
-variables-staging.json
-variables-prod.json
These three files should reflect what the variables are in your/the projects node environment. Changes/addition of environment variables should be added to Git with the feature you are editing or in the hotfix you are creating.
When creating a release you must remember to add the updated files to your release branch.
Secrets should ideally be saved in a keymanager, and not in Git.
First off we will need to create a ticket for your release so we get a task number. This is done in your projects issuetracker. In this case the ticket created is named AB-2324.
When you are ready to deploy your changes to production, you will have to create a release to master.
This is done with:
git checkout master
git checkoub -b release-*.*.*
(creating release branch that is semantically versioned)
git checkout develop -- .
(checkout all files from the develop branch and add it to your current release-*.*.*. )
this will add all the expected files that you have in your expected folder as well.
you should now run tests to see if everything works as expected.
sesam -vv test
If the result of the test comes back as OK, you are ready to commit.
git add .
(adds all files)
git commit -m "AB-2324: add all files from develop to release-*.*.*"
(When using task number AB-2324 you will create a reference to the ticket and in some issuetrackers you will be able to see a link to the Pull request)
git push
You are now ready to create the pull request in your version control system. This will trigger your build process to trigger a new build. When your build has completed successfully, you are ready to merge your release branch into master.
When the merge is completed you can now tag your release in your version control system to release-..*
When you can't deploy everything from develop into production, and you would like to release some feature that is completed. you will need to find the config files manually. You will need to figure out what pipes/systems that are ready for deploy, but you would still need to go through the same process as noted in the "When you want to deploy all changes in develop into master" stage.
git checkout master
git checkout -b release-*.*.*
(creating a branch based on master branch)
You will now have to have a list of the pipes/systems you would like to deploy.
Considering you are in the node folder:
git checkout develop pipes/<my_pipe_name> systems/<my_system_name>
this will only checkout the pipes/systems that you would like to be included in this release. Note that your tests will fail now, since you have not checked out the corresponding tests to the pipe you just checked out.:
git checkout develop expected/<my_pipe_name>.*
*(this will check out the two expected files that are in relation to the pipe you have checked out)*
sesam -vv test
(run the test to see if testresults are ok)
Remember to checkout the environment config files as well.
If everything is ok, you can now add and commit the files to your new release-branch.
git add .
git commit -m "AB-2324: adding specific files from dev to my new release-*.*.*"
git push
You are now ready to create the pull request in your version control system. This will trigger your build process to trigger a new build. When your build has completed successfully, you are ready to merge your release branch into master.
When the merge is completed you can now tag your release in your version control system to release-..*. You are now ready to merge back to develop.
Often you might end up having merge conflicts when you merge back to develop. You can read more about this in Resolve common problems.
When we're creating a new feature branch, we want the branch to be named after the relevant issue/task id. Lets say we have a ticket called AB-123. Then you would create your branch like this:
git checkout develop -b AB-123
When you want to create a new release to deploy, we want releases to use semantic version numbers. This makes it easier to determine what type of change a release involves.
To determine the next version number, you can follow this diagram:
When you have worked on a release, there will be cases when your develop and master branch diverges. Lets say you have not created a release in a long time. You will end up having a lot of new features in your develop branch that does not exist in master.
Even though new pipes and systems will not have a merge conflict, you will have cases where your global pipes have many new features in dev that does not exist in master. You will need to fix the release so that you only add the features you want to release. An example of this follows:
your-global-pipe-in-dev:
"datasets": ["dataset_foo", "dataset_bar", "dataset_baz", "dataset_foobar", "dataset_foobaz"]
While your global-pipe in master looks like:
"datasets": ["dataset_foo", "dataset_bar", "dataset_foobar"]
Your feature with "dataset_baz"
is now finished and you will only want to release this, and not all the others that are not finished. You will have to do changes as a commit in the release branch to get the correct structure in your master branch.
And your global pipe should look like this:
"datasets": ["dataset_foo", "dataset_bar", "dataset_foobar", "dataset_baz"]
You can see that the order in your dev global pipe vs your master global pipe is diverging now. Since our Master branch is the Main branch, and develop is continually under development we will need to restructure develop to match the newest release.
dev (currently):
"datasets": ["dataset_foo", "dataset_bar", "dataset_baz", "dataset_foobar", "dataset_foobaz"]
master (after changes to release-branch)
"datasets": ["dataset_foo", "dataset_bar", "dataset_foobar", "dataset_baz"]
When this type of change is merged back to develop you will get merge conflicts that needs to be resolved. The order that is primary choice is the changes from master. Which results into dev looking like:
dev (after merge back from release branch):
"datasets": ["dataset_foo", "dataset_bar", "dataset_foobar", "dataset_baz", "dataset_foobaz"]
master (after changes to release-branch)
"datasets": ["dataset_foo", "dataset_bar", "dataset_foobar", "dataset_baz"]
You can see that the order is changed in develop to match what is in master.
The following strategy will revert a merge commit. This can be used in any branch where you want to undo a merge.
git checkout develop -b revert/my_feature_branch
Now you will need to find the commit hash of the merge commit. This can be found with "git log". Then use the hash in the next command:
git revert -m 1 <hash of merge commit>
Now you have a branch that reverts the merge. Use that for a new pull request against develop. If you want to fix the feature you can start with following steps after you have merged the previous revert.
git pull develop
..
git checkout develop -b my_feature_branch
..
git revert -m 1 <hash of revert commit from earlier>
Now you have a branch where the reverted changes have been re-applied. Now you can continue working in the feature branch and fix the issues that required the revert in the first place. When your changes are done, you can treat this branch as a regular feature branch and create a new pull request to merge your changes.
When this happens, you most likely have two choices. Either revert the change (see We found a bug in recently merged PR or fix it directly in production with a hofix branch.
To fix it directly in production, use the following steps:
git checkout master -b hotfix_for_my_feature
.