Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: outputs the error messages #194

Merged
merged 11 commits into from Sep 26, 2022
44 changes: 44 additions & 0 deletions .github/workflows/lint-pr-title-preview-outputErrorMessage
@@ -0,0 +1,44 @@
name: "Lint PR title preview (current branch, outputErrorMessage)"
on:
pull_request:
types:
- opened
- edited
- synchronize

jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16
- run: yarn install
- run: yarn build
- uses: ./
id: lint_pr_title
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: marocchino/sticky-pull-request-comment@v2
# When the previous steps fails, the workflow would stop. By adding this
# condition you can continue the execution with the populated error message.
if: always()
with:
header: pr-title-lint-error
message: |
Hey there and thank you for opening this pull request! 👋🏼

We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted.

Details:

```
${{ steps.lint_pr_title.outputs.error_message }}
```
# Delete a previous comment when the issue has been resolved
- if: ${{ steps.lint_pr_title.outputs.error_message == null }}
uses: marocchino/sticky-pull-request-comment@v2
with:
header: pr-title-lint-error
delete: true
56 changes: 56 additions & 0 deletions README.md
Expand Up @@ -113,6 +113,62 @@ There are two events that can be used as triggers for this action, each with dif
1. [`pull_request_target`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request_target): This allows the action to be used in a fork-based workflow, where e.g. you want to accept pull requests in a public repository. In this case, the configuration from the main branch of your repository will be used for the check. This means that you need to have this configuration in the main branch for the action to run at all (e.g. it won't run within a PR that adds the action initially). Also if you change the configuration in a PR, the changes will not be reflected for the current PR – only subsequent ones after the changes are in the main branch.
2. [`pull_request`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request): This configuration uses the latest configuration that is available in the current branch. It will only work if the branch is based in the repository itself. If this configuration is used and a pull request from a fork is opened, you'll encounter an error as the GitHub token environment parameter is not available. This option is viable if all contributors have write access to the repository.

## Outputs
juninholiveira marked this conversation as resolved.
Show resolved Hide resolved

In case the validation fails, this action will populate the `error_message` ouput.
juninholiveira marked this conversation as resolved.
Show resolved Hide resolved

[An output can be used in other steps](https://docs.github.com/en/actions/using-jobs/defining-outputs-for-jobs), for example to comment the error message onto the pull request.

<details>
<summary>Example</summary>

```yml
name: "Lint PR"

on:
pull_request_target:
types:
- opened
- edited
- synchronize

jobs:
main:
name: Validate PR title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v4
id: lint_pr_title
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- uses: marocchino/sticky-pull-request-comment@v2
# When the previous steps fails, the workflow would stop. By adding this
# condition you can continue the execution with the populated error message.
if: always()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juninholiveira Have you tested what happens when the validation no longer fails with this step? I guess ideally the comment would be removed. It seems like the action would provide an option for a workflow like this, maybe we can set an argument conditionally based on if there's an error_message?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amannn proper setup is:

      # Comments the error message from the above lint_pr_title action 
      - if: always()
        name: Comment on PR
        uses: marocchino/sticky-pull-request-comment@v2
        with:
          header: pr-title-lint-error
          message: |
                   Hey there 👋🏼 thanks for opening the PR but we need you to adjust the title of the pull request. 
                   We require all PRs to follow [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/). More details 👇🏼
                   
                   ```
                   ${{ steps.lint_pr_title.outputs.error_message}}
                   ```
       # deletes the error comment if the title is correct            
      - if: ${{ steps.lint_pr_title.outputs.error_message == null }}
        name: delete the comment
        uses: marocchino/sticky-pull-request-comment@v2
        with:   
          header: pr-title-lint-error
          delete: true

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@derberg Thanks a lot for sharing your configuration! That looks really good to me, I've just updated this PR accordingly and will merge once CI is green.

Thank you @juninholiveira for taking the lead with this feature! 👏

with:
header: pr-title-lint-error
message: |
Hey there and thank you for opening this pull request! 👋🏼

We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted.

Details:

```
${{ steps.lint_pr_title.outputs.error_message }}
```

# Delete a previous comment when the issue has been resolved
- if: ${{ steps.lint_pr_title.outputs.error_message == null }}
uses: marocchino/sticky-pull-request-comment@v2
with:
header: pr-title-lint-error
delete: true
```

</details>

## Legacy configuration

When using "Squash and merge" on a PR with only one commit, GitHub will suggest using that commit message instead of the PR title for the merge commit and it's easy to commit this by mistake. To help out in this situation this action supports two configuration options. However, [GitHub has introduced an option to streamline this behaviour](https://github.blog/changelog/2022-05-11-default-to-pr-titles-for-squash-merge-commit-messages/), so using that instead should be preferred.
Expand Down
27 changes: 16 additions & 11 deletions src/validatePrTitle.js
@@ -1,3 +1,4 @@
const core = require('@actions/core');
const conventionalCommitsConfig = require('conventional-changelog-conventionalcommits');
const conventionalCommitTypes = require('conventional-commit-types');
const parser = require('conventional-commits-parser').sync;
Expand Down Expand Up @@ -52,30 +53,29 @@ module.exports = async function validatePrTitle(
}

if (!result.type) {
throw new Error(
raiseError(
`No release type found in pull request title "${prTitle}". Add a prefix to indicate what kind of release this pull request corresponds to. For reference, see https://www.conventionalcommits.org/\n\n${printAvailableTypes()}`
);
}

if (!result.subject) {
throw new Error(`No subject found in pull request title "${prTitle}".`);
raiseError(`No subject found in pull request title "${prTitle}".`);
}

if (!types.includes(result.type)) {
throw new Error(
raiseError(
`Unknown release type "${
result.type
}" found in pull request title "${prTitle}". \n\n${printAvailableTypes()}`
);
}

if (requireScope && !result.scope) {
let msg = `No scope found in pull request title "${prTitle}".`;
let message = `No scope found in pull request title "${prTitle}".`;
if (scopes) {
msg += ` Use one of the available scopes: ${scopes.join(', ')}.`;
message += ` Use one of the available scopes: ${scopes.join(', ')}.`;
}

throw new Error(msg);
raiseError(message);
}

const givenScopes = result.scope
Expand All @@ -84,7 +84,7 @@ module.exports = async function validatePrTitle(

const unknownScopes = givenScopes ? givenScopes.filter(isUnknownScope) : [];
if (scopes && unknownScopes.length > 0) {
throw new Error(
raiseError(
`Unknown ${
unknownScopes.length > 1 ? 'scopes' : 'scope'
} "${unknownScopes.join(
Expand All @@ -99,7 +99,7 @@ module.exports = async function validatePrTitle(
? givenScopes.filter(isDisallowedScope)
: [];
if (disallowScopes && disallowedScopes.length > 0) {
throw new Error(
raiseError(
`Disallowed ${
disallowedScopes.length === 1 ? 'scope was' : 'scopes were'
} found: ${disallowScopes.join(', ')}`
Expand All @@ -113,8 +113,7 @@ module.exports = async function validatePrTitle(
title: prTitle
});
}

throw new Error(message);
raiseError(message);
}

if (subjectPattern) {
Expand All @@ -133,4 +132,10 @@ module.exports = async function validatePrTitle(
);
}
}

function raiseError(message) {
core.setOutput('error_message', message);

throw new Error(message);
}
};