diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml new file mode 100644 index 000000000..934f23792 --- /dev/null +++ b/.github/workflows/create_release.yml @@ -0,0 +1,87 @@ +name: 🚀 Create Release + +on: + workflow_dispatch: + inputs: + bump_minor: + description: 'Bump minor version' + required: false + type: boolean + default: false + version: + description: 'Release version (optional, if not provided will use version from develop without -dev)' + required: false + type: string + +jobs: + release: + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/develop' + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.9' + + - name: Configure Git + run: | + git config --global user.name "${{ secrets.CI_USER }}" + git config --global user.email "${{ secrets.CI_EMAIL }}" + + - name: Get release version + id: get_version + run: | + if [ -n "${{ github.event.inputs.version }}" ]; then + echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT + else + ARGS="" + if [ "${{ github.event.inputs.bump_minor }}" = "true" ]; then + ARGS="--bump-minor" + fi + VERSION=$(python manage_version.py get-release-version $ARGS) + echo "version=$VERSION" >> $GITHUB_OUTPUT + fi + + - name: Update version for release + run: | + python manage_version.py update --version ${{ steps.get_version.outputs.version }} + + - name: Commit release version + run: | + git add ayon_api/version.py pyproject.toml + git commit -m "Release version ${{ steps.get_version.outputs.version }}" + git push origin develop + + - name: Rebase main on develop + run: | + git checkout main + git rebase develop + git push origin main + + - name: Create and push tag + run: | + git tag ${{ steps.get_version.outputs.version }} + git push origin ${{ steps.get_version.outputs.version }} + + - name: Bump version on develop + run: | + git checkout develop + NEW_VERSION=$(python manage_version.py get-dev-version) + python manage_version.py update --version $NEW_VERSION + git add ayon_api/version.py pyproject.toml + git commit -m "Bump version to $NEW_VERSION" + git push origin develop + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.get_version.outputs.version }} + generate_release_notes: true + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/manage_version.py b/manage_version.py new file mode 100644 index 000000000..2f780d176 --- /dev/null +++ b/manage_version.py @@ -0,0 +1,103 @@ +import re +import sys +import argparse +from pathlib import Path + +SEMVER_REGEX = re.compile( + r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)" + r"(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?" + r"(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$" +) + + +def get_current_version(version_file: Path) -> str: + content = version_file.read_text(encoding="utf-8") + match = re.search(r'__version__\s*=\s*"(.*)"', content) + if match: + return match.group(1) + raise ValueError(f"Version not found in {version_file}") + + +def update_version_in_src( + version_file: Path, + pyproject_file: Path, + new_version: str, +): + content = version_file.read_text(encoding="utf-8") + new_content = re.sub( + r'(__version__\s*=\s*").*(")', + rf'\g<1>{new_version}\g<2>', + content + ) + version_file.write_text(new_content, encoding="utf-8") + + # Update pyproject.toml + content = pyproject_file.read_text(encoding="utf-8") + new_lines = [] + for line in content.splitlines(): + if line.startswith("version"): + line = f"version = \"{new_version}\"" + new_lines.append(line) + + pyproject_file.write_text("\n".join(new_lines), encoding="utf-8") + + +def bump_to_dev_version(version: str) -> str: + version_parts = SEMVER_REGEX.match(version).groups() + major, minor, patch = version_parts[0:3] + patch = str(int(patch) + 1) + return f"{major}.{minor}.{patch}-dev" + + +def bump_to_release_version(version: str, bump_minor: bool = False) -> str: + version_parts = SEMVER_REGEX.match(version).groups() + major, minor, patch = version_parts[0:3] + if bump_minor: + minor = str(int(minor) + 1) + patch = "0" + return f"{major}.{minor}.{patch}" + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "command", + choices=["get-release-version", "update", "get-dev-version"] + ) + parser.add_argument( + "--version", + help="Version to set for update command", + ) + parser.add_argument( + "--bump-minor", + action="store_true", + help="Bump minor version for get-release-version command", + ) + args = parser.parse_args() + + repo_root = Path(__file__).parent + version_file = repo_root / "ayon_api" / "version.py" + pyproject_file = repo_root / "pyproject.toml" + + current_version = get_current_version(version_file) + + if args.command == "get-release-version": + if current_version: + print(bump_to_release_version(current_version, args.bump_minor)) + else: + sys.exit(1) + elif args.command == "get-dev-version": + if current_version: + print(bump_to_dev_version(current_version)) + else: + sys.exit(1) + elif args.command == "update": + if not args.version: + print("Error: --version is required for update command") + sys.exit(1) + update_version_in_src(version_file, pyproject_file, args.version) + print(f"Updated version to {args.version}") + + +if __name__ == "__main__": + main()