From b7fe0f9fb75749b90c559c7f7d0587f6ce96d75f Mon Sep 17 00:00:00 2001
From: Adam Bovill <a@turo.com>
Date: Wed, 13 Sep 2023 22:08:03 +0000
Subject: [PATCH] fix(release-notes-preview): add breaking changes doc check

This adds a new check that enforces that a breaking changes document has been created.
---
 .github/workflows/ci.yaml         |   2 +-
 README.md                         |   6 +-
 lint-release-notes/README.md      |  57 +++++++++++
 lint-release-notes/action.yaml    | 165 ++++++++++++++++++++++++++++++
 release-notes-preview/README.md   |  50 +--------
 release-notes-preview/action.yaml |  94 ++++++++++++++++-
 6 files changed, 319 insertions(+), 55 deletions(-)
 create mode 100644 lint-release-notes/README.md
 create mode 100644 lint-release-notes/action.yaml

diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 7faf124..3aa76cc 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -13,7 +13,7 @@ jobs:
         uses: actions/checkout@v4
         with:
           fetch-depth: 0
-      - uses: ./release-notes-preview
+      - uses: ./lint-release-notes
         with:
           github-token: ${{ secrets.GITHUB_TOKEN }}
   lint:
diff --git a/README.md b/README.md
index 6c45ab1..4143a00 100644
--- a/README.md
+++ b/README.md
@@ -13,13 +13,13 @@ GitHub Actions for handling releases.
 
 ## Actions
 
-### action: [`release-notes-preview`](./release-notes-preview)
+### action: [`release-notes-preview`](./lint-release-notes)
 
 Automatically generate release notes using semantic-release and post them as a comment in a pull request with the changes that would be included in the next version of the codebase if the pull request is merged.
 
-See usage [here](./release-notes-preview/README.md#usage).
+See usage [here](lint-release-notes/README.md#usage).
 
-Documentation is found [here](./release-notes-preview/README.md).
+Documentation is found [here](lint-release-notes/README.md).
 
 ## Get Help
 
diff --git a/lint-release-notes/README.md b/lint-release-notes/README.md
new file mode 100644
index 0000000..8b7175e
--- /dev/null
+++ b/lint-release-notes/README.md
@@ -0,0 +1,57 @@
+# GitHub Action Lint Release Notes
+
+## Description
+
+Github action that lints release notes. It generates release notes using semantic-release and posts them as a comment in
+a pull request with the changes that would be included in the next version of the codebase if the pull request is
+merged. It also will fail if there are breaking changes and no `v<major-version>.md` doc has been created.
+
+## Configuration
+
+### Step1: Set any [Semantic Release Configuration](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#configuration) in your repository.
+
+### Step2: [Add Secrets](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets) in your repository for the [Semantic Release Authentication](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/ci-configuration.md#authentication) Environment Variables.
+
+### Step3: Add a [Workflow File](https://help.github.com/en/articles/workflow-syntax-for-github-actions) to your repository to create custom automated processes.
+
+## Usage
+
+```yaml
+name: Release notes preview
+
+on:
+  # It's import that this runs on the push event, as semantic release will not run on pull_request events
+  push:
+    branches-ignore:
+      - main
+
+jobs:
+  lint-release-notes:
+    name: Lint release notes
+    steps:
+      - uses: open-turo/actions-release/lint-release-notes@v2
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+```
+
+## Inputs
+
+| parameter                     | description                                                                                                                                                               | required | default                                   |
+| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ----------------------------------------- |
+| checkout-repo                 | Perform checkout as first step of action                                                                                                                                  | `false`  | true                                      |
+| enforce-breaking-changes-docs | Ensure that an appropriate `v<major-version>.md` doc has been created if there are breaking changes in the PR. Fail if required and missing.                              | `false`  | `true`                                    |
+| extra-plugins                 | Extra plugins for pre-install. You can also specify specifying version range for the extra plugins if you prefer. Defaults to install @open-turo/semantic-release-config. | `false`  | @open-turo/semantic-release-config@^1.4.0 |
+| github-token                  | GitHub token that can checkout the repository as well as create tags/releases against it. e.g. 'secrets.GITHUB_TOKEN'                                                     | `true`   |                                           |
+| semantic-version              | Specify what version of semantic release to use                                                                                                                           | `false`  |                                           |
+
+## Outputs
+
+N/A
+
+## Runs
+
+This action is an `composite` action.
+
+## Notes
+
+- By default, this action will perform actions/checkout as its first step.
diff --git a/lint-release-notes/action.yaml b/lint-release-notes/action.yaml
new file mode 100644
index 0000000..467a278
--- /dev/null
+++ b/lint-release-notes/action.yaml
@@ -0,0 +1,165 @@
+name: GitHub Action Release Notes Preview
+description: GitHub Action that publishes a new release.
+inputs:
+  checkout-repo:
+    required: false
+    description: Perform checkout as first step of action
+    default: "true"
+  github-token:
+    required: true
+    description: GitHub token that can checkout the repository as well as create tags/releases against it. e.g. 'secrets.GITHUB_TOKEN'
+    default: ${{ github.token }}
+  enforce-breaking-changes-docs:
+    required: false
+    description: Ensure that an appropriate `v<major-version>.md` doc has been created if there are breaking changes in the PR.
+    default: "true"
+  extra-plugins:
+    required: false
+    description: Extra plugins for pre-install. You can also specify specifying version range for the extra plugins if you prefer.  Defaults to install @open-turo/semantic-release-config.
+    default: |
+      @open-turo/semantic-release-config
+  semantic-version:
+    required: false
+    description: Specify what version of semantic release to use
+runs:
+  using: composite
+  steps:
+    - uses: actions/checkout@v3
+      if: inputs.checkout-repo
+      with:
+        fetch-depth: 0
+    - name: Setup tools
+      uses: open-turo/action-setup-tools@v1
+      with:
+        node: 18.16.1
+    - uses: jwalton/gh-find-current-pr@v1
+      id: find-pull-request
+      with:
+        state: open
+    - name: Generate release notes
+      id: release-notes-preview
+      uses: open-turo/actions-release/semantic-release@v2
+      env:
+        GITHUB_TOKEN: ${{ inputs.github-token }}
+      with:
+        branches: ${{ github.ref_name }}
+        dry-run: true
+        extra-plugins: ${{ inputs.extra-plugins }}
+        semantic-version: ${{ inputs.semantic-version }}
+
+    # Add release notes preview to PR
+    - name: Check for release notes comment
+      uses: peter-evans/find-comment@v2
+      id: fc-release-notes
+      if: steps.find-pull-request.outputs.number != ''
+      with:
+        issue-number: ${{ steps.find-pull-request.outputs.number }}
+        comment-author: "github-actions[bot]"
+        body-includes: "<!-- release notes preview comment -->"
+    - name: Delete previous release note
+      if: steps.fc-release-notes.outputs.comment-id != ''
+      uses: jungwinter/comment@v1
+      with:
+        type: delete
+        comment_id: ${{ steps.fc-release-notes.outputs.comment-id }}
+        token: ${{ inputs.github-token }}
+    - name: Comment release notes preview
+      uses: peter-evans/create-or-update-comment@v1
+      if: steps.release-notes-preview.outputs.new-release-notes != '' && steps.find-pull-request.outputs.number != ''
+      with:
+        issue-number: ${{ steps.find-pull-request.outputs.number }}
+        body: |
+          ## Release notes preview
+          Below is a preview of the release notes if your PR gets merged.
+
+          ---
+          <!-- release notes preview comment -->
+          ${{ steps.release-notes-preview.outputs.new-release-notes }}
+    - name: Create no release created
+      uses: peter-evans/create-or-update-comment@v1
+      if: steps.release-notes-preview.outputs.new-release-notes == '' && steps.find-pull-request.outputs.number != ''
+      with:
+        issue-number: ${{ steps.find-pull-request.outputs.number }}
+        body: |
+          <!-- release notes preview comment -->
+          ## Release notes preview
+          **_No_ new release will be created.**
+
+          If you are expecting a release, you will need to either fix a bug or add a feature.
+          Chores, CI, docs, refactoring, style and other changes will not trigger a release.
+
+    # Ensure that a breaking changes doc has been created
+    - name: Check for breaking changes comment
+      uses: peter-evans/find-comment@v2
+      id: fc-breaking-changes
+      if: steps.find-pull-request.outputs.number != ''
+      with:
+        issue-number: ${{ steps.find-pull-request.outputs.number }}
+        comment-author: "github-actions[bot]"
+        body-includes: "<!-- breaking changes comment -->"
+    - name: Delete previous breaking changes comment
+      if: steps.fc-breaking-changes.outputs.comment-id != ''
+      uses: jungwinter/comment@v1
+      with:
+        type: delete
+        comment_id: ${{ steps.fc-breaking-changes.outputs.comment-id }}
+        token: ${{ inputs.github-token }}
+    - name: "Check File Existence"
+      id: breaking-changes-file
+      shell: bash
+      run: |
+        set -e
+        breaking_changes_file_missing=false
+        if [ "${{ steps.release-notes-preview.outputs.new-release-published }}" = "true" ]; then
+          echo "new release published"
+          if [ "${{ steps.release-notes-preview.outputs.new-release-type }}" = "major" ]; then
+            echo "braking change"
+            file_path="docs/breaking-changes/v${{ steps.release-notes-preview.outputs.new-release-major-version }}.md"
+            # Check if the file exists
+            if [ -e "$file_path" ]; then
+              echo "breaking change doc $file_path exists."
+            else
+              echo "breaking change doc $file_path does not exist."
+              breaking_changes_file_missing=true
+            fi
+          fi
+        fi
+        echo "required=${breaking_changes_file_missing}" >> $GITHUB_OUTPUT
+    - name: Comment missing breaking changes doc
+      uses: peter-evans/create-or-update-comment@v1
+      if: steps.breaking-changes-file.outputs.required && inputs.enforce-breaking-changes-docs && steps.find-pull-request.outputs.number != ''
+      with:
+        issue-number: ${{ steps.find-pull-request.outputs.number }}
+        body: |
+          ## Error: missing breaking changes documentation
+          This pull request contains breaking changes, but no documentation has been added to `docs/breaking-changes/v${{ steps.release-notes-preview.outputs.new-release-major-version }}.md`.
+
+          <details>
+            <summary>Instructions for creating breaking changes document:</summary>
+
+          ```shell
+          mkdir -p docs/breaking-changes
+          cat <<EOF > docs/breaking-changes/v${{ steps.release-notes-preview.outputs.new-release-major-version }}.md
+          # Breaking changes in v${{ steps.release-notes-preview.outputs.new-release-major-version }}
+
+          [//]: # "Brief description of current major version release scope"
+
+          ## Description of changes
+
+          [//]: # "Elaborate and add context to help the developer understand the changes."
+
+          ## Upgrade instructions
+
+          [//]: # "Required and suggested prerequisites, example code, etc."
+
+          EOF
+          ```
+          </details>
+
+          ---
+          <!-- breaking changes comment -->
+    - name: Fail if we are checking for the breaking changes doc and it is missing
+      if: steps.breaking-changes-file.outputs.required && inputs.enforce-breaking-changes-docs
+      shell: bash
+      run: |
+        echo "::error::Breaking changes document is missing. Expected: ``docs/breaking-changes/v${{ steps.release-notes-preview.outputs.new-release-major-version }}.md``" && exit 1
diff --git a/release-notes-preview/README.md b/release-notes-preview/README.md
index cab9a1a..208f083 100644
--- a/release-notes-preview/README.md
+++ b/release-notes-preview/README.md
@@ -1,51 +1,5 @@
-# GitHub Action Release Notes Preview
+# DEPRECATED!!!! GitHub Action Release Notes Preview
 
 ## Description
 
-Github action that generates release notes using semantic-release and posts them as a comment in a pull request with the changes that would be included in the next version of the codebase if the pull request is merged.
-
-## Configuration
-
-### Step1: Set any [Semantic Release Configuration](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#configuration) in your repository.
-
-### Step2: [Add Secrets](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets) in your repository for the [Semantic Release Authentication](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/ci-configuration.md#authentication) Environment Variables.
-
-### Step3: Add a [Workflow File](https://help.github.com/en/articles/workflow-syntax-for-github-actions) to your repository to create custom automated processes.
-
-## Usage
-
-```yaml
-name: Release notes preview
-
-on:
-  # It's import that this runs on the push event, as semantic release will not run on pull_request events
-  push:
-
-jobs:
-  release-notes:
-    name: Release notes preview
-    steps:
-      - uses: open-turo/actions-release/release-notes-preview@v1
-        with:
-          github-token: ${{ secrets.GITHUB_TOKEN }}
-```
-
-## Inputs
-
-| parameter        | description                                                                                                                                                               | required | default                                   |
-| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ----------------------------------------- |
-| extra-plugins    | Extra plugins for pre-install. You can also specify specifying version range for the extra plugins if you prefer. Defaults to install @open-turo/semantic-release-config. | `false`  | @open-turo/semantic-release-config@^1.4.0 |
-| github-token     | GitHub token that can checkout the repository as well as create tags/releases against it. e.g. 'secrets.GITHUB_TOKEN'                                                     | `true`   |                                           |
-| semantic-version | Specify what version of semantic release to use                                                                                                                           | `false`  |                                           |
-
-## Outputs
-
-N/A
-
-## Runs
-
-This action is an `composite` action.
-
-## Notes
-
-- By default, this action will perform actions/checkout as its first step.
+This has been deprecated and will be removed in the future. Please use `open-turo/actions-release/lint-release-notes@v1`.
diff --git a/release-notes-preview/action.yaml b/release-notes-preview/action.yaml
index d80b929..73bd2a8 100644
--- a/release-notes-preview/action.yaml
+++ b/release-notes-preview/action.yaml
@@ -5,6 +5,10 @@ inputs:
     required: true
     description: GitHub token that can checkout the repository as well as create tags/releases against it. e.g. 'secrets.GITHUB_TOKEN'
     default: ${{ github.token }}
+  enforce-breaking-changes-docs:
+    required: false
+    description: Ensure that an appropriate `v<major-version>.md` doc has been created if there are breaking changes in the PR. Fail if required and missing.
+    default: "true"
   extra-plugins:
     required: false
     description: Extra plugins for pre-install. You can also specify specifying version range for the extra plugins if you prefer.  Defaults to install @open-turo/semantic-release-config.
@@ -16,6 +20,9 @@ inputs:
 runs:
   using: composite
   steps:
+    - shell: bash
+      run: |
+        echo "::error::DEPRECATION: open-turo/actions-release/release-notes-preview@v1 has been deprecated.  Please use open-turo/actions-release/lint-release-notes@v1."
     - uses: actions/checkout@v3
       with:
         fetch-depth: 0
@@ -37,20 +44,22 @@ runs:
         dry-run: true
         extra-plugins: ${{ inputs.extra-plugins }}
         semantic-version: ${{ inputs.semantic-version }}
+
+    # Add release notes preview to PR
     - name: Check for release notes comment
       uses: peter-evans/find-comment@v2
-      id: fc
+      id: fc-release-notes
       if: steps.find-pull-request.outputs.number != ''
       with:
         issue-number: ${{ steps.find-pull-request.outputs.number }}
         comment-author: "github-actions[bot]"
         body-includes: "<!-- release notes preview comment -->"
     - name: Delete previous release note
-      if: steps.fc.outputs.comment-id != ''
+      if: steps.fc-release-notes.outputs.comment-id != ''
       uses: jungwinter/comment@v1
       with:
         type: delete
-        comment_id: ${{ steps.fc.outputs.comment-id }}
+        comment_id: ${{ steps.fc-release-notes.outputs.comment-id }}
         token: ${{ inputs.github-token }}
     - name: Comment release notes preview
       uses: peter-evans/create-or-update-comment@v1
@@ -58,6 +67,9 @@ runs:
       with:
         issue-number: ${{ steps.find-pull-request.outputs.number }}
         body: |
+          # DEPRECATION:
+          This action has been deprecated.  Please update to use `open-turo/actions-release/lint-release-notes@v1`.
+
           ## Release notes preview
           Below is a preview of the release notes if your PR gets merged.
 
@@ -76,3 +88,79 @@ runs:
 
           If you are expecting a release, you will need to either fix a bug or add a feature.
           Chores, CI, docs, refactoring, style and other changes will not trigger a release.
+
+    # Ensure that a breaking changes doc has been created
+    - name: Check for breaking changes comment
+      uses: peter-evans/find-comment@v2
+      id: fc-breaking-changes
+      if: steps.find-pull-request.outputs.number != ''
+      with:
+        issue-number: ${{ steps.find-pull-request.outputs.number }}
+        comment-author: "github-actions[bot]"
+        body-includes: "<!-- breaking changes comment -->"
+    - name: Delete previous breaking changes comment
+      if: steps.fc-breaking-changes.outputs.comment-id != ''
+      uses: jungwinter/comment@v1
+      with:
+        type: delete
+        comment_id: ${{ steps.fc-breaking-changes.outputs.comment-id }}
+        token: ${{ inputs.github-token }}
+    - name: "Check File Existence"
+      id: breaking-changes-file
+      shell: bash
+      run: |
+        set -e
+        breaking_changes_file_missing=false
+        if [ "${{ steps.release-notes-preview.outputs.new-release-published }}" = "true" ]; then
+          echo "new release published"
+          if [ "${{ steps.release-notes-preview.outputs.new-release-type }}" = "major" ]; then
+            echo "braking change"
+            file_path="docs/breaking-changes/v${{ steps.release-notes-preview.outputs.new-release-major-version }}.md"
+            # Check if the file exists
+            if [ -e "$file_path" ]; then
+              echo "breaking change doc $file_path exists."
+            else
+              echo "breaking change doc $file_path does not exist."
+              breaking_changes_file_missing=true
+            fi
+          fi
+        fi
+        echo "required=${breaking_changes_file_missing}" >> $GITHUB_OUTPUT
+    - name: Comment missing breaking changes doc
+      uses: peter-evans/create-or-update-comment@v1
+      if: steps.breaking-changes-file.outputs.required && inputs.enforce-breaking-changes-docs && steps.find-pull-request.outputs.number != ''
+      with:
+        issue-number: ${{ steps.find-pull-request.outputs.number }}
+        body: |
+          ## Error: missing breaking changes documentation
+          This pull request contains breaking changes, but no documentation has been added to `docs/breaking-changes/v${{ steps.release-notes-preview.outputs.new-release-major-version }}.md`.
+
+          <details>
+            <summary>Instructions for creating breaking changes document:</summary>
+
+          ```shell
+          mkdir -p docs/breaking-changes
+          cat <<EOF > docs/breaking-changes/v${{ steps.release-notes-preview.outputs.new-release-major-version }}.md
+          # Breaking changes in v${{ steps.release-notes-preview.outputs.new-release-major-version }}
+
+          [//]: # "Brief description of current major version release scope"
+
+          ## Description of changes
+
+          [//]: # "Elaborate and add context to help the developer understand the changes."
+
+          ## Upgrade instructions
+
+          [//]: # "Required and suggested prerequisites, example code, etc."
+
+          EOF
+          ```
+          </details>
+
+          ---
+          <!-- breaking changes comment -->
+    - name: Fail if we are checking for the breaking changes doc and it is missing
+      if: steps.breaking-changes-file.outputs.required && inputs.enforce-breaking-changes-docs
+      shell: bash
+      run: |
+        echo "::error::Breaking changes document is missing. Expected: ``docs/breaking-changes/v${{ steps.release-notes-preview.outputs.new-release-major-version }}.md``" && exit 1