Repository: release-drafter/release-drafter
Pull request #513 (2020-05-06 13:40:47)

Add support for automatic version resolution
# Motivation
In our team, the person initiating the release often doesn't have context on whether the release should be patch, minor or major. People working on invididual PRs have better judgement on whether their change is substantial enough to be major/minor/patch.  Therefore, they should apply a github label to decide the nature of the change.  Currently, release-drafter provides no way to automatically determine the version number.

This change adds the ability to determine what the next version number should be based upon currentVersion + maxIncrement(major, minor, patch).

Please see updates to the `README.md` for details.

# Feedback required
- I'm not experienced in JS, so would appreciate advice and tips where necessary about code style and design.  I've tried to do this in a way that makes sense from my understanding of the code.
- Please give an early indication of the direction of travel of this PR.  I'm not sure if i've gone about it according to the best way possible.
- ~Please give advice on testing.  Again, because i am a JS dufus I didn't quite understand the testing structure, and the `resolveVersionKeyInc` method remains untested.  This would certainly need to be addressed before merging.~

Thanks, and look forward to contributing!!


Patch:
diff --git a/README.md b/README.md
index 9b2cc11..0524602 100644
--- a/README.md
+++ b/README.md
@@ -71,6 +71,17 @@ categories:
   - title: '🧰 Maintenance'
     label: 'chore'
 change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
+version-resolver:
+  major:
+    labels:
+      - 'major'
+  minor:
+    labels:
+      - 'minor'
+  patch:
+    labels:
+      - 'patch'
+  default: patch
 template: |
   ## Changes
 
@@ -92,11 +103,12 @@ You can configure Release Drafter using the following key in your `.github/relea
 | `branches`            | Optional | The branches to listen for configuration updates to `.github/release-drafter.yml` and for merge commits. Useful if you want to test the app on a pull request branch. Default is the repository’s default branch. |
 | `categories`          | Optional | Categorize pull requests using labels. Refer to [Categorize Pull Requests](#categorize-pull-requests) to learn more about this option.                                                                            |
 | `exclude-labels`      | Optional | Exclude pull requests using labels. Refer to [Exclude Pull Requests](#exclude-pull-requests) to learn more about this option.                                                                                     |
-| `include-labels`      | Optional | Include only the specified pull requests using labels. Refer to [Include Pull Requests](#include-pull-requests) to learn more about this option.                                                                                     |
+| `include-labels`      | Optional | Include only the specified pull requests using labels. Refer to [Include Pull Requests](#include-pull-requests) to learn more about this option.                                                                  |
 | `replacers`           | Optional | Search and replace content in the generated changelog body. Refer to [Replacers](#replacers) to learn more about this option.                                                                                     |
 | `sort-by`             | Optional | Sort changelog by merged_at or title. Can be one of: `merged_at`, `title`. Default: `merged_at`.                                                                                                                  |
 | `sort-direction`      | Optional | Sort changelog in ascending or descending order. Can be one of: `ascending`, `descending`. Default: `descending`.                                                                                                 |
 | `prerelease`          | Optional | Mark the draft release as pre-release. Default `false`.                                                                                                                                                           |
+| `version-resolver`    | Optional | Adjust the `$RESOLVED_VERSION` variable using labels. Refer to [Version Resolver](#version-resolver) to learn more about this                                                                                     |
 
 Release Drafter also supports [Probot Config](https://github.com/probot/probot-config), if you want to store your configuration files in a central repository. This allows you to share configurations between projects, and create a organization-wide configuration file by creating a repository named `.github` with the file `.github/release-drafter.yml`.
 
@@ -119,6 +131,7 @@ You can use any of the following variables in your `template`, `name-template` a
 | `$NEXT_PATCH_VERSION` | The next patch version number. For example, if the last tag or release was `v1.2.3`, the value would be `v1.2.4`. This is the most commonly used value. |
 | `$NEXT_MINOR_VERSION` | The next minor version number. For example, if the last tag or release was `v1.2.3`, the value would be `v1.3.0`.                                       |
 | `$NEXT_MAJOR_VERSION` | The next major version number. For example, if the last tag or release was `v1.2.3`, the value would be `v2.0.0`.                                       |
+| `$RESOLVED_VERSION`   | The next resolved version number, based on GitHub labels. Refer to [Version Resolution](#version-resolution) to learn more about this.                  |
 
 ## Version Template Variables
 
@@ -130,6 +143,28 @@ You can use any of the following variables in `version-template` to format the `
 | `$MINOR` | The minor version number. |
 | `$MAJOR` | The major version number. |
 
+## Version Resolver
+
+With the `version-resolver` option version number incrementing can be resolved automatically based on labels of individual pull requests. Append the following to your `.github/release-drafter.yml` file:
+
+```yml
+version-resolver:
+  major:
+    labels:
+      - 'major'
+  minor:
+    labels:
+      - 'minor'
+  patch:
+    labels:
+      - 'patch'
+  default: patch
+```
+
+The above config controls the output of the `$RESOLVED_VERSION` variable.
+
+If a pull requests is found with the label `major`/`minor`/`patch`, the corresponding version key will be incremented from a semantic version. The maximum out of major, minor and patch found in any of the pull requests will be used to increment the version number. If no pull requests are found with the assigned labels, the `default` will be assigned.
+
 ## Change Template Variables
 
 You can use any of the following variables in `change-template`:
@@ -175,7 +210,7 @@ Pull requests with the label "skip-changelog" will now be excluded from the rele
 
 ## Include Pull Requests
 
-With the `include-labels` option you can specify pull requests from the release notes using labels. Only pull requests that have the configured labels will be included in the pull request.  For example, append the following to your `.github/release-drafter.yml` file:
+With the `include-labels` option you can specify pull requests from the release notes using labels. Only pull requests that have the configured labels will be included in the pull request. For example, append the following to your `.github/release-drafter.yml` file:
 
 ```yml
 include-labels:
diff --git a/lib/default-config.js b/lib/default-config.js
index 7eeb1b6..94956f9 100644
--- a/lib/default-config.js
+++ b/lib/default-config.js
@@ -6,6 +6,12 @@ const DEFAULT_CONFIG = Object.freeze({
   'change-template': `* $TITLE (#$NUMBER) @$AUTHOR`,
   'no-changes-template': `* No changes`,
   'version-template': `$MAJOR.$MINOR.$PATCH`,
+  'version-resolver': {
+    major: { labels: [] },
+    minor: { labels: [] },
+    patch: { labels: [] },
+    default: 'patch',
+  },
   categories: [],
   'exclude-labels': [],
   'include-labels': [],
diff --git a/lib/releases.js b/lib/releases.js
index 8d4a028..37a289a 100644
--- a/lib/releases.js
+++ b/lib/releases.js
@@ -76,38 +76,42 @@ const contributorsSentence = ({ commits, pullRequests }) => {
   }
 }
 
-const categorizePullRequests = (pullRequests, config) => {
-  const { 
-    'exclude-labels': excludeLabels,
-    'include-labels': includeLabels,
-    categories 
-  } = config
-  const allCategoryLabels = categories.flatMap(category => category.labels)
-  const uncategorizedPullRequests = []
-  const categorizedPullRequests = [...categories].map((category) => {
-    return { ...category, pullRequests: [] }
-  })
-
-  const filterExcludedPullRequests = (pullRequest) => {
+const getFilterExcludedPullRequests = (excludeLabels) => {
+  return (pullRequest) => {
     const labels = pullRequest.labels.nodes
-
     if (labels.some((label) => excludeLabels.includes(label.name))) {
       return false
     }
     return true
   }
+}
 
-  const filterIncludedPullRequests = pullRequest => {
+const getFilterIncludedPullRequests = (includeLabels) => {
+  return (pullRequest) => {
     const labels = pullRequest.labels.nodes
-
-    if (includeLabels.length == 0 ||
-        labels.some(label => includeLabels.includes(label.name))) {
+    if (
+      includeLabels.length == 0 ||
+      labels.some((label) => includeLabels.includes(label.name))
+    ) {
       return true
     }
     return false
   }
+}
 
-  const filterUncategorizedPullRequests = pullRequest => {
+const categorizePullRequests = (pullRequests, config) => {
+  const {
+    'exclude-labels': excludeLabels,
+    'include-labels': includeLabels,
+    categories,
+  } = config
+  const allCategoryLabels = categories.flatMap((category) => category.labels)
+  const uncategorizedPullRequests = []
+  const categorizedPullRequests = [...categories].map((category) => {
+    return { ...category, pullRequests: [] }
+  })
+
+  const filterUncategorizedPullRequests = (pullRequest) => {
     const labels = pullRequest.labels.nodes
 
     if (
@@ -122,8 +126,8 @@ const categorizePullRequests = (pullRequests, config) => {
 
   // we only want pull requests that have yet to be categorized
   const filteredPullRequests = pullRequests
-    .filter(filterExcludedPullRequests)
-    .filter(filterIncludedPullRequests)
+    .filter(getFilterExcludedPullRequests(excludeLabels))
+    .filter(getFilterIncludedPullRequests(includeLabels))
     .filter(filterUncategorizedPullRequests)
 
   categorizedPullRequests.map((category) => {
@@ -183,6 +187,32 @@ const generateChangeLog = (mergedPullRequests, config) => {
   return changeLog.join('').trim()
 }
 
+const resolveVersionKeyIncrement = (mergedPullRequests, config) => {
+  const priorityMap = {
+    patch: 1,
+    minor: 2,
+    major: 3,
+  }
+  const labelToKeyMap = Object.fromEntries(
+    Object.keys(priorityMap)
+      .flatMap((key) => [
+        config['version-resolver'][key].labels.map((label) => [label, key]),
+      ])
+      .flat()
+  )
+  const keys = mergedPullRequests
+    .filter(getFilterExcludedPullRequests(config['exclude-labels']))
+    .filter(getFilterIncludedPullRequests(config['include-labels']))
+    .flatMap((pr) => pr.labels.nodes.map((node) => labelToKeyMap[node.name]))
+    .filter(Boolean)
+  const keyPriorities = keys.map((key) => priorityMap[key])
+  const priority = Math.max(...keyPriorities)
+  const versionKey = Object.keys(priorityMap).find(
+    (key) => priorityMap[key] === priority
+  )
+  return versionKey || config['version-resolver'].default
+}
+
 module.exports.generateReleaseInfo = ({
   commits,
   config,
@@ -212,7 +242,8 @@ module.exports.generateReleaseInfo = ({
     config['version-template'],
     // Use the first override parameter to identify
     // a version, from the most accurate to the least
-    version || tag || name
+    version || tag || name,
+    resolveVersionKeyIncrement(mergedPullRequests, config)
   )
 
   if (versionInfo) {
diff --git a/lib/schema.js b/lib/schema.js
index abe579a..2d352ac 100644
--- a/lib/schema.js
+++ b/lib/schema.js
@@ -74,6 +74,15 @@ const schema = (context) => {
       )
       .default(DEFAULT_CONFIG.categories),
 
+    'version-resolver': Joi.object()
+      .keys({
+        major: Joi.object({ labels: Joi.array().items(Joi.string()).single() }),
+        minor: Joi.object({ labels: Joi.array().items(Joi.string()).single() }),
+        patch: Joi.object({ labels: Joi.array().items(Joi.string()).single() }),
+        default: Joi.string().valid('major', 'minor', 'patch').default('patch'),
+      })
+      .default(DEFAULT_CONFIG['version-resolver']),
+
     template: Joi.string().required(),
 
     _extends: Joi.string(),
diff --git a/lib/versions.js b/lib/versions.js
index 70ddf1b..157551f 100644
--- a/lib/versions.js
+++ b/lib/versions.js
@@ -24,11 +24,14 @@ const getTemplatableVersion = (input) => {
     $NEXT_MINOR_VERSION: splitSemVer({ ...input, inc: 'minor' }),
     $NEXT_PATCH_VERSION: splitSemVer({ ...input, inc: 'patch' }),
     $INPUT_VERSION: splitSemVer(input, 'inputVersion'),
-    $RESOLVED_VERSION: null,
+    $RESOLVED_VERSION: splitSemVer({
+      ...input,
+      inc: input.versionKeyIncrement || 'patch',
+    }),
   }
 
   templatableVersion.$RESOLVED_VERSION =
-    templatableVersion.$INPUT_VERSION || templatableVersion.$NEXT_PATCH_VERSION
+    templatableVersion.$INPUT_VERSION || templatableVersion.$RESOLVED_VERSION
 
   return templatableVersion
 }
@@ -43,7 +46,12 @@ const coerceVersion = (input) => {
     : semver.coerce(input)
 }
 
-module.exports.getVersionInfo = (release, template, inputVersion = null) => {
+module.exports.getVersionInfo = (
+  release,
+  template,
+  inputVersion = null,
+  versionKeyIncrement = null
+) => {
   const version = coerceVersion(release)
   inputVersion = coerceVersion(inputVersion)
 
@@ -56,6 +64,7 @@ module.exports.getVersionInfo = (release, template, inputVersion = null) => {
       version,
       template,
       inputVersion,
+      versionKeyIncrement,
     }),
   }
 }
diff --git a/schema.json b/schema.json
index fd3fcba..fd4ea3a 100644
--- a/schema.json
+++ b/schema.json
@@ -114,6 +114,7 @@
             "type": "string"
           },
           "labels": {
+            "default": [],
             "type": "array",
             "items": {
               "type": "string"
@@ -125,6 +126,63 @@
         "required": ["title"]
       }
     },
+    "version-resolver": {
+      "default": {
+        "major": {},
+        "minor": {},
+        "patch": {},
+        "default": "patch"
+      },
+      "type": "object",
+      "properties": {
+        "major": {
+          "type": "object",
+          "properties": {
+            "labels": {
+              "type": "array",
+              "items": {
+                "type": "string"
+              }
+            }
+          },
+          "additionalProperties": false,
+          "patterns": []
+        },
+        "minor": {
+          "type": "object",
+          "properties": {
+            "labels": {
+              "type": "array",
+              "items": {
+                "type": "string"
+              }
+            }
+          },
+          "additionalProperties": false,
+          "patterns": []
+        },
+        "patch": {
+          "type": "object",
+          "properties": {
+            "labels": {
+              "type": "array",
+              "items": {
+                "type": "string"
+              }
+            }
+          },
+          "additionalProperties": false,
+          "patterns": []
+        },
+        "default": {
+          "default": "patch",
+          "enum": ["major", "minor", "patch"],
+          "type": "string"
+        }
+      },
+      "additionalProperties": false,
+      "patterns": []
+    },
     "template": {
       "type": "string"
     },


Test patch:
diff --git a/test/fixtures/__generated__/graphql-commits-forking.json b/test/fixtures/__generated__/graphql-commits-forking.json
index cf82d0d..51c6629 100644
--- a/test/fixtures/__generated__/graphql-commits-forking.json
+++ b/test/fixtures/__generated__/graphql-commits-forking.json
@@ -163,6 +163,9 @@
                         "nodes": [
                           {
                             "name": "fix"
+                          },
+                          {
+                            "name": "patch"
                           }
                         ]
                       }
@@ -213,6 +216,9 @@
                         "nodes": [
                           {
                             "name": "fix"
+                          },
+                          {
+                            "name": "patch"
                           }
                         ]
                       }
@@ -263,6 +269,9 @@
                         "nodes": [
                           {
                             "name": "feature"
+                          },
+                          {
+                            "name": "minor"
                           }
                         ]
                       }
@@ -310,7 +319,14 @@
                       "mergedAt": "2020-05-26T20:16:44Z",
                       "isCrossRepository": false,
                       "labels": {
-                        "nodes": []
+                        "nodes": [
+                          {
+                            "name": "feature"
+                          },
+                          {
+                            "name": "major"
+                          }
+                        ]
                       }
                     },
                     {
diff --git a/test/fixtures/__generated__/graphql-commits-merge-commit.json b/test/fixtures/__generated__/graphql-commits-merge-commit.json
index 803e177..210a297 100644
--- a/test/fixtures/__generated__/graphql-commits-merge-commit.json
+++ b/test/fixtures/__generated__/graphql-commits-merge-commit.json
@@ -101,6 +101,9 @@
                         "nodes": [
                           {
                             "name": "fix"
+                          },
+                          {
+                            "name": "patch"
                           }
                         ]
                       }
@@ -135,6 +138,9 @@
                         "nodes": [
                           {
                             "name": "feature"
+                          },
+                          {
+                            "name": "minor"
                           }
                         ]
                       }
@@ -331,6 +337,9 @@
                         "nodes": [
                           {
                             "name": "fix"
+                          },
+                          {
+                            "name": "patch"
                           }
                         ]
                       }
@@ -365,6 +374,9 @@
                         "nodes": [
                           {
                             "name": "fix"
+                          },
+                          {
+                            "name": "patch"
                           }
                         ]
                       }
@@ -399,6 +411,9 @@
                         "nodes": [
                           {
                             "name": "feature"
+                          },
+                          {
+                            "name": "minor"
                           }
                         ]
                       }
@@ -433,6 +448,9 @@
                         "nodes": [
                           {
                             "name": "feature"
+                          },
+                          {
+                            "name": "minor"
                           }
                         ]
                       }
diff --git a/test/fixtures/__generated__/graphql-commits-overlapping-label.json b/test/fixtures/__generated__/graphql-commits-overlapping-label.json
index 95dc99b..ba135e2 100644
--- a/test/fixtures/__generated__/graphql-commits-overlapping-label.json
+++ b/test/fixtures/__generated__/graphql-commits-overlapping-label.json
@@ -102,6 +102,9 @@
                           {
                             "name": "bug"
                           },
+                          {
+                            "name": "patch"
+                          },
                           {
                             "name": "sentry"
                           }
@@ -138,6 +141,9 @@
                         "nodes": [
                           {
                             "name": "feature"
+                          },
+                          {
+                            "name": "minor"
                           }
                         ]
                       }
@@ -172,6 +178,9 @@
                         "nodes": [
                           {
                             "name": "feature"
+                          },
+                          {
+                            "name": "major"
                           }
                         ]
                       }
diff --git a/test/fixtures/__generated__/graphql-commits-rebase-merging.json b/test/fixtures/__generated__/graphql-commits-rebase-merging.json
index 552dc83..1a98ed0 100644
--- a/test/fixtures/__generated__/graphql-commits-rebase-merging.json
+++ b/test/fixtures/__generated__/graphql-commits-rebase-merging.json
@@ -165,6 +165,9 @@
                         "nodes": [
                           {
                             "name": "fix"
+                          },
+                          {
+                            "name": "patch"
                           }
                         ]
                       }
@@ -199,6 +202,9 @@
                         "nodes": [
                           {
                             "name": "fix"
+                          },
+                          {
+                            "name": "patch"
                           }
                         ]
                       }
@@ -233,6 +239,9 @@
                         "nodes": [
                           {
                             "name": "feature"
+                          },
+                          {
+                            "name": "minor"
                           }
                         ]
                       }
@@ -267,6 +276,9 @@
                         "nodes": [
                           {
                             "name": "feature"
+                          },
+                          {
+                            "name": "minor"
                           }
                         ]
                       }
@@ -301,6 +313,9 @@
                         "nodes": [
                           {
                             "name": "feature"
+                          },
+                          {
+                            "name": "major"
                           }
                         ]
                       }
diff --git a/test/fixtures/__generated__/graphql-commits-squash-merging.json b/test/fixtures/__generated__/graphql-commits-squash-merging.json
index 47d708f..91f13b5 100644
--- a/test/fixtures/__generated__/graphql-commits-squash-merging.json
+++ b/test/fixtures/__generated__/graphql-commits-squash-merging.json
@@ -101,6 +101,9 @@
                         "nodes": [
                           {
                             "name": "fix"
+                          },
+                          {
+                            "name": "patch"
                           }
                         ]
                       }
@@ -135,6 +138,9 @@
                         "nodes": [
                           {
                             "name": "feature"
+                          },
+                          {
+                            "name": "minor"
                           }
                         ]
                       }
@@ -169,6 +175,9 @@
                         "nodes": [
                           {
                             "name": "feature"
+                          },
+                          {
+                            "name": "major"
                           }
                         ]
                       }
diff --git a/test/fixtures/config/config-with-custom-version-resolver-major.yml b/test/fixtures/config/config-with-custom-version-resolver-major.yml
new file mode 100644
index 0000000..2cbb0fe
--- /dev/null
+++ b/test/fixtures/config/config-with-custom-version-resolver-major.yml
@@ -0,0 +1,28 @@
+name-template: 'v$RESOLVED_VERSION'
+tag-template: 'v$RESOLVED_VERSION'
+branches:
+  - master
+categories:
+  - title: '🚀 Features'
+    label: 'feature'
+  - title: '🐛 Bug fixes'
+    label: 'bug'
+  - title: '📄 Documentation'
+    label: 'documentation'
+  - title: '🧰 Maintenance'
+    label: 'maintenance'
+change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
+template: dummy
+version-resolver:
+  major:
+    labels:
+      - 'major'
+  minor:
+    labels:
+      - 'minor'
+  patch:
+    labels:
+      - 'patch'
+  default: minor
+exclude-labels:
+  - skip-changelog
\ No newline at end of file
diff --git a/test/fixtures/config/config-with-custom-version-resolver-minor.yml b/test/fixtures/config/config-with-custom-version-resolver-minor.yml
new file mode 100644
index 0000000..d2fcf10
--- /dev/null
+++ b/test/fixtures/config/config-with-custom-version-resolver-minor.yml
@@ -0,0 +1,28 @@
+name-template: 'v$RESOLVED_VERSION'
+tag-template: 'v$RESOLVED_VERSION'
+branches:
+  - master
+categories:
+  - title: '🚀 Features'
+    label: 'feature'
+  - title: '🐛 Bug fixes'
+    label: 'bug'
+  - title: '📄 Documentation'
+    label: 'documentation'
+  - title: '🧰 Maintenance'
+    label: 'maintenance'
+change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
+template: dummy
+version-resolver:
+  major:
+    labels:
+      - 'MAJ'
+  minor:
+    labels:
+      - 'minor'
+  patch:
+    labels:
+      - 'patch'
+  default: minor
+exclude-labels:
+  - skip-changelog
\ No newline at end of file
diff --git a/test/fixtures/config/config-with-custom-version-resolver-none.yml b/test/fixtures/config/config-with-custom-version-resolver-none.yml
new file mode 100644
index 0000000..64f1623
--- /dev/null
+++ b/test/fixtures/config/config-with-custom-version-resolver-none.yml
@@ -0,0 +1,28 @@
+name-template: 'v$RESOLVED_VERSION'
+tag-template: 'v$RESOLVED_VERSION'
+branches:
+  - master
+categories:
+  - title: '🚀 Features'
+    label: 'feature'
+  - title: '🐛 Bug fixes'
+    label: 'bug'
+  - title: '📄 Documentation'
+    label: 'documentation'
+  - title: '🧰 Maintenance'
+    label: 'maintenance'
+change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
+template: dummy
+version-resolver:
+  major:
+    labels:
+      - 'MAJ'
+  minor:
+    labels:
+      - 'MIN'
+  patch:
+    labels:
+      - 'PAT'
+  default: minor
+exclude-labels:
+  - skip-changelog
\ No newline at end of file
diff --git a/test/fixtures/config/config-with-custom-version-resolver-patch.yml b/test/fixtures/config/config-with-custom-version-resolver-patch.yml
new file mode 100644
index 0000000..04aac55
--- /dev/null
+++ b/test/fixtures/config/config-with-custom-version-resolver-patch.yml
@@ -0,0 +1,28 @@
+name-template: 'v$RESOLVED_VERSION'
+tag-template: 'v$RESOLVED_VERSION'
+branches:
+  - master
+categories:
+  - title: '🚀 Features'
+    label: 'feature'
+  - title: '🐛 Bug fixes'
+    label: 'bug'
+  - title: '📄 Documentation'
+    label: 'documentation'
+  - title: '🧰 Maintenance'
+    label: 'maintenance'
+change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
+template: dummy
+version-resolver:
+  major:
+    labels:
+      - 'MAJ'
+  minor:
+    labels:
+      - 'MIN'
+  patch:
+    labels:
+      - 'patch'
+  default: minor
+exclude-labels:
+  - skip-changelog
\ No newline at end of file
diff --git a/test/index.test.js b/test/index.test.js
index 10913dd..da112eb 100644
--- a/test/index.test.js
+++ b/test/index.test.js
@@ -1897,5 +1897,168 @@ Previous tag: ''
         expect.assertions(1)
       })
     })
+
+    describe('with custom version resolver', () => {
+      it('uses correct default when no labels exist', async () => {
+        getConfigMock('config-with-custom-version-resolver-none.yml')
+
+        nock('https://api.github.com')
+          .get(
+            '/repos/toolmantim/release-drafter-test-project/releases?per_page=100'
+          )
+          .reply(200, [require('./fixtures/release')])
+
+        nock('https://api.github.com')
+          .post('/graphql', (body) =>
+            body.query.includes('query findCommitsWithAssociatedPullRequests')
+          )
+          .reply(
+            200,
+            require('./fixtures/__generated__/graphql-commits-forking.json')
+          )
+
+        nock('https://api.github.com')
+          .post(
+            '/repos/toolmantim/release-drafter-test-project/releases',
+            (body) => {
+              expect(body).toMatchObject({
+                body: `dummy`,
+                draft: true,
+                name: 'v2.1.0',
+                tag_name: 'v2.1.0',
+              })
+              return true
+            }
+          )
+          .reply(200, require('./fixtures/release'))
+
+        await probot.receive({
+          name: 'push',
+          payload: require('./fixtures/push'),
+        })
+
+        expect.assertions(1)
+      })
+      it('when only patch label exists, use patch', async () => {
+        getConfigMock('config-with-custom-version-resolver-patch.yml')
+
+        nock('https://api.github.com')
+          .get(
+            '/repos/toolmantim/release-drafter-test-project/releases?per_page=100'
+          )
+          .reply(200, [require('./fixtures/release')])
+
+        nock('https://api.github.com')
+          .post('/graphql', (body) =>
+            body.query.includes('query findCommitsWithAssociatedPullRequests')
+          )
+          .reply(
+            200,
+            require('./fixtures/__generated__/graphql-commits-forking.json')
+          )
+
+        nock('https://api.github.com')
+          .post(
+            '/repos/toolmantim/release-drafter-test-project/releases',
+            (body) => {
+              expect(body).toMatchObject({
+                body: `dummy`,
+                draft: true,
+                name: 'v2.0.1',
+                tag_name: 'v2.0.1',
+              })
+              return true
+            }
+          )
+          .reply(200, require('./fixtures/release'))
+
+        await probot.receive({
+          name: 'push',
+          payload: require('./fixtures/push'),
+        })
+
+        expect.assertions(1)
+      })
+      it('minor beats patch', async () => {
+        getConfigMock('config-with-custom-version-resolver-minor.yml')
+
+        nock('https://api.github.com')
+          .get(
+            '/repos/toolmantim/release-drafter-test-project/releases?per_page=100'
+          )
+          .reply(200, [require('./fixtures/release')])
+
+        nock('https://api.github.com')
+          .post('/graphql', (body) =>
+            body.query.includes('query findCommitsWithAssociatedPullRequests')
+          )
+          .reply(
+            200,
+            require('./fixtures/__generated__/graphql-commits-forking.json')
+          )
+
+        nock('https://api.github.com')
+          .post(
+            '/repos/toolmantim/release-drafter-test-project/releases',
+            (body) => {
+              expect(body).toMatchObject({
+                body: `dummy`,
+                draft: true,
+                name: 'v2.1.0',
+                tag_name: 'v2.1.0',
+              })
+              return true
+            }
+          )
+          .reply(200, require('./fixtures/release'))
+
+        await probot.receive({
+          name: 'push',
+          payload: require('./fixtures/push'),
+        })
+
+        expect.assertions(1)
+      })
+      it('major beats others', async () => {
+        getConfigMock('config-with-custom-version-resolver-major.yml')
+
+        nock('https://api.github.com')
+          .get(
+            '/repos/toolmantim/release-drafter-test-project/releases?per_page=100'
+          )
+          .reply(200, [require('./fixtures/release')])
+
+        nock('https://api.github.com')
+          .post('/graphql', (body) =>
+            body.query.includes('query findCommitsWithAssociatedPullRequests')
+          )
+          .reply(
+            200,
+            require('./fixtures/__generated__/graphql-commits-forking.json')
+          )
+
+        nock('https://api.github.com')
+          .post(
+            '/repos/toolmantim/release-drafter-test-project/releases',
+            (body) => {
+              expect(body).toMatchObject({
+                body: `dummy`,
+                draft: true,
+                name: 'v3.0.0',
+                tag_name: 'v3.0.0',
+              })
+              return true
+            }
+          )
+          .reply(200, require('./fixtures/release'))
+
+        await probot.receive({
+          name: 'push',
+          payload: require('./fixtures/push'),
+        })
+
+        expect.assertions(1)
+      })
+    })
   })
 })
diff --git a/test/versions.test.js b/test/versions.test.js
index 167c3f3..c7a18b2 100644
--- a/test/versions.test.js
+++ b/test/versions.test.js
@@ -1,4 +1,5 @@
 const { getVersionInfo } = require('../lib/versions')
+const each = require('jest-each').default
 
 describe('versions', () => {
   it('extracts a version-like string from the last tag', () => {
@@ -53,4 +54,24 @@ describe('versions', () => {
 
     expect(versionInfo).toEqual(undefined)
   })
+
+  each([
+    ['patch', '10.0.4'],
+    ['minor', '10.1.0'],
+    ['major', '11.0.0'],
+  ]).it(
+    "when the resolver versionKey increment is '%s'",
+    (versionKey, expected) => {
+      const versionInfo = getVersionInfo(
+        {
+          tag_name: 'v10.0.3',
+          name: 'Some release',
+        },
+        null,
+        null,
+        versionKey
+      )
+      expect(versionInfo.$RESOLVED_VERSION.version).toEqual(expected)
+    }
+  )
 })