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

Support ignoring file deletions #76

Merged
merged 4 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 22 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@

## 🚀 Usage

Create a file named `labeler.yml` inside the `.github/workflows` directory and paste the following configuration:
Create a file named `labeler.yml` inside the `.github/workflows` directory and paste the following configuration.

> [!NOTE]
> Take into account that PR Size Labeler considers any line addition, deletion, or modification as a change by default, but you can configure it with [optional arguments](https://github.com/CodelyTV/pr-size-labeler?tab=readme-ov-file#%EF%B8%8F-arguments) such as `files_to_ignore`, `ignore_file_deletions`, or even `ignore_line_deletions`.

```yml
name: labeler
Expand Down Expand Up @@ -55,23 +58,24 @@ jobs:

## 🎛️ Arguments

| Name | Required | Default Value | Description |
|-------------------------|----------|----------------------|-------------------------------------------------------------------------------------------------------------------------|
| `GITHUB_TOKEN` | Yes | Automatically supplied| GitHub token needed to interact with the repository. |
| `xs_label` | No | 'size/xs' | Label for very small-sized PRs. |
| `xs_max_size` | No | '10' | Maximum number of changes allowed for XS-sized PRs. |
| `s_label` | No | 'size/s' | Label for small-sized PRs. |
| `s_max_size` | No | '100' | Maximum number of changes allowed for S-sized PRs. |
| `m_label` | No | 'size/m' | Label for medium-sized PRs. |
| `m_max_size` | No | '500' | Maximum number of changes allowed for M-sized PRs. |
| `l_label` | No | 'size/l' | Label for large-sized PRs. |
| `l_max_size` | No | '1000' | Maximum number of changes allowed for L-sized PRs. |
| `xl_label` | No | 'size/xl' | Label for extra-large-sized PRs. |
| `fail_if_xl` | No | 'false' | Whether to fail the GitHub workflow if the PR size is 'XL' (blocks the merge). |
| `message_if_xl` | No | Custom message | Message to display when a PR exceeds the 'XL' size limit. |
| `github_api_url` | No | 'https://api.github.com' | URL for the GitHub API, can be changed for GitHub Enterprise Servers. |
| `files_to_ignore` | No | '' | Files to ignore during PR size calculation. Supports newline or whitespace delimited list. |
| `ignore_line_deletions` | No | 'false' | Whether to ignore lines which are deleted when calculating the PR size. If set to 'true', deleted lines will be ignored. |
| Name | Required | Default Value | Description |
|-------------------------|----------|----------------------|---------------------------------------------------------------------------------------------------------------------------|
| `GITHUB_TOKEN` | Yes | Automatically supplied| GitHub token needed to interact with the repository. |
| `xs_label` | No | 'size/xs' | Label for very small-sized PRs. |
| `xs_max_size` | No | '10' | Maximum number of changes allowed for XS-sized PRs. |
| `s_label` | No | 'size/s' | Label for small-sized PRs. |
| `s_max_size` | No | '100' | Maximum number of changes allowed for S-sized PRs. |
| `m_label` | No | 'size/m' | Label for medium-sized PRs. |
| `m_max_size` | No | '500' | Maximum number of changes allowed for M-sized PRs. |
| `l_label` | No | 'size/l' | Label for large-sized PRs. |
| `l_max_size` | No | '1000' | Maximum number of changes allowed for L-sized PRs. |
| `xl_label` | No | 'size/xl' | Label for extra-large-sized PRs. A PR will be labeled as 'xl' if it exceeds the amount of changes defined in `l_max_size` |
| `fail_if_xl` | No | 'false' | Whether to fail the GitHub workflow if the PR size is 'XL' (blocks the merge). |
| `message_if_xl` | No | Custom message | Message to display when a PR exceeds the 'XL' size limit. |
| `github_api_url` | No | 'https://api.github.com' | URL for the GitHub API, can be changed for GitHub Enterprise Servers. |
| `files_to_ignore` | No | '' | Files to ignore during PR size calculation. Supports newline or whitespace delimited list. |
| `ignore_line_deletions` | No | 'false' | Whether to ignore lines which are deleted when calculating the PR size. If set to 'true', deleted lines will be ignored. |
| `ignore_file_deletions` | No | 'false' | Whether to ignore completely deleted files when calculating the PR size. If set to 'true', deleted files will be ignored. Distinct from `ignore_line_deletions` in that it only ignores files which are deleted completely. If `ignore_line_deletions` is used then using `ignore_file_deletions` is redundant. |

### Example for `files_to_ignore`:
```yml
Expand All @@ -83,11 +87,6 @@ files_to_ignore: |
"docs/*"
```

## 🤔 Basic concepts or assumptions

- PR Size Labeler considers any line addition, deletion, or modification as a change.
- A PR will be labeled as 'xl' if it exceeds the amount of changes defined in `l_max_size`.

## Contributing
If you would like to help improve the project, please read the [contribution guidelines](https://github.com/CodelyTV/pr-size-labeler/blob/main/.github/CONTRIBUTIONS.md).

Expand Down
5 changes: 5 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ inputs:
description: 'Whether to ignore lines which are deleted when calculating the PR size. If set to "true", deleted lines will be ignored.'
required: false
default: 'false'
ignore_file_deletions:
description: 'Whether to ignore files which are deleted when calculating the PR size. If set to "true", deleted files will be ignored.'
required: false
default: 'false'
runs:
using: 'docker'
image: 'Dockerfile'
Expand All @@ -82,6 +86,7 @@ runs:
- --message_if_xl="${{ inputs.message_if_xl }}"
- --files_to_ignore=${{ inputs.files_to_ignore }}
- --ignore_line_deletions=${{ inputs.ignore_line_deletions }}
- --ignore_file_deletions=${{ inputs.ignore_file_deletions }}
branding:
icon: 'tag'
color: 'green'
9 changes: 8 additions & 1 deletion src/github.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ github::calculate_total_modifications() {
local -r pr_number="${1}"
local -r files_to_ignore="${2}"
local -r ignore_line_deletions="${3}"
local -r ignore_file_deletions="${4}"

local additions=0
local deletions=0

if [ -z "$files_to_ignore" ]; then
if [ -z "$files_to_ignore" ] && [ "$ignore_file_deletions" != "true" ]; then
local -r body=$(curl -sSL -H "Authorization: token $GITHUB_TOKEN" -H "$GITHUB_API_HEADER" "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/pulls/$pr_number")

additions=$(echo "$body" | jq '.additions')
Expand All @@ -19,12 +20,18 @@ github::calculate_total_modifications() {
((deletions += $(echo "$body" | jq '.deletions')))
fi
else
# NOTE: this code is not resilient to changes w/ > 100 files as we're not paginating
local -r body=$(curl -sSL -H "Authorization: token $GITHUB_TOKEN" -H "$GITHUB_API_HEADER" "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/pulls/$pr_number/files?per_page=100")

for file in $(echo "$body" | jq -r '.[] | @base64'); do
filename=$(jq::base64 '.filename')
status=$(jq::base64 '.status')
ignore=false

if [[ ( "$ignore_file_deletions" == "true" || "$ignore_line_deletions" == "true" ) && "$status" == "removed" ]]; then
continue
fi

for pattern in $files_to_ignore; do
if [[ $filename == $pattern ]]; then
ignore=true
Expand Down
3 changes: 2 additions & 1 deletion src/labeler.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ labeler::label() {
local -r message_if_xl="${11}"
local -r files_to_ignore="${12}"
local -r ignore_line_deletions="${13}"
local -r ignore_file_deletions="${14}"

local -r pr_number=$(github_actions::get_pr_number)
local -r total_modifications=$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions")
local -r total_modifications=$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions" "$ignore_file_deletions")

log::message "Total modifications (additions + deletions): $total_modifications"
log::message "Ignoring files (if present): $files_to_ignore"
Expand Down
5 changes: 3 additions & 2 deletions src/main.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ source "$PR_SIZE_LABELER_HOME/src/misc.sh"
##? Adds a size label to a GitHub Pull Request
##?
##? Usage:
##? main.sh --github_token=<token> --xs_label=<label> --xs_max_size=<size> --s_label=<label> --s_max_size=<size> --m_label=<label> --m_max_size=<size> --l_label=<label> --l_max_size=<size> --xl_label=<label> --fail_if_xl=<false> --message_if_xl=<message> --github_api_url=<url> --files_to_ignore=<files> --ignore_line_deletions=<false>
##? main.sh --github_token=<token> --xs_label=<label> --xs_max_size=<size> --s_label=<label> --s_max_size=<size> --m_label=<label> --m_max_size=<size> --l_label=<label> --l_max_size=<size> --xl_label=<label> --fail_if_xl=<false> --message_if_xl=<message> --github_api_url=<url> --files_to_ignore=<files> --ignore_line_deletions=<false> --ignore_file_deletions=<false>
main() {
eval "$(/root/bin/docpars -h "$(grep "^##?" "$PR_SIZE_LABELER_HOME/src/main.sh" | cut -c 5-)" : "$@")"

Expand All @@ -32,7 +32,8 @@ main() {
"$fail_if_xl" \
"$message_if_xl" \
"$files_to_ignore" \
"$ignore_line_deletions"
"$ignore_line_deletions" \
"$ignore_file_deletions"

exit $?
}
19 changes: 19 additions & 0 deletions tests/fixtures/pull_request_files_api
Original file line number Diff line number Diff line change
@@ -1,74 +1,93 @@
[
{
"filename": ".editorconfig",
"status": "added",
"additions": 9,
"deletions": 0,
"changes": 9
},
{
"filename": ".github/workflows/ci.yml",
"status": "modified",
"additions": 17,
"deletions": 0,
"changes": 17
},
{
"filename": "asdasdasd.lock",
"status": "modified",
"additions": 1188,
"deletions": 0,
"changes": 1188
},
{
"filename": "entrypoint.sh",
"status": "modified",
"additions": 4,
"deletions": 4,
"changes": 8
},
{
"filename": "src/ensure.sh",
"status": "modified",
"additions": 4,
"deletions": 4,
"changes": 8
},
{
"filename": "src/github.sh",
"status": "added",
"additions": 89,
"deletions": 76,
"changes": 165
},
{
"filename": "src/github_actions.sh",
"status": "modified",
"additions": 1,
"deletions": 1,
"changes": 2
},
{
"filename": "src/inner.lock",
"status": "modified",
"additions": 1188,
"deletions": 0,
"changes": 1188
},
{
"filename": "src/labeler.sh",
"status": "modified",
"additions": 48,
"deletions": 48,
"changes": 96
},
{
"filename": "src/log.sh",
"status": "modified",
"additions": 17,
"deletions": 0,
"changes": 17
},
{
"filename": "src/main.sh",
"status": "modified",
"additions": 34,
"deletions": 23,
"changes": 57
},
{
"filename": "src/misc.sh",
"status": "modified",
"additions": 10,
"deletions": 14,
"changes": 24
},
{
"filename": "deleted_file.txt",
"status": "removed",
"additions": 0,
"deletions": 123,
"changes": 123
}
]
32 changes: 25 additions & 7 deletions tests/github_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,54 @@ function set_up() {
pr_number=123
files_to_ignore=''
ignore_line_deletions='false'
ignore_file_deletions='false'

function test_should_count_changes() {
mock curl cat ./tests/fixtures/pull_request_api

assert_match_snapshot "$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions")"
assert_match_snapshot "$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions" "$ignore_file_deletions")"
}

function test_should_count_changes_ignore_deletions() {
function test_should_count_changes_ignore_line_deletions() {
ignore_line_deletions='true'

mock curl cat ./tests/fixtures/pull_request_api

assert_match_snapshot "$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions")"
assert_match_snapshot "$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions" "$ignore_file_deletions")"
}

# NOTE: when `files_to_ignore` is set, we have to invoke the PR files API and iterate each file
# NOTE: when `files_to_ignore` or `ignore_file_deletions` is set, we have to invoke the PR files API and iterate each file
# one at at time. This is why the mock call is diffent in the subsequent test cases
function test_should_count_changes_ignore_file_deletions() {
ignore_file_deletions='true'

mock curl cat ./tests/fixtures/pull_request_files_api

assert_match_snapshot "$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions" "$ignore_file_deletions")"
}

function test_should_ignore_files_with_glob() {
files_to_ignore=("*.lock" ".editorconfig")

mock curl cat ./tests/fixtures/pull_request_files_api

assert_match_snapshot "$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions")"
assert_match_snapshot "$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions" "$ignore_file_deletions")"
}

function test_should_ignore_files_with_glob_ignore_deletions() {
function test_should_ignore_files_with_glob_ignore_line_deletions() {
files_to_ignore=("*.lock" ".editorconfig")
ignore_line_deletions='true'

mock curl cat ./tests/fixtures/pull_request_files_api

assert_match_snapshot "$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions")"
assert_match_snapshot "$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions" "$ignore_file_deletions")"
}

function test_should_ignore_files_with_glob_ignore_file_deletions() {
files_to_ignore=("*.lock" ".editorconfig")
ignore_file_deletions='true'

mock curl cat ./tests/fixtures/pull_request_files_api

assert_match_snapshot "$(github::calculate_total_modifications "$pr_number" "${files_to_ignore[*]}" "$ignore_line_deletions" "$ignore_file_deletions")"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2779
Original file line number Diff line number Diff line change
@@ -1 +1 @@
394
517
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
394
Loading