Development Workflow

1. Introduction

This guide describes the development workflow for Event and Membership Management projects. We follow the GitFlow branching model, automated through the GitFlow Maven Plugin.

1.1. GitFlow Origins

GitFlow was originally conceived by Vincent Driessen in his influential 2010 blog post "A successful Git branching model".

For an excellent introduction to GitFlow concepts with visual diagrams, see the Atlassian GitFlow Tutorial.

1.2. Core Principles

Stable develop

The develop branch should always be buildable with all tests passing

Production-ready main

The main branch contains only released, production-ready code

Feature isolation

New features are developed in isolated branches

Release preparation

Releases are prepared in dedicated branches for stabilization

2. Branch Strategy

main     ─────●───────────────────●──────────────────────●────►
              │                   ↑                      ↑
              │            release/1.2.0                 │
              │                   ↑                      │
              │                   │              release/1.3.0
              │                   │                      ↑
develop  ─────●───●───●───●───●───●───●───●───●───●───●──●───►
                  ↑   ↑   ↑
          feature/  feature/  feature/
          ADO-101   ADO-102   ADO-103

2.1. Branch Types

Branch Type Purpose Naming Convention

main

Production-ready releases

main (protected)

develop

Integration branch for features

develop (protected)

Feature

New functionality

feature/ADO-{id}-GitFlow development process for Event and Membership projects

Bugfix

Bug fixes for develop

bugfix/ADO-{id}-GitFlow development process for Event and Membership projects

Release

Release preparation

release/{version}

Hotfix

Emergency production fixes

hotfix/{version}

3. Feature Development

3.1. Creating a Feature Branch

# Ensure develop is up to date
git checkout develop
git pull origin develop

# Create feature branch
git checkout -b feature/ADO-123-add-user-authentication

3.2. Branch Naming Convention

feature/ADO-{work-item-id}-{brief-description}
  • Always reference the Azure DevOps work item ID

  • Use lowercase with hyphens

  • Keep the description brief but descriptive

Examples
feature/ADO-123-add-user-authentication
feature/ADO-456-refactor-payment-service
bugfix/ADO-789-fix-login-redirect

3.3. Commit Messages

ADO-{id}: Brief description (max 72 chars)

Optional longer explanation of:
- What changed
- Why it changed
- Notable implementation details
Examples
ADO-123: Add JWT authentication to login endpoint

Implement JWT-based authentication using Spring Security.
- Added JwtTokenProvider service
- Configured SecurityFilterChain
- Added login and refresh token endpoints

3.4. Formatting and the Pre-commit Hook

The Angular repositories — membership-ui, event-registration-ui and event-admin-ui — format staged files on commit, using husky, lint-staged and Prettier. The Java-only repositories have no hook.

The hook is a convenience, not the gate. It runs only when the checkout has its tooling, and otherwise skips with a notice instead of blocking the commit:

  • In a git worktree it does not run at all in membership-ui and event-registration-ui. Husky 9 points core.hooksPath at .husky/_, which npm install generates per checkout, and a worktree does not have one.

  • event-admin-ui stays on husky 7, because its build toolchain is Node 16 and husky 9 requires Node 18. Husky 7 points core.hooksPath at the tracked .husky directory, so git runs the hook in a worktree too — where it finds no node_modules and skips.

  • In a fresh clone before npm install, or from a client without node on PATH, it prints a notice and exits.

  • It never installs, builds or downloads anything.

Git hooks do not load ~/.bashrc, so for nvm’s node to be found by IDEs, GUI clients and non-interactive shells, put this in ~/.config/husky/init.sh, which husky 9 sources before every hook. Husky 7 does not read it, so in event-admin-ui such a client skips the hook instead:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

The gate is the Format job in the pull-request pipeline, from the shared check-format.yml workflow. It stages the pull request’s changes as one commit, runs the repository’s own lint-staged over them, and fails if anything would be rewritten. It therefore applies exactly the hook’s rules — the same glob, .prettierignore and commands.

Two consequences to expect:

  • Only changed files are checked. Formatting drift in untouched files is left alone.

  • Touching a file formats all of it. lint-staged formats whole files, so editing a file with pre-existing drift produces a whitespace-only diff across it — expected, and reviewable with git diff -w. Where the hook did not run, format the file yourself with npx prettier --write <file> before pushing.

After pulling a change that upgrades husky, run npm install once so the checkout’s hooks path is updated.

3.5. CI/CD During Feature Development

  • No CI during feature branch commits - Tests are not run on every push

  • Tests run when PR is created - Full test suite executes on PR creation/update

  • Merge requires passing tests - Unless overridden by an authorized person

3.6. Creating a Pull Request

When your feature is ready for review:

  1. Push your feature branch to origin

  2. Create a PR targeting develop

  3. Fill in the PR template with:

    • Summary of changes

    • Link to ADO work item

    • Testing performed

    • Checklist completion

4. Release Process

4.1. Overview

A release takes three steps, and only the middle one is hand work:

  1. Start — the manual-release-start.yml workflow cuts release/X.Y.Z from develop and opens a pull request into main.

  2. Prepare — release notes in RELEASE.md, and any fix the release needs, are committed to the release branch.

  3. Merge — merging the pull request triggers push-main.yml, which publishes and deploys the release, then finishes GitFlow: tags main, merges the tag back into develop, and bumps develop to the next SNAPSHOT.

4.2. Starting a Release

Confirm first that the develop pipeline is green on the commit you intend to release, and that no other release/ or hotfix/ branch is open — release-finish expects exactly one.

Run the GitFlow Release Start workflow from the Actions tab, or:

gh workflow run manual-release-start.yml --repo christhonie/<repo> --ref develop -f version=X.Y.Z

Use the version develop is already on, without -SNAPSHOT. The input is free text, and cutting a higher number strands the one consumers have been pinning against — see CI and Release Pipeline Traps.

The workflow:

  • Creates release/X.Y.Z from develop and pushes it

  • Sets <revision> to X.Y.Z on the release branch only

  • Opens a pull request Release X.Y.Z from the release branch into main

develop is not changed when a release starts. Its version moves when the release finishes.

4.3. Release Branch Activities

During the release phase:

  • Release notes in RELEASE.md, appended as a new ## X.Y.Z section

  • Fixes the release needs before it ships

  • Configuration adjustments

What runs on the release branch is deliberately little:

  • The push that creates the branch is made with GITHUB_TOKEN, which triggers no workflows.

  • Repositories with a push-release.yml run the back-end tests on later pushes — but it ignores *.md, so a notes-only commit runs nothing.

  • The SPA and plugin repositories have no release-branch workflow at all.

  • pr-non-main.yml ignores pull requests into main, and main has no required checks.

A release pull request that reports no checks is therefore normal. The code was tested by the develop pipeline before the release was cut.

4.4. Completing a Release

When the release is ready, merge the pull request into main. push-main.yml then runs:

  1. Production build with the prod Maven profile

  2. Docker image build and push

  3. Helm chart package and push

  4. Stage deploy — the stage ArgoCD manifest is bumped to the new chart version

  5. GitFlow release-finish, which:

    • Tags main with X.Y.Z

    • Merges the tag into develop, resolving a conflict confined to <revision> automatically

    • Bumps develop to the next SNAPSHOT (see Version Bumping)

    • Deletes the release branch

Verify the finish: the tag exists, develop carries Merge tag 'X.Y.Z' into develop followed by the Release now finished bump, and the release branch is gone.

If the Gitflow job fails, the artefact has usually already shipped from the jobs ahead of it. Do not re-run the job — finish the remaining steps by hand, as described in CI and Release Pipeline Traps.

5. GitFlow Maven Plugin

5.1. Overview

The GitFlow Maven Plugin automates GitFlow operations, ensuring consistent version management and branch handling.

Best Practice: Configure the plugin in the parent POM to ensure consistency across all projects in the organization.

5.2. Plugin Configuration

Reference implementation from event/pom.xml:

<plugin>
  <groupId>com.amashchenko.maven.plugin</groupId>
  <artifactId>gitflow-maven-plugin</artifactId>
  <version>${gitflow-maven-plugin.version}</version>
  <configuration>
    <!-- Whether to print commands output into the console -->
    <verbose>false</verbose>
    <!-- Whether to fetch remote branch and compare it with the local one -->
    <fetchRemote>true</fetchRemote>
    <!-- Whether to call Maven install goal during the mojo execution -->
    <installProject>false</installProject>
    <!-- Whether to push to the remote for release/feature/hotfix start -->
    <pushRemote>true</pushRemote>
    <!-- Whether to skip changing project version on feature branches -->
    <skipFeatureVersion>true</skipFeatureVersion>

    <!-- CI-friendly versioning support -->
    <versionProperty>revision</versionProperty>
    <skipUpdateVersion>true</skipUpdateVersion>

    <!-- Git flow configuration -->
    <gitFlowConfig>
      <productionBranch>main</productionBranch>
      <developmentBranch>develop</developmentBranch>
      <featureBranchPrefix>feature/</featureBranchPrefix>
      <releaseBranchPrefix>release/</releaseBranchPrefix>
      <hotfixBranchPrefix>hotfix/</hotfixBranchPrefix>
      <supportBranchPrefix>support/</supportBranchPrefix>
      <versionTagPrefix />
      <origin>origin</origin>
    </gitFlowConfig>

    <!-- Git commit messages -->
    <commitMessages>
      <featureStartMessage>Feature start. Set feature version to @{version}.</featureStartMessage>
      <featureFinishMessage>Feature finished. Development version updated to @{version}.</featureFinishMessage>
      <hotfixStartMessage>Hotfix start. Set hotfix version to @{version}.</hotfixStartMessage>
      <hotfixFinishMessage>Hotfix now finished. Development version updated to @{version}.</hotfixFinishMessage>
      <releaseStartMessage>Release start. Set release version to @{version}.</releaseStartMessage>
      <releaseFinishMessage>Release now finished. Development version incremented to @{version}.</releaseFinishMessage>
      <releaseFinishMergeMessage>Released v@{version}</releaseFinishMergeMessage>
      <tagHotfixMessage>Tag hotfix @{version}</tagHotfixMessage>
      <tagReleaseMessage>Tag release @{version}</tagReleaseMessage>
    </commitMessages>
  </configuration>
</plugin>

5.3. Key Configuration Options

Option Description

versionProperty=revision

Uses CI-friendly ${revision} property for versioning

skipFeatureVersion=true

Don’t modify version when creating feature branches

pushRemote=true

Automatically push branches and tags to remote

skipUpdateVersion=true

Works with flatten-maven-plugin for CI-friendly builds

5.4. Plugin Goals

Goal Description

gitflow:feature-start

Create a new feature branch from develop

gitflow:feature-finish

Merge feature branch back to develop

gitflow:release-start

Create release branch, update versions

gitflow:release-finish

Merge to main, tag, merge back to develop

gitflow:hotfix-start

Create hotfix branch from main

gitflow:hotfix-finish

Merge hotfix to main and develop

5.5. CI-Friendly Versioning

The plugin works with Maven’s CI-friendly versioning and the flatten-maven-plugin:

<properties>
  <revision>1.3.2-SNAPSHOT</revision>
</properties>

<version>${revision}</version>

This allows the version to be set dynamically during CI builds while the POM remains unchanged.

6. Hotfix Process

Hotfixes are emergency fixes applied directly to production.

6.1. Creating a Hotfix

mvn gitflow:hotfix-start -DhotfixVersion=1.2.1

This:

  • Creates hotfix/1.2.1 branch from main

  • Updates version to 1.2.1

6.2. Completing a Hotfix

mvn gitflow:hotfix-finish

This:

  • Merges hotfix to main

  • Creates version tag

  • Merges hotfix to develop

  • Deletes hotfix branch

TODO: GitHub Actions automation for the hotfix workflow has not yet been implemented. Currently, hotfixes are performed manually using the GitFlow Maven Plugin.

7. Version Management

7.1. Version Lifecycle

Branch Version Format Example

develop

X.Y.Z-SNAPSHOT

1.3.0-SNAPSHOT

release/X.Y.Z

X.Y.Z

1.2.0

main (after release)

X.Y.Z (tagged)

1.2.0

develop (after release)

X.Y.(Z+1)-SNAPSHOT

1.2.1-SNAPSHOT

7.2. Version Bumping

When a release starts, only the release branch changes:

  • Release branch: 1.2.0-SNAPSHOT1.2.0

  • Develop branch: unchanged at 1.2.0-SNAPSHOT

When the release finishes, develop moves to the next patch SNAPSHOT — 1.2.01.2.1-SNAPSHOT. If develop has already been moved past that while the release was open, it keeps its own version; the finish never moves it backwards.

A minor or major increment is made on develop by hand, by editing <revision>.

7.3. Semantic Versioning

MAJOR

Breaking changes to public API

MINOR

New functionality, backwards compatible

PATCH

Bug fixes, backwards compatible

8. CI/CD Integration

For detailed information on how the development workflow integrates with CI/CD pipelines, see GitHub Actions CI/CD Architecture.

8.1. PR Pipelines

  • PRs to develop trigger the test pipeline

  • All tests must pass before merge (unless overridden)

  • Path filtering ensures only relevant tests run

  • In the Angular repositories, a Format job checks every PR’s changes regardless of paths — see Formatting and the Pre-commit Hook

8.2. Develop Push Pipeline

Pushes to develop trigger:

  • Frontend and backend tests (based on changes)

  • Maven packaging

  • Docker image build and push

  • Dependency graph submission

8.3. Main Push Pipeline (Release)

Pushes to main trigger:

  • Production build with prod profile

  • Docker image push

  • Helm chart package and push

  • Stage deploy (ArgoCD manifest update)

  • GitFlow release-finish automation

9. Best Practices

9.1. Do’s

  • ✅ Keep feature branches short-lived (days, not weeks)

  • ✅ Update from develop regularly to avoid merge conflicts

  • ✅ Write meaningful commit messages with ADO references

  • ✅ Run tests locally before pushing

  • ✅ Request code reviews promptly

9.2. Don’ts

  • ❌ Don’t commit directly to main or develop

  • ❌ Don’t merge PRs with failing tests

  • ❌ Don’t leave feature branches open for extended periods

  • ❌ Don’t force push to shared branches

  • ❌ Don’t skip the release stabilization phase

11. External References