Recent development was focused on building automated workflows that deal with the repetitive tasks related to the integration of new features into the codebase and streamlining updates to the app users.
preview of the created CI/CD pipeline
Branching strategy
As a first step, it was important to decide on the branching strategy. I settled upon GitLab Flow
with environment branches.
The other 2 popular workflows like GitHub Flow
and GitFlow
did not fit. As I needed something a bit more extensive than GitHub Flow
and GitFlow
seems a bit too complex when developing an app solo.
My branching setup below
- main - used as an alpha version of an app (for testing, pre-production)
- production - currently deployed version to end users
GitLab Flow has some nice conventions and rules that make it an interesting choice for me: (At least this is my interpretation of how it should work and how it is implemented)
- Possibly all changes (features, hotfixes, etc) start from a feature branch and go through all environments first before landing in
production
- Everything pushed to
production
branch is deployed to users - no
release
/hotfix
branches, straight and simple going from feature branch up to production through each environment
Semantic-release
Convenient package worth setting up. It simplifies application versioning according to the sem-ver standard.
New changes introduced into the system should be commited with a proper commit message and the rest - figuring out the next app version number is handled by semantic-release
.
For commit messages, I use commitizen
.
Once semantic-release is set up, triggering the command npx semantic-release
analyzes commit messages and changes the version number inside of package.json
. I believe, by default, it does only change the version number, but with plugins, the functionality can be extended.
Below, my current setup in .releaserc
{
"branches": [
{
"name": "production"
},
{
"name": "main",
"prerelease": "alpha"
}
],
"debug": "true",
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/npm",
{
"npmPublish": false
}
],
"@semantic-release/github",
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md"
}
],
[
"@semantic-release/git",
{
"assets": [
"package.json",
"CHANGELOG.md"
],
"message": "chore(release): create v${nextRelease.version}"
}
]
]
}
some of the above plugins are needed to allow semantic-release
to automatically commit and push changes to the repository (needed for CI workflow).
branches configuration defines channels for different versioning:
production
- main application versions (e.g.1.0.0, 1.3.0, 2.0.1
)main
- alpha channel for pre-release (e.g.1.0.0-alpha.1
)
GitHub Actions
With branching structure and semantic-release
in place, I setup multiple Github Actions triggered when a specific event happens on one of the branches such as:
- on
pull_request
creation intomain
branch - on
push
intomain
andproduction
branches - manual trigger on merging
main
branch intoproduction
(control over when deployment should happen)
All of the previously mentioned components work together to handle everything related to code integration to environment branches and deployment of application updates to end users. Development happens only at the bottom of the graph with feature branches (branching off of main
), everything else: running automated tests, updating version number, building application bundles, and deployment is handled by workflows.
An example workflow I have set up for production
release (whenever there is a push into the production
branch)
- Create Production release - triggers
semantic-release
to increase the app version number - Build App - builds applications for Windows, Linux, and macOS
- Modify updater.json - updates a gist needed for notifying users about the available update
- Merge production -> main - updates
main
(alpha) branch aftersemantic-release
version bump
Additional notes
The closer the change to production, the more tests
Ideally, the closer the change to production, the more testing should be performed. For example when finished working on a new feature, a pull request could trigger only unit tests
check for time efficiency. Moving up to the next environment to pre-production
/ production
should run integration tests
and e2e tests
to be sure that the application main functionality still works properly and integration won't break the current version.
I tried to add cypress e2e tests but it does not seem to work.
Official docs recommend using WebDriver Testing. Unfortunately, currently, I am not able to run tests on Mac as tauri-driver
is not available on this platform (dependency needed for running application in test mode)