diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml deleted file mode 100644 index db0fb31..0000000 --- a/.github/workflows/create-release.yml +++ /dev/null @@ -1,132 +0,0 @@ -name: Reusable Create release - -on: - workflow_call: - inputs: - version: - description: 'Semantic version of the release (eg. v1.2.3 or v1.2.3-alpha.1)' - required: true - type: string - repository: - description: 'The repository where the release should be created' - required: false - default: ${{ github.repository }} - type: string - ref: - description: 'The branch or SHA for the release (defaults to main)' - required: false - default: ${{ github.ref }} - type: string - skip_release: - description: 'Skip creating the release and only generate the changelog' - required: false - default: false - type: boolean - secrets: - token: - description: 'The token to use when interacting with GitHub' - required: true - -env: - GITHUB_TOKEN: ${{ secrets.token }} - -jobs: - release: - runs-on: ubuntu-latest - steps: - - name: Verify tag is semver - run: | - set -x - if [[ ! "${{ inputs.version }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ ]]; then - echo "This is not a semver compliant tag" - echo "Exiting" - exit 1 - fi - - if [[ "${{ inputs.version }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "is_prerelease=false" >> "$GITHUB_OUTPUT" - else - echo "is_prerelease=true" >> "$GITHUB_OUTPUT" - fi - - if [[ "${{ inputs.version }}" =~ ^v[0-9]+\.[0-9]+\.0$ ]]; then - echo "is_dotzero=true" >> "$GITHUB_OUTPUT" - else - echo "is_dotzero=false" >> "$GITHUB_OUTPUT" - fi - - XY_VERSION=$(echo ${{ inputs.version }} | awk -F. '{print substr($1,2)"."$2}') - echo "xy_version=${XY_VERSION}" >> "$GITHUB_OUTPUT" - id: check_tag - - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - repository: ${{ inputs.repository }} - ref: ${{ inputs.ref }} - path: ${{ inputs.repository }} - token: ${{ secrets.token }} - - - name: Make changelog - working-directory: ./${{ inputs.repository }} - run: | - set -x - - # Details we need in order to create the release - REPOSITORY=${{ inputs.repository }} - echo "owner=${REPOSITORY%/*}" >> "$GITHUB_OUTPUT" - echo "repo=${REPOSITORY#*/}" >> "$GITHUB_OUTPUT" - SHA=$(git rev-parse HEAD) - echo "sha=${SHA}" >> "$GITHUB_OUTPUT" - - # Always compare to latest published full release for repository - PREV_TAG=$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/${{ inputs.repository }}/releases/latest | jq -r '.tag_name') - filterfunc() { git log --pretty=format:%s "${PREV_TAG}..HEAD" | grep "^\s*:$1:" | sed "s/^\s*:$1:\s*/ * /"; } - # Handle scenario where no previous tag exists - if [ -z "${PREV_TAG}" ]; then - filterfunc() { git log --pretty=format:%s | grep "^\s*:$1:" | sed "s/^\s*:$1:\s*/ * /"; } - fi - - RELEASE_DOC="${PWD}/release.md" - echo "release_doc=${RELEASE_DOC}" >> "$GITHUB_ENV" - - BREAKING_CHANGES="$(filterfunc warning)" - if [ -n "${BREAKING_CHANGES}" ]; then - echo -e "## :warning: Breaking Changes\n${BREAKING_CHANGES}\n\n" >> "${RELEASE_DOC}" - fi - - FEATURE_CHANGES="$(filterfunc sparkles)" - if [ -n "${FEATURE_CHANGES}" ]; then - echo -e "## :sparkles: Features\n${FEATURE_CHANGES}\n\n" >> "${RELEASE_DOC}" - fi - - BUG_FIXES="$(filterfunc bug)" - if [ -n "${BUG_FIXES}" ]; then - echo -e "## :bug: Bug Fixes\n${BUG_FIXES}\n\n" >> "${RELEASE_DOC}" - fi - - # Add contributors as GitHub would have added them - gh api \ - --method POST \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - /repos/${{ inputs.repository }}/releases/generate-notes \ - -f tag_name="${{ inputs.version }}" \ - -f target_commitish="${{ inputs.ref }}" \ - -f previous_tag_name="${PREV_TAG}" | jq -r '.body' | grep -Pzo '.*Contributors(.*\n)*' >> "${RELEASE_DOC}" - id: changelog - - - name: Create Release - if: ${{ inputs.skip_release == false }} - uses: ncipollo/release-action@main - with: - owner: ${{ steps.changelog.outputs.owner }} - repo: ${{ steps.changelog.outputs.repo }} - tag: ${{ inputs.version }} - commit: ${{ steps.changelog.outputs.sha }} - bodyFile: ${{ env.release_doc }} - draft: false - prerelease: ${{ steps.check_tag.outputs.is_prerelease }} - skipIfReleaseExists: true - token: ${{ secrets.token }} diff --git a/.github/workflows/generate-changelog.yml b/.github/workflows/generate-changelog.yml new file mode 100644 index 0000000..2ed5f34 --- /dev/null +++ b/.github/workflows/generate-changelog.yml @@ -0,0 +1,117 @@ +name: Generate Changelog + +on: + workflow_call: + inputs: + version: + description: 'Semantic version of the release (e.g., v1.2.3)' + required: true + type: string + prev_version: + description: 'Previous release version (e.g., v1.2.2)' + required: false + default: '' + type: string + repository: + description: 'Repository name' + required: false + default: ${{ github.repository }} + type: string + ref: + description: 'Branch or SHA for the release' + required: false + default: ${{ github.ref }} + type: string + github_token: + description: 'GitHub token' + required: false + type: string + secrets: + token: + description: 'GitHub token' + required: false + + +jobs: + changelog: + runs-on: ubuntu-latest + steps: + - name: Set GITHUB_TOKEN environment variable + run: | + if [ -n "${{ inputs.github_token }}" ]; then + echo "GITHUB_TOKEN=${{ inputs.github_token }}" >> $GITHUB_ENV + else + echo "GITHUB_TOKEN=${{ secrets.token }}" >> $GITHUB_ENV + fi + + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: "${{ env.GITHUB_TOKEN }}" + repository: "${{ inputs.repository }}" + ref: "${{ inputs.ref }}" + + - name: Generate Changelog + id: changelog + env: + GITHUB_TOKEN: "${{ env.GITHUB_TOKEN }}" + run: | + set -x + + REPOSITORY="${{ inputs.repository }}" + SHA="$(git rev-parse HEAD)" + echo "sha=${SHA}" >> "$GITHUB_OUTPUT" + + # Get the previous tag + if [ -n "${{ inputs.prev_version }}" ] && git rev-list "${{ inputs.prev_version }}" 2> /dev/null; then + PREV_TAG="${{ inputs.prev_version }}" + else + PREV_TAG=$(gh api -H "Accept: application/vnd.github+json" "/repos/${{ inputs.repository }}/releases/latest" | jq -r '.tag_name // empty') + fi + + # Generate release notes + NOTES=$(gh api --method POST \ + -H "Accept: application/vnd.github+json" \ + "/repos/${{ inputs.repository }}/releases/generate-notes" \ + -f tag_name="${{ inputs.version }}" \ + -f target_commitish="${SHA}" \ + -f previous_tag_name="${PREV_TAG}" | jq -r '.body') + + RELEASE_DOC="${PWD}/release.md" + echo "**Full Changelog**: https://github.com/${REPOSITORY}/commits/${{ inputs.version }}" > "${RELEASE_DOC}" + + filterfunc() { echo "${NOTES}" | grep "^*\s*:$1:" | sed "s/.*:$1:\s*/* /"; } + + BREAKING_CHANGES="$(filterfunc warning)" + if [ -n "${BREAKING_CHANGES}" ]; then + echo "## :warning: Breaking Changes" >> "${RELEASE_DOC}" + echo "${BREAKING_CHANGES}" >> "${RELEASE_DOC}" + echo "" >> "${RELEASE_DOC}" + fi + + FEATURE_CHANGES="$(filterfunc sparkles)" + if [ -n "${FEATURE_CHANGES}" ]; then + echo "## :sparkles: Features" >> "${RELEASE_DOC}" + echo "${FEATURE_CHANGES}" >> "${RELEASE_DOC}" + echo "" >> "${RELEASE_DOC}" + fi + + BUG_FIXES="$(filterfunc bug)" + if [ -n "${BUG_FIXES}" ]; then + echo "## :bug: Bug Fixes" >> "${RELEASE_DOC}" + echo "${BUG_FIXES}" >> "${RELEASE_DOC}" + echo "" >> "${RELEASE_DOC}" + fi + + NEW_CONTRIB=$(echo "${NOTES}" | sed -n "/Contributors/,\$p") + if [ -n "${NEW_CONTRIB}" ]; then + echo "${NEW_CONTRIB}" >> "${RELEASE_DOC}" + else + echo "${NOTES}" | sed -n "/Changelog/,\$p" >> "${RELEASE_DOC}" + fi + + - name: Upload Changelog Artifact + uses: actions/upload-artifact@v4 + with: + name: changelog-artifact + path: release.md diff --git a/create-release/action.yml b/create-release/action.yml index edbd9bb..6052fbb 100644 --- a/create-release/action.yml +++ b/create-release/action.yml @@ -19,19 +19,11 @@ inputs: description: 'The branch or SHA for the release (defaults to main)' required: false default: ${{ github.ref }} -outputs: - breaking-changes: - description: "Breaking changes introduced in this release" - value: ${{ steps.changelog.outputs.breaking-changes }} - features: - description: "Features introduced in this release" - value: ${{ steps.changelog.outputs.features }} - bug-fixes: - description: "Bug fixes introduced in this release" - value: ${{ steps.changelog.outputs.bug-fixes }} - new-contributors: - description: "New contributors to this release" - value: ${{ steps.changelog.outputs.new-contributors }} + is_prerelease: + description: 'Is this a pre-release?' + required: false + default: "false" + runs: using: "composite" steps: @@ -61,103 +53,30 @@ runs: echo "xy_version=${XY_VERSION}" >> $GITHUB_OUTPUT id: check_tag - - name: Checkout code - uses: actions/checkout@v4 + - name: Generate Changelog + uses: ./.github/workflows/generate-changelog.yml with: - fetch-depth: 0 - repository: ${{ inputs.repository }} - ref: ${{ inputs.ref }} - path: ${{ inputs.repository }} - token: ${{ inputs.github_token }} - - - name: Make changelog - working-directory: ./${{ inputs.repository }} - env: - GITHUB_TOKEN: ${{ inputs.github_token }} - shell: bash - run: | - set -x - set +o pipefail - - # Details we need in order to create the release - REPOSITORY=${{ inputs.repository }} - echo "owner=${REPOSITORY%/*}" >> $GITHUB_OUTPUT - echo "repo=${REPOSITORY#*/}" >> $GITHUB_OUTPUT - SHA=$(git rev-parse HEAD) - echo "sha=${SHA}" >> $GITHUB_OUTPUT - - # Let GitHub format the commits - if [ -n "${{ inputs.prev_version }}" ] && git rev-list ${{ inputs.prev_version }} 2> /dev/null; then - PREV_TAG="${{ inputs.prev_version }}" - else - PREV_TAG=$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" repos/${{ inputs.repository }}/releases/latest | jq -r '.tag_name // empty') - fi - NOTES=$(gh api \ - --method POST \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - repos/${{ inputs.repository }}/releases/generate-notes \ - -f tag_name="${{ inputs.version }}" \ - -f target_commitish="${{ inputs.ref }}" \ - -f previous_tag_name="${PREV_TAG}" | jq -r '.body') - filterfunc() { echo "${NOTES}" | grep "^*\s*:$1:" | sed "s/.*:$1:\s*/* /"; } + version: ${{ github.event.inputs.version }} + prev_version: ${{ github.event.inputs.prev_version }} + repository: ${{ github.event.inputs.repository }} + ref: ${{ github.event.inputs.ref }} + github_token: ${{ inputs.github_token }} - RELEASE_DOC="${PWD}/release.md" - echo "release_doc=${RELEASE_DOC}" >> $GITHUB_ENV - - BREAKING_CHANGES="$(filterfunc warning)" - if [ -n "${BREAKING_CHANGES}" ]; then - echo "## :warning: Breaking Changes" >> ${RELEASE_DOC} - echo "${BREAKING_CHANGES}" >> ${RELEASE_DOC} - echo "" >> ${RELEASE_DOC} - echo "breaking-changes<> $GITHUB_OUTPUT - echo "${BREAKING_CHANGES}" >> $GITHUB_OUTPUT - echo "nEOFn" >> $GITHUB_OUTPUT - fi - - FEATURE_CHANGES="$(filterfunc sparkles)" - if [ -n "${FEATURE_CHANGES}" ]; then - echo "## :sparkles: Features" >> ${RELEASE_DOC} - echo "${FEATURE_CHANGES}" >> ${RELEASE_DOC} - echo "" >> ${RELEASE_DOC} - echo "features<> $GITHUB_OUTPUT - echo "${FEATURE_CHANGES}" >> $GITHUB_OUTPUT - echo "nEOFn" >> $GITHUB_OUTPUT - fi - - BUG_FIXES="$(filterfunc bug)" - if [ -n "${BUG_FIXES}" ]; then - echo "## :bug: Bug Fixes" >> ${RELEASE_DOC} - echo "${BUG_FIXES}" >> ${RELEASE_DOC} - echo "" >> ${RELEASE_DOC} - echo "bug-fixes<> $GITHUB_OUTPUT - echo "${BUG_FIXES}" >> $GITHUB_OUTPUT - echo "nEOFn" >> $GITHUB_OUTPUT - fi - - # TODO(djzager): More? could make this workflow accept as an argument whether or not - # to include other types (ie. seedling, docs) + - name: Download Changelog + uses: actions/download-artifact@v4 + with: + name: changelog-artifact + path: . - # Add contributors as GitHub would have added them - NEW_CONTRIB=$(echo "${NOTES}" | sed -n "/Contributors/,\$p") - if [ -n "${NEW_CONTRIB}" ]; then - echo "${NEW_CONTRIB}" >> ${RELEASE_DOC} - echo "new-contributors<> $GITHUB_OUTPUT - echo "${NEW_CONTRIB}" | head -n -3 >> $GITHUB_OUTPUT - echo "nEOFn" >> $GITHUB_OUTPUT - else - echo "${NOTES}" | sed -n "/Changelog/,\$p" >> ${RELEASE_DOC} - fi - id: changelog - uses: ncipollo/release-action@main with: - owner: ${{ steps.changelog.outputs.owner }} - repo: ${{ steps.changelog.outputs.repo }} + owner: ${{ github.repository_owner }} + repo: ${{ inputs.repository }} tag: ${{ inputs.version }} - commit: ${{ steps.changelog.outputs.sha }} - bodyFile: ${{ env.release_doc }} + commit: ${{ github.sha }} + bodyFile: release.md draft: false - prerelease: ${{ steps.check_tag.outputs.is_prerelease }} + prerelease: ${{ inputs.is_prerelease }} skipIfReleaseExists: true - token: ${{ inputs.github_token }} + token: ${{ inputs.github_token }} \ No newline at end of file