Skip to content

Commit

Permalink
Add "standard" cogment release scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
cloderic committed Jan 17, 2024
1 parent a8bc9be commit c6416ff
Show file tree
Hide file tree
Showing 10 changed files with 435 additions and 8 deletions.
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
root = true

[*]
indent_style = space
indent_size = 2
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 120

[{*.py,*.yml}]
indent_size = 4
77 changes: 72 additions & 5 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,76 @@
stages:
- lint
- lint
- build
- publish

workflow:
# Only run for merge requests, tags, and `main` and `develop` (default) branches
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_BRANCH == 'main'
- if: $CI_COMMIT_BRANCH =~ '/^release\/v[0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9]+)?$/'

licenses_checker:
stage: lint
image: registry.gitlab.com/ai-r/cogment/license-checker:latest
script:
- license-checker
stage: lint
image: registry.gitlab.com/ai-r/cogment/license-checker:latest
script:
- license-checker

shellcheck:
image: koalaman/shellcheck-alpine:stable
stage: lint
before_script:
- shellcheck --version
script:
- shellcheck $(find . -name '*.sh' | xargs)

shfmt:
image: mvdan/shfmt:v3.1.0-alpine
stage: lint
before_script:
- shfmt -version
script:
- shfmt -i 2 -ci -d .

.base:
image: python:3.10
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
before_script:
- mkdir -p ${PIP_CACHE_DIR}
- python -m venv .venv
- source .venv/bin/activate
- pip install -r requirements.txt
- pip install -e .
cache:
- paths:
- .cache/pip
- key:
files:
- requirements.txt
- setup.cfg
paths:
- ".venv"

build_sdist:
extends: .base
stage: build
script:
- python -m build
- twine check dist/*
artifacts:
expire_in: 1 week
paths:
- dist/*.tar.gz
- dist/*.whl

publish_to_pypi:
extends: .base
stage: publish
script:
- python -m build
- python -m twine upload dist/* --non-interactive -u $PYPI_USERNAME -p $PYPI_PASSWORD
rules:
- if: $CI_COMMIT_TAG
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- Initial release
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,21 @@ Terminology:
- Model: a relatively raw PyTorch (or other?) model, inheriting from `nn.Module`
- Agent: a model wrapped in some utility class to interact with np arrays
- Actor: a cogment service that may involve models and/or actors
## Release process
People having maintainers rights of the repository can follow these steps to release a version **MAJOR.MINOR.PATCH**. The versioning scheme follows [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
1. Run `./scripts/create_release_branch.sh MAJOR.MINOR.PATCH`, this will automatically:
- update the version of the package, in `cogment_lab/version.py`,
- create a release branch with this changes at `release/vMAJOR.MINOR.PATCH` and push it.
2. On the release branch:
- Make sure the changelog, at `CHANGELOG.md`, reflects the changes since the last release,
- Fix any issue, making sure that te build passes on CI,
- Commit and push any changes.
3. Run `./scripts/tag_release.sh MAJOR.MINOR.PATCH`, this will automatically:
- create the specific version section in the changelog and push it to the release branch,
- merge the release branch in `main`,
- create the release tag and,
- update the `develop` to match the latest release.
4. The CI will automatically publish the package to PyPI.
3 changes: 1 addition & 2 deletions cogment_lab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@
import logging

from cogment_lab.process_manager import Cogment
from cogment_lab.version import __version__
from cogment.utils import logger

logger.addHandler(logging.NullHandler())

__version__ = "0.0.1"


__all__ = ["Cogment"]
3 changes: 3 additions & 0 deletions cogment_lab/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copyright 2023 AI Redefined Inc. <[email protected]>

__version__ = "0.1.0"
77 changes: 77 additions & 0 deletions scripts/commons.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env bash

####
# Helper functions & variables
####

ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
export ROOT_DIR

GIT_REMOTE="origin"
export GIT_REMOTE

# Let's check if we have GNU sed or BSD sed
if sed --help >/dev/null 2>&1; then
# There is a '--help' option, it is GNU BSD
SED_NL="\\n"
else
SED_NL="\\
"
fi
export SED_NL

# Generic functions

## join_by
## Examples:
## $ join_by "-delimiter-" "a" "b" "c"
## "a-delimiter-b-delimiter-c"
function join_by() {
local delimiter=$1
shift
local strings=$1
shift
printf %s "${strings}" "${@/#/$delimiter}"
}

## array_contains
## Examples:
## $ array_contains "foo" "bar" "foobaz"
## 1
##
## $ array_contains "foo" "bar" "foo" "baz"
## 0
function array_contains() {
local seeking=$1
shift
local array=("$@")
shift
for element in "${array[@]}"; do
if [[ "${element}" == "${seeking}" ]]; then
return 0
fi
done
return 1
}

# Version related functions

VERSION_SED_REGEX="[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\(-[a-zA-Z0-9]\{1,\}\)\{0,1\}"

function validate_version() {
local input_version=$1
shift
local parsed_version
parsed_version=$(sed -n "s/^v\{0,1\}\(${VERSION_SED_REGEX}\)$/\1/p" <<<"${input_version}")
printf %s "${parsed_version}"
}

function retrieve_package_version() {
sed -n "s/^__version__[[:blank:]]*\=[[:blank:]]*\"\(${VERSION_SED_REGEX}\)\"/\1/p" "${ROOT_DIR}/cogment_lab/version.py"
}

function update_package_version() {
local version=$1
sed -i.bak "/^__version__[[:blank:]]*\=/s/${VERSION_SED_REGEX}/${version}/" "${ROOT_DIR}/cogment_lab/version.py"
retrieve_package_version
}
109 changes: 109 additions & 0 deletions scripts/create_release_branch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#!/usr/bin/env bash

####
# Release preparation script
#
# Should be executed by the release manager to initiate the finalization work on a particular release
####

# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/commons.sh"

function usage() {
local usage_str=""
usage_str+="Update the version and create a release branch\n\n"
usage_str+="Usage:\n"
usage_str+=" $(basename "${BASH_SOURCE[0]}") <version> [--dry-run]\n\n"
usage_str+=" version: looks like MAJOR.MINOR.PATCH[.PRERELEASE] having:\n"
usage_str+=" - MAJOR, MINOR and PATCH digit only,\n"
usage_str+=" - PRERELEASE optional, any string >1 alphanumerical characters.\n\n"
usage_str+="Options:\n"
usage_str+=" --dry-run: Do not push anything to the remote.\n"
usage_str+=" -h, --help: Show this screen.\n"
printf "%b" "${usage_str}"
}

set -o errexit

# Parse the command line arguments.
dry_run=0

while [[ "$1" != "" ]]; do
case $1 in
--dry-run)
dry_run=1
;;
--help | -h)
usage
exit 0
;;
*)
if [[ -z "${version}" ]]; then
input_version=$1
validated_version=$(validate_version "${input_version}")
if [[ -z "${validated_version}" ]]; then
printf "%s: provided version is invalid.\n\n" "${input_version}"
usage
exit 1
fi
version="${validated_version}"
else
printf "%s: unrecognized argument.\n\n" "$1"
usage
exit 1
fi
;;
esac
shift
done

if [[ -z "${version}" ]]; then
printf "Missing version.\n\n"
usage
exit 1
fi

printf "* Preparing release v%s...\n" "${version}"

# Move to the remote `develop` branch
git -C "${ROOT_DIR}" fetch -q "${GIT_REMOTE}"
git -C "${ROOT_DIR}" checkout -q "${GIT_REMOTE}/develop"

printf "** Now on the latest %s/develop\n" "${GIT_REMOTE}"

# Retrieving the current version of the package
current_version=$(retrieve_package_version)

printf "** Current version is v%s\n" "${current_version}"

# Creating the release branch, this will fail if the branch already exists
release_branch="release/v${version}"
git -C "${ROOT_DIR}" branch "${release_branch}"
git -C "${ROOT_DIR}" checkout -q "${release_branch}"

printf "** Release branch \"%s\" created\n" "${release_branch}"

# Updating the version of the package and commit
updated_version=$(update_package_version "${version}")
if [[ "${version}" != "${updated_version}" ]]; then
printf "Error while updating the version to %s.\n" "${version}"
exit 1
fi
git -C "${ROOT_DIR}" commit -q -a -m"Preparing release v${version}"

# TODO here we could ask / retrieve the latest version of the internal dependencies and update .cogment-api.yaml and .gitlab-ci.yml

printf "** Version updated to v%s\n" "${updated_version}"

if [[ "${dry_run}" == 1 ]]; then
printf "** DRY RUN SUCCESSFUL - Nothing pushed to %s\n" "${GIT_REMOTE}"
else
git -C "${ROOT_DIR}" push -q "${GIT_REMOTE}" "${release_branch}"
printf "** Release branch \"%s\" pushed to \"%s\" \n" "${release_branch}" "${GIT_REMOTE}"
fi

printf "* To finalize the release:\n"
printf "** Update the dependencies, in particular make sure nothing is relying on a \"latest\" version of another package.\n"
printf "** Check and update the package's changelog at \"%s/CHANGELOG.md\"\n" "${ROOT_DIR}"
printf "** Make sure the CI builds everything properly\n"
printf "** Finally, run \"%s %s\"\n" "$(dirname "${BASH_SOURCE[0]}")/tag_release.sh" "${version}"
Loading

0 comments on commit c6416ff

Please sign in to comment.