This document contains a description of the conventions which should be followed when contributing to this repository. They are not final and suggestions are welcome.
- Follow Effective Go conventions.
- Use snake-case everywhere in the database and JSON objects.
We should keep the changelog up to date as this is part of the open source platform. Each issue should be added to the top of the appropriate verb in the [Unreleased]
section of the changelog in the corresponding issue branch in the format {issue name} [#{issue-ID}]({issue url})
(eg. [Unreleased] Added - Set up project skeleton #1)
When implementing an API:
- Define the OpenAPI 3.0 documentation for the API in the appropriate yaml files stored in
driver/web/docs
folder. - Run
make oapi-gen-docs
to generate thedef.yaml
file stored indriver/web/docs/gen
folder. To run this command, you will need to install swagger-cli. This command will merge all OpenAPI files into thedef.yaml
file. Please do not change thedef.yaml
file manually. - Test you API via the documentation - Open http://localhost/surveys/doc/ui/ , choose "Local server" from the "Servers" combobox and run your API. This is an alternative to Postman. Make sure to set the correct value in the
SURVEYS_BASE_URL
environment variable (eg. http://localhost/surveys) before running the service to access the docs.
Pull requests should be linked to the associated issue with a keyword in the description (eg. Resolves #{issue number}
). This will close the issue automatically when the PR is merged.
Whenever a new interface is created, a unit test should be created for each function it exposes. The purpose of these unit tests is primarily to ensure that the contract with consumers established by the interfaces are not unintentionally broken by future implementation changes. With this in mind, test cases should include all common usage, as well as any edge cases for which consistency is important.
When updating or changing existing implementations, run the associated unit tests to ensure that they still pass. If they do not, the implementation changes likely changed the interface as well. If the change to the interface was intentional, update the unit tests as needed to make them pass and document the Breaking Change. If the change was not intentional, rework your implementation changes to keep the interface consistent and ensure all tests pass.
To test some components of the system in isolation, it may be necessary to mock some interfaces. Mocks should be automatically generated using the Mockery utility. Mockery can be installed by running go install github.com/vektra/mockery/v2@latest
. One example of an interface that will need to be mocked is the interfaces.Storage
interface. To generate (or regenerate) the mocks for the storage interface using Mockery, cd core/interfaces
then run mockery --name=Storage
.
Whenever a new release is made, the following process should be followed.
Changes to the develop
branch will be continuously deployed into the dev environment to be tested. When several significant changes have been merged into the develop
branch and have been tested, a new dev release should be made.
To make a dev release:
- Checkout the
develop
branch andgit pull
to ensure you have the latest updates locally. - Update the "Unreleased" version in the CHANGELOG to
[X.X.X] - YYYY-MM-dd
(eg.[1.1.7] - 2022-06-08
). - Update SECURITY.md to reflect the latest supported and unsupported versions.
- Update the latest version in any docs or source code as needed.
- Make any changes needed to document breaking changes and deprecations.
- Commit all changes to the
develop
branch with the commit messageRelease vX.X.X
(eg. `Release v1.1.7). - Create a new tag from the
develop
branch calledvX.X.X
(eg.v1.1.7
). - Push changes to
develop
branch and create remote tag atomically usinggit push --atomic origin develop vX.X.X
(eg.git push --atomic origin develop v1.1.7
).
NOTE: Pushing to
develop
will automatically trigger a deployment to thedev
environment. Pushing and creating the new tag atomically will ensure that the deployment pipeline correctly uses the new tag to set the version on the build it generates.
When you are ready to move a release to the production environment:
- Make a pull request from
develop
intomain
namedRelease vX.X.X
(eg.Release v1.1.7
). - Review the changes included in the update to ensure they are all production ready.
- Checkout the
main
branch andgit pull
to ensure you have the latest updates locally. - Run
git merge --ff-only origin/develop
. If this merge fails, merge any changes frommain
back intodevelop
then restart from Step 3.
NOTE: While this is slightly cumbersome, GitHub does not currently support fast-forward merge through the pull request user interface. We want to use fast-forward merging to preserve the linear history from develop without introducing a new merge commit (like
Create a merge commit
), or rebasing and changing commit hashes unnecessarily (likeRebase and merge
). This will ensure that the exact same commit hash is used to build for staging and production that was used to build for develop.
- Run
git push
. - RECOMMENDED - Publish a new GitHub Release from this tag with the title
vX.X.X
(eg.v1.1.7
). Include the contents from the CHANGELOG for this latest version in the release notes, as well as a link to the whole CHANGELOG on themain
branch. For libraries this is highly recommended.
Pushing to the main
branch will automatically trigger a deployment to the stage
environment. Once the release has been tested appropriately, the production pipeline can be manually triggered to deploy the same Docker image in the stage
environment to the prod
environment.
Breaking changes should be avoided when possible, but will sometimes be necessary. In the event that a breaking change does need to be made, this change should be documented clearly for developers relying on the functionality. This includes the following items:
- Create and apply a "breaking" label to the associated issue in GitHub
- Add a "BREAKING:" prefix to the associated line in the CHANGELOG
- Document upgrade instructions in the README in the
Upgrading > Migration steps > Unreleased > Breaking changes
section. These should explain the changes that were made, as well as all changes the developer will need to make to handle the breaking change. Examples should be provided where appropriate.
When a release including the breaking change is created, the following steps must be taken:
- Update the MAJOR version number to indicate that incompatible interface changes have occurred (see Semantic Versioning)
- Update the
Upgrading > Migration steps > Unreleased
section in the README to the latest version (eg.Upgrading > Migration steps > v1.1.0
) - Add a "BREAKING" warning to the release notes
- Include a copy of the upgrade instructions from the README in the release notes
In some cases when Breaking Changes need to be made, the existing functionality must be maintained to provide backwards compatibility. To do so, the new component (function, type, field, package...) should be created and the old component should be maintained and flagged as deprecated. This will give time for developers relying on the component to make the necessary updates before it becomes unavailable. In these cases, the following process should be followed:
- Add a "DEPRECATED:" prefix to the associated line in the CHANGELOG
- Add a "Deprecated:" comment to the component and provide information about the deprecation and replacement. See the Godoc documentation for more information.
- Document upgrade instructions in the README in the
Upgrading > Migration steps > Unreleased > Deprecations
section. These should explain the changes that were made, as well as all changes the developer will need to make to replace the deprecated component. Examples should be provided where appropriate. If known, include a timeline for when the deprecated components will be removed.
When a release including the deprecation is created, the following steps must be taken:
- Update the
Upgrading > Migration steps > Unreleased
section in the README to the latest version (eg.Upgrading > Migration steps > v1.1.0
) - Include a copy of the upgrade instructions from the README in the release notes
When the deprecated components are finally removed, follow the process to document this as a Breaking Change.