diff --git a/.github/workflows/conventional-pr.yml b/.github/workflows/conventional-pr.yml new file mode 100644 index 00000000..2076210d --- /dev/null +++ b/.github/workflows/conventional-pr.yml @@ -0,0 +1,18 @@ +name: conventional-pr +on: + pull_request: + branches: + - main + - master + types: + - opened + - edited + - synchronize +jobs: + lint-pr: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: CondeNast/conventional-pull-request-action@v0.2.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a1be3d26..878c985e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,81 +7,84 @@ on: workflow_dispatch: inputs: version: - description: 'Version to release (optional)' - required: false + description: 'The version to release' type: string -concurrency: - group: release-${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - permissions: contents: write pull-requests: read statuses: write + packages: write jobs: - continuous: - name: Continuous - runs-on: ubuntu-latest + release: + name: Release + runs-on: 'ubuntu-latest' + timeout-minutes: 15 + if: "!startsWith(github.event.head_commit.message, '[Release]')" steps: - - uses: actions/checkout@v4 - - name: Determine version - id: get_version - run: | - if [ -n "${{ github.event.inputs.version }}" ]; then - echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT - else - echo "No version provided, calculating next version..." - fi - - uses: rmeneely/git-next-version@v1 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 with: - tag_pattern: '[0-9]*.[0-9]*.[0-9]*' - increment: 'minor' - - name: Set final version - id: set_version + fetch-depth: 0 + - uses: jdx/mise-action@v2 + with: + experimental: true + - name: Check if there are releasable changes + id: is-releasable run: | - if [ -n "${{ steps.get_version.outputs.VERSION }}" ]; then - echo "version=${{ steps.get_version.outputs.VERSION }}" >> $GITHUB_OUTPUT + # Run git cliff and save the output + bumped_output=$(git cliff --bump) + echo "Bumped output:" + echo "${bumped_output}" + + # Read the content of CHANGELOG.md + changelog_content=$(cat CHANGELOG.md) + echo "CHANGELOG.md content:" + echo "${changelog_content}" + + # Compare the outputs and set the result + if [ "${bumped_output}" = "${changelog_content}" ]; then + echo "should-release=false" >> $GITHUB_ENV else - echo "version=${{ env.NEXT_VERSION }}" >> $GITHUB_OUTPUT + echo "should-release=true" >> $GITHUB_ENV fi - - name: "Generate Tuist Changelog" - id: changelog - uses: mikepenz/release-changelog-builder-action@v4 - with: - owner: "tuist" - repo: "XcodeGraph" - configuration: ".github/changelog-configuration.json" + + - name: Get next version + id: next-version + if: env.should-release == 'true' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: echo "NEXT_VERSION=$(git cliff --bumped-version)" >> "$GITHUB_OUTPUT" + - name: Get release notes + id: release-notes + if: env.should-release == 'true' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Check if there are categorized PRs - id: check_prs run: | - if [ "${{ steps.changelog.outputs.categorized_prs }}" = "0" ]; then - echo "skip_next_steps=true" >> $GITHUB_OUTPUT - else - echo "skip_next_steps=false" >> $GITHUB_OUTPUT - fi - - name: Update Changelog - uses: stefanzweifel/changelog-updater-action@v1 - if: steps.check_prs.outputs.skip_next_steps != 'true' - with: - latest-version: ${{ steps.set_version.outputs.version }} - release-notes: ${{ steps.changelog.outputs.changelog }} - path-to-changelog: CHANGELOG.md - - uses: stefanzweifel/git-auto-commit-action@v5 - if: steps.check_prs.outputs.skip_next_steps != 'true' + echo "RELEASE_NOTES<> "$GITHUB_OUTPUT" + git cliff --unreleased >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + - name: Update CHANGELOG.md + if: env.should-release == 'true' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: git cliff --bump -o CHANGELOG.md + - name: Commit changes + id: auto-commit-action + uses: stefanzweifel/git-auto-commit-action@v5 + if: env.should-release == 'true' with: - commit_message: "Version ${{ steps.set_version.outputs.version }}" - tagging_message: ${{ steps.set_version.outputs.version }} commit_options: '--allow-empty' - - name: Create GitHub Release on the tuist/XcodeGraph repository - if: steps.check_prs.outputs.skip_next_steps != 'true' - uses: softprops/action-gh-release@v1 + tagging_message: ${{ steps.next-version.outputs.NEXT_VERSION }} + skip_dirty_check: true + commit_message: "[Release] XcodeGraph ${{ steps.next-version.outputs.NEXT_VERSION }}" + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + if: env.should-release == 'true' with: draft: false repository: tuist/XcodeGraph - name: ${{ steps.set_version.outputs.version }} - tag_name: ${{ steps.set_version.outputs.version }} - body: ${{ steps.changelog.outputs.changelog }} + name: ${{ steps.next-version.outputs.NEXT_VERSION }} + tag_name: ${{ steps.next-version.outputs.NEXT_VERSION }} + body: ${{ steps.release-notes.outputs.RELEASE_NOTES }} + target_commitish: ${{ steps.auto-commit-action.outputs.commit_hash }} \ No newline at end of file diff --git a/.mise.toml b/.mise.toml index 80a13e84..f3b5d989 100644 --- a/.mise.toml +++ b/.mise.toml @@ -2,3 +2,4 @@ tuist = "4.16.1" swiftlint = "0.54.0" swiftformat = "0.53.3" +"git-cliff" = "2.4.0" \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a335c90..ff07468c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog -## 0.9.0 - 2024-07-30 +All notable changes to this project will be documented in this file. -- no changes +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.8.0] - 2024-07-30 +### Details +#### Chore +- Update mikepenz/release-changelog-builder-action action to v4 + +#### Docs +- Update .all-contributorsrc [skip ci] +- Update README.md [skip ci] + +## [0.7.0] - 2024-06-25 +### Details +#### Docs +- Create .all-contributorsrc [skip ci] +- Update README.md [skip ci] + +[0.8.0]: https://github.com/tuist/command/compare/0.7.0..0.8.0 +[0.7.0]: https://github.com/tuist/command/compare/0.6.0..0.7.0 + + diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 00000000..afdcaf62 --- /dev/null +++ b/cliff.toml @@ -0,0 +1,108 @@ +# git-cliff ~ configuration file +# https://git-cliff.org/docs/configuration + +[remote.github] +owner = "tuist" +repo = "command" +# token = "" + +[changelog] +# template for the changelog header +header = """ +# Changelog\n +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n +""" +# template for the changelog body +# https://keats.github.io/tera/docs/#introduction +body = """ +{%- macro remote_url() -%} + https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} +{%- endmacro -%} + +{% if version -%} + ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else -%} + ## [Unreleased] +{% endif -%} + +### Details\ + +{% for group, commits in commits | group_by(attribute="group") %} + #### {{ group | upper_first }} + {%- for commit in commits %} + - {{ commit.message | upper_first | trim }}\ + {% if commit.github.username %} by @{{ commit.github.username }}{%- endif -%} + {% if commit.github.pr_number %} in \ + [#{{ commit.github.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.github.pr_number }}) \ + {%- endif -%} + {% endfor %} +{% endfor %} + +{%- if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %} + ## New Contributors +{%- endif -%} + +{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %} + * @{{ contributor.username }} made their first contribution + {%- if contributor.pr_number %} in \ + [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \ + {%- endif %} +{%- endfor %}\n +""" +# template for the changelog footer +footer = """ +{%- macro remote_url() -%} + https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} +{%- endmacro -%} + +{% for release in releases -%} + {% if release.version -%} + {% if release.previous.version -%} + [{{ release.version | trim_start_matches(pat="v") }}]: \ + {{ self::remote_url() }}/compare/{{ release.previous.version }}..{{ release.version }} + {% endif -%} + {% else -%} + [unreleased]: {{ self::remote_url() }}/compare/{{ release.previous.version }}..HEAD + {% endif -%} +{% endfor %} + +""" +# remove the leading and trailing whitespace from the templates +trim = true +# postprocessors +postprocessors = [] + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = true +# process each line of a commit as an individual commit +split_commits = false +# regex for preprocessing the commit messages +commit_preprocessors = [ + # remove issue numbers from commits + { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "" }, +] +# protect breaking changes from being skipped due to matching a skipping commit_parser +protect_breaking_commits = false +# filter out the commits that are not matched by commit parsers +filter_commits = false +# regex for matching git tags +tag_pattern = "[0-9].*" +# regex for skipping tags +skip_tags = "beta|alpha" +# regex for ignoring tags +ignore_tags = "rc" +# sort the tags topologically +topo_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "newest" + +[bump] +breaking_always_bump_major = true +features_always_bump_minor=true +initial_tag="0.2.1"