From 774a3f7ecc4c0b9ec44fd26e69266d4e5b463823 Mon Sep 17 00:00:00 2001 From: Alexander Minges Date: Thu, 17 Jul 2025 14:03:18 +0200 Subject: [PATCH] ci(release): add release workflow to gitlab ci Add automated release creation triggered by semantic version tags. --- .gitlab-ci.yml | 53 +++++++ CHANGELOG.md | 12 ++ CONTRIBUTING.md | 57 ++++++++ docs/source/index.rst | 1 + docs/source/release-workflow.rst | 244 +++++++++++++++++++++++++++++++ 5 files changed, 367 insertions(+) create mode 100644 docs/source/release-workflow.rst diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 17632fd..34a905e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,6 +10,8 @@ stages: - secret-detection - build-docs - pages + - build + - release variables: PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" cache: @@ -78,5 +80,56 @@ pages: only: - main +build-package: + stage: build + image: python:3 + before_script: + - python -m pip install --upgrade pip + - pip install build + script: + - python -m build + artifacts: + paths: + - dist/ + expire_in: 1 week + rules: + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+.*$/ + when: always + - when: never + +release: + stage: release + image: registry.gitlab.com/gitlab-org/release-cli:latest + needs: ["test", "build-package"] + before_script: + - apk add --no-cache git python3 py3-pip + - python3 -m pip install setuptools_scm + script: + - | + # Get version from setuptools_scm + VERSION=$(python3 -c "from setuptools_scm import get_version; print(get_version())") + echo "Creating release for version: $VERSION" + + # Extract changelog section for this version + CHANGELOG_SECTION=$(awk "/^## \[v?$VERSION\]/ {flag=1; next} /^## \[/ && flag {flag=0} flag" CHANGELOG.md | sed '/^$/d' || echo "No changelog entry found for version $VERSION") + + # If changelog section is empty, provide a default message + if [ -z "$CHANGELOG_SECTION" ]; then + CHANGELOG_SECTION="Release $VERSION - See full changelog at $CI_PROJECT_URL/-/blob/v$VERSION/CHANGELOG.md" + fi + + # Create GitLab release with artifacts + release-cli create \ + --name "Release $VERSION" \ + --tag-name "v$VERSION" \ + --description "$CHANGELOG_SECTION" \ + --ref "$CI_COMMIT_SHA" \ + --assets-link "{\"name\":\"Source Distribution\",\"url\":\"$CI_PROJECT_URL/-/jobs/$CI_JOB_ID/artifacts/file/dist/doi2dataset-$VERSION.tar.gz\"}" \ + --assets-link "{\"name\":\"Wheel Distribution\",\"url\":\"$CI_PROJECT_URL/-/jobs/$CI_JOB_ID/artifacts/file/dist/doi2dataset-$VERSION-py3-none-any.whl\"}" + rules: + - if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+.*$/ + when: always + - when: never + include: - template: Security/Secret-Detection.gitlab-ci.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 783f338..d8a7e84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `DATAVERSE_AUTH_PASSWORD` - Basic authentication password - Environment variables take precedence over configuration file values - Backward compatibility maintained - config file values used when environment variables are not set +- Automated tag-based release workflow with GitLab CI +- Release documentation in `docs/source/release-workflow.rst` +- Release process documentation in `CONTRIBUTING.md` ### Changed @@ -26,6 +29,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Expand automated commit ignoring for merge/revert/fixup/squash commits - Update pre-commit CI messages to follow conventional commit format - Improve commit message documentation with validation examples and best practices +- Enhanced GitLab CI pipeline with automated release stages + +### Added (CI/CD) + +- Automated package building (wheel and source distribution) on tag push +- GitLab release creation with changelog extraction +- Release artifact attachment (Python packages) +- Tag-based release triggering following semantic versioning +- Integration with existing setuptools_scm configuration ## [v2.0.3] - 2025-07-14 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ece10cd..771fc6b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -82,6 +82,7 @@ pytest --cov=. --cov-report=html ### Test Structure Tests are organized into several files covering: + - Core functionality (DOI validation, name processing) - API integration (mock responses) - Citation building @@ -113,6 +114,61 @@ make multiversion The documentation supports multiple versions and is automatically deployed via GitLab CI/CD. +## Release Process + +This project uses automated tag-based releases following semantic versioning. Only maintainers can create releases. + +### Creating a Release + +1. **Update the changelog** in `CHANGELOG.md`: + + ```markdown + ## [v2.0.4] - 2025-01-XX + + ### Added + + - New feature description + + ### Fixed + + - Bug fix description + ``` + +2. **Commit the changelog update**: + + ```bash + git add CHANGELOG.md + git commit -m "docs: update changelog for v2.0.4" + ``` + +3. **Create and push the release tag**: + + ```bash + git tag v2.0.4 + git push origin v2.0.4 + ``` + +4. **GitLab CI automatically**: + - Runs all tests + - Builds Python packages (wheel and source distribution) + - Creates GitLab release with changelog content + - Attaches build artifacts to the release + +### Version Numbering + +- Follow [Semantic Versioning](https://semver.org/) (MAJOR.MINOR.PATCH) +- Tags must match the pattern `v[0-9]+.[0-9]+.[0-9]+` (e.g., `v2.0.4`) +- Pre-release versions are supported (e.g., `v2.0.4-rc.1`, `v2.0.4-alpha.1`) + +### Release Artifacts + +Each release automatically includes: + +- Source distribution (`.tar.gz`) +- Wheel distribution (`.whl`) +- Changelog content extracted from `CHANGELOG.md` +- Documentation snapshot + ## Submitting Changes 1. **Create a branch** from `main` for your changes @@ -135,6 +191,7 @@ Please be respectful and constructive in all interactions. We aim to maintain a ## Questions? If you have questions about contributing, feel free to: + - Open an issue for discussion - Check the existing documentation - Contact the maintainers diff --git a/docs/source/index.rst b/docs/source/index.rst index 0e1fcbc..56551d8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -41,4 +41,5 @@ Key Features: modules contributing commit-messages + release-workflow faq diff --git a/docs/source/release-workflow.rst b/docs/source/release-workflow.rst new file mode 100644 index 0000000..d4f9e9e --- /dev/null +++ b/docs/source/release-workflow.rst @@ -0,0 +1,244 @@ +Release Workflow +================ + +This project uses an automated tag-based release workflow that follows industry best practices and integrates seamlessly with GitLab CI/CD. Releases are triggered by pushing semantic version tags and include automatic changelog extraction, package building, and artifact distribution. + +Overview +-------- + +The release process is designed to be simple, safe, and automated: + +1. **Maintainer updates changelog** with new version information +2. **Maintainer creates and pushes a git tag** following semantic versioning +3. **GitLab CI automatically** builds packages and creates the release +4. **Release artifacts** are made available for download + +This approach follows Git and industry conventions, ensuring compatibility with tools like ``setuptools_scm``, package managers, and dependency resolution systems. + +For Maintainers: Creating a Release +------------------------------------ + +Prerequisites +~~~~~~~~~~~~~ + +- Write access to the main repository +- All changes merged to ``main`` branch +- Tests passing on the ``main`` branch + +Step-by-Step Process +~~~~~~~~~~~~~~~~~~~~ + +1. **Update the Changelog** + + Edit ``CHANGELOG.md`` to add a new version section: + + .. code-block:: markdown + + ## [v2.0.4] - 2025-01-15 + + ### Added + + - New feature that enhances DOI processing + - Support for additional metadata fields + + ### Fixed + + - Bug fix for edge case in affiliation parsing + - Improved error handling for malformed DOIs + + ### Changed + + - Updated dependency versions for security + +2. **Commit the Changelog** + + Use a conventional commit message: + + .. code-block:: bash + + git add CHANGELOG.md + git commit -m "docs: update changelog for v2.0.4" + +3. **Create and Push the Tag** + + Create a semantic version tag and push it: + + .. code-block:: bash + + git tag v2.0.4 + git push origin v2.0.4 + +4. **Monitor the Release** + + GitLab CI will automatically: + + - Run the full test suite + - Build Python packages (wheel and source distribution) + - Extract changelog content for the release description + - Create the GitLab release with downloadable artifacts + +Automated Release Pipeline +--------------------------- + +The release pipeline consists of several stages: + +Build Stage +~~~~~~~~~~~ + +When a semantic version tag is pushed: + +- **Package Building**: Creates both wheel (``.whl``) and source distribution (``.tar.gz``) packages +- **Artifact Storage**: Packages are stored as CI artifacts for attachment to the release +- **Version Detection**: Uses ``setuptools_scm`` to automatically detect version from the git tag + +Release Stage +~~~~~~~~~~~~~ + +After successful building: + +- **Changelog Extraction**: Automatically parses ``CHANGELOG.md`` to extract content for the tagged version +- **Release Creation**: Creates a GitLab release with: + - Release name: "Release X.Y.Z" + - Tag reference: The pushed tag + - Description: Extracted changelog content + - Downloadable artifacts: Both wheel and source distributions + +Version Numbering +------------------ + +This project follows `Semantic Versioning `_ (SemVer): + +Standard Versions +~~~~~~~~~~~~~~~~~ + +- **MAJOR.MINOR.PATCH** (e.g., ``v2.0.4``) +- **MAJOR**: Incompatible API changes +- **MINOR**: New functionality in a backward-compatible manner +- **PATCH**: Backward-compatible bug fixes + +Pre-release Versions +~~~~~~~~~~~~~~~~~~~~ + +Pre-release versions are supported for testing: + +- **Alpha**: ``v2.0.4-alpha.1`` +- **Beta**: ``v2.0.4-beta.1`` +- **Release Candidate**: ``v2.0.4-rc.1`` + +Tag Format Requirements +~~~~~~~~~~~~~~~~~~~~~~~ + +The CI pipeline only triggers on tags matching the pattern: + +.. code-block:: text + + ^v[0-9]+\.[0-9]+\.[0-9]+.*$ + +Valid examples: +- ``v1.0.0`` +- ``v2.1.3`` +- ``v1.0.0-alpha.1`` +- ``v2.0.0-rc.2`` + +Invalid examples: +- ``1.0.0`` (missing 'v' prefix) +- ``v1.0`` (missing patch version) +- ``release-1.0.0`` (wrong format) + +Release Artifacts +----------------- + +Each release includes the following downloadable artifacts: + +Python Packages +~~~~~~~~~~~~~~~ + +- **Source Distribution** (``.tar.gz``): Contains all source code and can be installed with ``pip install`` +- **Wheel Distribution** (``.whl``): Pre-built binary package for faster installation + +Documentation +~~~~~~~~~~~~~ + +- **Documentation Snapshot**: The documentation website reflects the state at the time of release +- **Changelog**: Full changelog content is included in the release description + +Installation from Release +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Users can install directly from release artifacts: + +.. code-block:: bash + + # Install from wheel (recommended) + pip install https://git.uni-due.de/cbm343e/doi2dataset/-/releases/v2.0.4/downloads/doi2dataset-2.0.4-py3-none-any.whl + + # Install from source + pip install https://git.uni-due.de/cbm343e/doi2dataset/-/releases/v2.0.4/downloads/doi2dataset-2.0.4.tar.gz + +Troubleshooting +--------------- + +Common Issues +~~~~~~~~~~~~~ + +**Pipeline doesn't trigger on tag push** + - Verify tag format matches ``v[0-9]+.[0-9]+.[0-9]+.*`` + - Check that the tag was pushed to the main repository (not a fork) + - Ensure GitLab CI is enabled for the project + +**Changelog extraction fails** + - Verify the changelog section follows the expected format: ``## [vX.Y.Z] - YYYY-MM-DD`` + - Check that the version in the changelog matches the git tag + - Ensure the changelog file is named ``CHANGELOG.md`` and located in the project root + +**Build artifacts missing** + - Check that the build stage completed successfully + - Verify ``setuptools_scm`` can detect the version from the git tag + - Ensure all required dependencies are available in the build environment + +**Release creation fails** + - Verify the GitLab release CLI has necessary permissions + - Check that the tag doesn't already exist + - Ensure the changelog content doesn't contain special characters that break the release description + +Manual Recovery +~~~~~~~~~~~~~~~ + +If the automated release fails, maintainers can: + +1. **Check the CI logs** to identify the failure point +2. **Re-run failed jobs** from the GitLab CI interface +3. **Manually create the release** using the GitLab interface if needed +4. **Delete and recreate the tag** if there were issues with the tag itself + +Best Practices +-------------- + +For Maintainers +~~~~~~~~~~~~~~~ + +- **Test thoroughly** before creating releases +- **Update documentation** alongside code changes +- **Follow semantic versioning** strictly +- **Write clear changelog entries** that help users understand changes +- **Use pre-release versions** for testing major changes +- **Coordinate releases** with other maintainers to avoid conflicts + +For Contributors +~~~~~~~~~~~~~~~~ + +- **Write clear commit messages** following conventional commits +- **Update tests** for new functionality +- **Document changes** in pull requests +- **Consider backward compatibility** when making changes +- **Test with multiple Python versions** when possible + +Security Considerations +----------------------- + +- **Release artifacts** are publicly accessible +- **Changelog content** should not contain sensitive information +- **Version tags** are permanent and should not be deleted +- **CI pipeline** runs with elevated permissions during releases + +The automated release process ensures consistency, reduces manual errors, and provides a clear audit trail for all releases.