release-create-cli-release.yaml 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. ---
  2. name: Release - Create CLI GitHub Release
  3. 'on':
  4. push:
  5. tags:
  6. - 'v*.*.*' # Trigger on version tags like v1.0.0, v2.1.3, etc.
  7. permissions:
  8. contents: write
  9. jobs:
  10. release:
  11. runs-on: ubuntu-latest
  12. steps:
  13. - name: Checkout code
  14. uses: actions/checkout@v6
  15. with:
  16. fetch-depth: 0
  17. - name: Extract version from tag
  18. id: version
  19. run: |
  20. # Remove 'v' prefix if present (e.g., v1.0.0 -> 1.0.0)
  21. VERSION="${GITHUB_REF#refs/tags/}"
  22. VERSION="${VERSION#v}"
  23. echo "version=$VERSION" >> $GITHUB_OUTPUT
  24. echo "tag=$GITHUB_REF_NAME" >> $GITHUB_OUTPUT
  25. echo "Extracted version: $VERSION from tag $GITHUB_REF_NAME"
  26. - name: Validate version consistency
  27. run: |
  28. TAG_VERSION="${{ steps.version.outputs.version }}"
  29. # Extract version from pyproject.toml
  30. PYPROJECT_VERSION=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/')
  31. # Extract version from cli/__init__.py
  32. CLI_VERSION=$(grep '^__version__ = ' cli/__init__.py | sed 's/__version__ = "\(.*\)"/\1/')
  33. echo "Tag version: $TAG_VERSION"
  34. echo "pyproject.toml: $PYPROJECT_VERSION"
  35. echo "cli/__init__.py: $CLI_VERSION"
  36. echo ""
  37. # Check if all versions match
  38. if [ "$TAG_VERSION" != "$PYPROJECT_VERSION" ]; then
  39. echo "Error: Tag version ($TAG_VERSION) does not match pyproject.toml version ($PYPROJECT_VERSION)"
  40. echo "Please update pyproject.toml to version $TAG_VERSION before creating the release."
  41. exit 1
  42. fi
  43. if [ "$TAG_VERSION" != "$CLI_VERSION" ]; then
  44. echo "Error: Tag version ($TAG_VERSION) does not match cli/__init__.py version ($CLI_VERSION)"
  45. echo "Please update cli/__init__.py to version $TAG_VERSION before creating the release."
  46. exit 1
  47. fi
  48. echo "Version consistency check passed"
  49. echo "All version strings match: $TAG_VERSION"
  50. - name: Set up Python
  51. uses: actions/setup-python@v6
  52. with:
  53. python-version: '3.14'
  54. - name: Install build dependencies
  55. run: |
  56. python -m pip install --upgrade pip
  57. pip install build twine
  58. - name: Build package
  59. run: python -m build
  60. - name: Check distribution
  61. run: |
  62. echo "Built packages:"
  63. ls -lh dist/
  64. echo ""
  65. echo "Checking package integrity:"
  66. twine check dist/*
  67. - name: Prepare release asset aliases
  68. run: |
  69. RAW_VERSION="${{ steps.version.outputs.version }}"
  70. NORMALIZED_VERSION=$(python - "$RAW_VERSION" <<'PY'
  71. import re
  72. import sys
  73. raw_version = sys.argv[1]
  74. print(re.sub(r"-(\d+)$", lambda match: f".post{match.group(1)}", raw_version))
  75. PY
  76. )
  77. mkdir -p dist-release
  78. cp dist/* dist-release/
  79. if [ "$NORMALIZED_VERSION" != "$RAW_VERSION" ]; then
  80. NORMALIZED_SDIST="dist/boilerplates-$NORMALIZED_VERSION.tar.gz"
  81. RAW_SDIST="dist-release/boilerplates-$RAW_VERSION.tar.gz"
  82. if [ -f "$NORMALIZED_SDIST" ] && [ ! -f "$RAW_SDIST" ]; then
  83. cp "$NORMALIZED_SDIST" "$RAW_SDIST"
  84. echo "Created release alias: $(basename "$RAW_SDIST")"
  85. fi
  86. fi
  87. echo "Release assets:"
  88. ls -lh dist-release/
  89. # PyPI publishing disabled for now - install via GitHub releases
  90. # - name: Publish to PyPI
  91. # if: >
  92. # ${{ !contains(steps.version.outputs.version, 'alpha') &&
  93. # !contains(steps.version.outputs.version, 'beta') &&
  94. # !contains(steps.version.outputs.version, 'rc') }}
  95. # env:
  96. # TWINE_USERNAME: __token__
  97. # TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
  98. # run: |
  99. # echo "Publishing to PyPI..."
  100. # twine upload dist/*
  101. - name: Extract changelog for this version
  102. id: changelog
  103. run: |
  104. # Extract the changelog for this version from CHANGELOG.md
  105. VERSION="${{ steps.version.outputs.version }}"
  106. # First try to extract the section for this specific version
  107. CHANGELOG=$(awk -v ver="$VERSION" '/^## \[/{if($0 ~ "\\[" ver "\\]"){flag=1; next} else if(flag){exit}} flag' CHANGELOG.md)
  108. # If empty, fall back to [Unreleased] section
  109. if [ -z "$CHANGELOG" ]; then
  110. CHANGELOG=$(awk '/^## \[Unreleased\]/{flag=1; next} /^## \[/{flag=0} flag' CHANGELOG.md)
  111. fi
  112. if [ -z "$CHANGELOG" ]; then
  113. echo "No changelog entries found for this release"
  114. CHANGELOG="See commit history for details."
  115. fi
  116. # Save to output using heredoc to handle multiline
  117. {
  118. echo 'content<<EOF'
  119. echo "$CHANGELOG"
  120. echo EOF
  121. } >> $GITHUB_OUTPUT
  122. - name: Create GitHub Release
  123. uses: softprops/action-gh-release@v2
  124. with:
  125. tag_name: ${{ steps.version.outputs.tag }}
  126. name: Release ${{ steps.version.outputs.tag }}
  127. body: |
  128. ## Boilerplates CLI ${{ steps.version.outputs.tag }}
  129. ${{ steps.changelog.outputs.content }}
  130. ---
  131. ### Installation
  132. Install using the installation script:
  133. ```bash
  134. curl -fsSL https://raw.githubusercontent.com/christianlempa/boilerplates/main/scripts/install.sh | bash
  135. ```
  136. Or install a specific version:
  137. ```bash
  138. curl -fsSL https://raw.githubusercontent.com/christianlempa/boilerplates/main/scripts/install.sh |
  139. bash -s -- --version ${{ steps.version.outputs.tag }}
  140. ```
  141. draft: false
  142. prerelease: >
  143. ${{ contains(steps.version.outputs.version, 'alpha') ||
  144. contains(steps.version.outputs.version, 'beta') ||
  145. contains(steps.version.outputs.version, 'rc') }}
  146. files: |
  147. dist-release/*.whl
  148. dist-release/*.tar.gz
  149. env:
  150. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}