-
Notifications
You must be signed in to change notification settings - Fork 1
Git Strategy
To keep our work structured and neatly organized, we use Git as the main software for storing our projects’ code and other types of files. Git is a software that offers a variety of functionalities built upon the base of file storage. With these functionalities we can retain an insight in every developer’s contributions to projects and review these with ease. Reviewing is important because of checking for the code validity, but also for learning from each other’s work.
A ‘trunk’ can be related to that of a tree, it is the basis whereupon a tree grows. The same goes for Git branches. The main branch, sometimes called master, is the trunk of a Git repository. The trunk can grow over time with the introduction of new features that are merged from different branches. The difference between trunk based development over other branching models is the way branches are being handled. A branch from the trunk is short lived and specially created for building a feature out of a user story. This means branches will exist for specific items that can be developed over a short period of time.
A summary:
"A source-control branching model, where developers collaborate on code in a single branch called ‘trunk’ *, resist any pressure to create other long-lived development branches by employing documented techniques. They therefore avoid merge hell, do not break the build, and live happily ever after." (Hammant, 2020)
During development we will make use of trunk based development to control our way of handling branches and workflows. The method states we use:
- A trunk branch called ‘main’ as the basis of a repository (not “master”)
- Short lived branches based upon handable user stories
- A release branch that contains stable releases of the repository’s software
Following these guidelines we have created a manifest on how to work with Git according to trunk based development.
GitHub is a website for using Git. It is basically a front-end for skipping through the different repositories inside a project. It also provides useful functions for interacting with repositories. Especially creating and collaborating on pull requests is very useful. Different developers can commit and comment on each other’s code that allows for quick reviewing. Merging is another functionality that can easily be executed via GitHub.
All projects should be publicly available on the GitHub DiSSCo Organisation page. Make sure you are added to this organisation as soon as possible.
We can create a new repository with GitHub. When creating a new repository in Git, the name of the repository can be determined by the name of the application as stated by the product owner. A newly created repository always contains one basic branch we call ‘main’. This branch is the trunk of the repository and will be the parent for all newly created branches.
Important: When creating a new repository, you must make sure your main branch is protected. This means after the initial commit, the main branch can not be modified without a pull request. More information about pull requests can be found later in this page.
A new repository should always contain a certain set of files that can automatically (or manually) be added to the main branch. These files include:
- A .gitignore file
- A README.md file
- A LICENCE file
- A
.github/workflows/build.yaml
file and a.github/workflows/cache-trivy.yaml
file for the CI/CD pipeline.
The gitignore file is mandatory. Even if the project does not make use of it, it will still indicate to other developers the repository does not negate anything specific.
The purpose of the README file is to give a general description of the application that is being built using the repository. A standard README file could include:
- The purpose of the application
- Requirements
- A basic explanation on how to use the application
- Usable parameters
- How to install
We protect the main branch so no non-authorised merges can take place. We force each merge to go through the Peer Review process described in this document. Be aware that only user with Admin
role can add/change branch protection. The following branch policies are active.
- At least 1 approval is necessary
- We dismiss stale pull requests approvals when new commits are pushed. Change in the code will require a new review
- We require the following status checks before merging:
- SonarCloud Code Analysis
- Conversation needs to be resolved before pull request can be merged
GitHub Desktop is an application you can install on your local system and lets you create commits with ease. Due to the visual text editor, writing commits is much less of a pain than the terminal equivalent. Furthermore, GitHub Desktop will allow you to look into your commit history, see changes to files and push your commits to your working branch. There is unofficial support for a Linux version of GitHub desktop here.
When you start to work on the user stories that are stated by the product owner, you will make use of the repository belonging to that user story. For every user story or a new branch will be made. Remember, according to trunk based development new branches will be short lived and specifically made for one user story. Important to recognize is that branches will always and only sprout from the main branch. This will make sure the structure will remain simple and clean.
When creating a new branch to work on a user story, we make use of standard naming conventions. The naming conventions indicate the purpose of a branch and the origin in the shape of the user story. When using the naming conventions we will make sure to work inline with the TeamWork application that provides the user stories and contextual information. Every user story in TeamWork contains an identifier we use to refer to the origin of the branch.
Below are the the main naming conventions that can be used (Bera, 2020):
feature: The feature naming convention indicates a branch whereupon a new feature is being developed. It is constructed using the feature keyword and the TeamWork identifier of the user story. Example: feature/{teamwork_item_id}
bug: The bug naming convention indicates a branch that is being used to resolve a bug inside developed code. It is constructed by using the bug keyword, followed by the TeamWork identifier of the user story or a file name. A file name can be used when a bug is not relevant to an user story anymore. Example: bug/{teamwork_item_id} or bug/{file_name}
release: The release naming convention indicates a branch containing a stable release of the application. Different from feature or bug branches, this branch can remain some time until a new release is planned and replaces the old one. Release branches are not commonly used when working in continuous development (Hammant1, 2020). Example: release/{version 0.1}
hotfix: A hotfix branch exists for quick bug fixes upon a release branch. This is the only time during trunk based development when a branch can be created from a branch different from the main trunk. Hot fixes can occur when release branches are as stable as they need to be to be classified as releases. Example: hotfix/{version 0.1.1}
When working on a branch, it is a good practice to make a commit when you finish a part of a user story. To maintain a structure in the way we commit, we have set a pair of guidelines for the provided description. This way we want to prevent vague commits so every developer has a change to look into the committed additions, changes or removals.
A general commit consists of two components: a title and a description.
Title: The title of a commit needs to be short but descriptive. It should give other developers just a general impression of what is in store. For example: when creating a calculator application, I commit the memory function, a fitting title would be: ‘Calculator memory function’ or just a part: ‘Calculator memory function part 1/3.
Description: The description should further define the contents of a commit. It can contain several lines of information but should remain brief. Try to list the important items you added, changed or removed for this commit and think of a suitable statement to accompany the list. Furthermore, try to write in a present tense, the commit has yet to be merged and could be backed up by another commit. The example below makes use of the calculator example:
This commit adds a refined way the Calculator can remember numbers for future usage. It changes the interface to suit the new functionality. It removes the old, outdated memory function. Adds: A new memory function for the Calculator Changes: The interface to support the new memory function Removes: The old function for remembering numbers
When your commits ‘fully’ implement the requested features of a user story, it is time to create a pull request. First off, make sure you have committed all necessary changes to your branch. Secondly, push your branch’s changes to the main branch, the trunk of the repository. Git will now allow you to create a pull request. When creating a new pull request, check if you select the correct branch and if all commits are present. Now insert a brief but direct description of the feature you are going to add with the pull request similar to how we shape up a description of a commit. Lastly add your co-developers as reviewers so they can review the code. Save the pull request.
What happens now? In the most favorable situation, the co-developers will review your code within a short period of time. This will allow for optimization of the code and give the opportunity to yourself and the others to learn from each other’s code. It is not necessary to review the code by all co-developers, but the aim is to let at least one developer review the code. Therefore it is not a good practice to merge your code into the main branch without any notice of other developers. When a developer has finished reviewing, you can optionally apply changes in a new commit. When satisfied and with permission of at least one other developer (preferably the senior developer), the pull request can be merged into the trunk.
In order to merge a pull request to the trunk, the following conditions must be met:
- Review and approval by at least one other developer
- No SonarCloud issues (SonarCloud, our code quality-checker, is discussed later in this document)
- 80% unit test coverage
GitHub actions are driven by workflows. We use GitHub actions to assess code quality, identify vulnerabilities, and to push code to the Elastic Container Registry on AWS.
To set up GitHub actions, create a build.yaml file with the following path: .github/workflows.
The build.yaml file in this repository is a good example of what needs to be implemented.
A push to main or an open pull request will trigger the actions. The first action is to build the pushed project and run all unit tests. Upon a successful build and run, our quality checker SonarCloud will run its quality analysis on the code and verify test coverage.
In this step, the compiler builds the code and runs all tests. This is the first line of defense against major issues. If this step fails, the pipeline will not continue.
Within DiSSCo, we use the tool SonarCloud as a code quality checker. SonarCloud scans code for security vulnerabilities and maintainability issues, such as Within DiSSCo, we expect all SonarCloud issues to be resolved before merging . SonarCloud analysis is triggered by the GitHub actions described in the previous section. You can also run Sonar code checks as you code using the SonarLint IDE Extension.
In Java, in addition to adding an action in your build.yaml
file, the following plugins and dependencies are required in your pom.xml
to allow SonarCloud scanning:
`
<sonar.organization>dissco</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.coverage.jacoco.xmlReportPaths>
../app-it/target/site/jacoco-aggregate/jacoco.xml
</sonar.coverage.jacoco.xmlReportPaths>
In JavaScript, create a sonar-project.properties file in the root directory of your project.
Trivy is an open-source tool that scans a project for Common Vulnerabilities and Exposures (CVEs). It checks your Software Bill of Materials using an up to-date CVE database and rates any vulnerabilities from Low to Critical severity. If an issue has been fixed in a later version, Trivy tells you which version you need to update to.
You can scan an image locally as well as incorporate Trivy into your GitHub workflow. To add Trivy to your workflow, you only need to add it to your build.yaml
file.
Trivy is a powerful tool for identifying vulnerabilities in a project. Sometimes, issues may be easily fixed by updating your dependencies. If an issue has not been fixed, however, you have a problem. Some CVEs may not be immediately addressed.
The DiSSCo pipeline involves two scans using Trivy. The first pass scans and identifies all CVEs at all severity levels. The second pass searches for High and Critical vulnerabilities and breaks the pipeline if any vulnerabilities are found. If there are issues that can not be fixed, you can add the CVE to a .trivyignore
file. The first pass should not ignore any CVEs.
If you add a CVE to the .trivyignore
, you must address the following issues (1-2 sentences max)
- Date CVE was identified
- Why it must be ignored
- Is it actively being amended/Is there a user story to fix this issue?