Repository: semantic-release/gitlab (js)

Issue:
Reduce access_level requirements when using --dry-run
My team has a few projects where we require doing a `--dry-run` to obtain `nextRelease` information in an MR. Ideally we could use a token with reduced scope (say just `read_repository` and `read_api`). 

As a test this snippet in `verify.js` worked well enough to pass local testing.

```javascript
if(context.options.dryRun && ((projectAccess && projectAccess.access_level >= 10) || (groupAccess && groupAccess.access_level >= 10)))
{
  ...
}
else if(...existing check...)
```

Ultimately it would be great if #156 would get closed out by GitLab adding some functionality to adjust the `CI_JOB_TOKEN` scope. 

Pull request description:
feat(verify): Reduce access_level requirements when using --dry-run
Closes #449 

Summary

- Add check for `dryRun` in **verify** step
- Expand error codes to differentiate between repository "pull" and "push" permission errors.

Patch:
diff --git a/README.md b/README.md
index 44d9b47..78e012e 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,8 @@ The GitLab authentication configuration is **required** and can be set via
 
 Create a [personal access token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html) with the `api` scope and make it available in your CI environment via the `GL_TOKEN` environment variable. If you are using `GL_TOKEN` as the [remote Git repository authentication](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/ci-configuration.md#authentication) it must also have the `write_repository` scope.
 
+**Note**: When running with [`dryRun`](https://semantic-release.gitbook.io/semantic-release/usage/configuration#dryrun) only `read_repository` scope is required.
+
 ### Environment variables
 
 | Variable                       | Description                                               |
diff --git a/lib/definitions/errors.js b/lib/definitions/errors.js
index daa2a14..8d855a4 100644
--- a/lib/definitions/errors.js
+++ b/lib/definitions/errors.js
@@ -61,12 +61,20 @@ If you are using [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee)
       'README.md#options'
     )}).`,
   }),
-  EGLNOPERMISSION: ({repoId}) => ({
+  EGLNOPUSHPERMISSION: ({repoId}) => ({
     message: `The GitLab token doesn't allow to push on the repository ${repoId}.`,
     details: `The user associated with the [GitLab token](${linkify(
       'README.md#gitlab-authentication'
     )}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must allows to push to the repository ${repoId}.
 
+Please make sure the GitLab user associated with the token has the [permission to push](https://docs.gitlab.com/ee/user/permissions.html#project-members-permissions) to the repository ${repoId}.`,
+  }),
+  EGLNOPULLPERMISSION: ({repoId}) => ({
+    message: `The GitLab token doesn't allow to pull from the repository ${repoId}.`,
+    details: `The user associated with the [GitLab token](${linkify(
+      'README.md#gitlab-authentication'
+    )}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must allow pull from the repository ${repoId}.
+
 Please make sure the GitLab user associated with the token has the [permission to push](https://docs.gitlab.com/ee/user/permissions.html#project-members-permissions) to the repository ${repoId}.`,
   }),
   ENOGLTOKEN: ({repositoryUrl}) => ({
diff --git a/lib/verify.js b/lib/verify.js
index 18b2206..246f6f8 100644
--- a/lib/verify.js
+++ b/lib/verify.js
@@ -67,9 +67,15 @@ module.exports = async (pluginConfig, context) => {
           ...proxy,
         })
         .json());
-
-      if (!((projectAccess && projectAccess.access_level >= 30) || (groupAccess && groupAccess.access_level >= 30))) {
-        errors.push(getError('EGLNOPERMISSION', {repoId}));
+      if (
+        context.options.dryRun &&
+        !((projectAccess && projectAccess.access_level >= 10) || (groupAccess && groupAccess.access_level >= 10))
+      ) {
+        errors.push(getError('EGLNOPULLPERMISSION', {repoId}));
+      } else if (
+        !((projectAccess && projectAccess.access_level >= 30) || (groupAccess && groupAccess.access_level >= 30))
+      ) {
+        errors.push(getError('EGLNOPUSHPERMISSION', {repoId}));
       }
     } catch (error) {
       if (error.response && error.response.statusCode === 401) {


Test patch:
diff --git a/test/verify.test.js b/test/verify.test.js
index edff6cf..a42fe9c 100644
--- a/test/verify.test.js
+++ b/test/verify.test.js
@@ -479,7 +479,28 @@ test.serial("Throw SemanticReleaseError if token doesn't have the push permissio
 
   t.is(errors.length, 0);
   t.is(error.name, 'SemanticReleaseError');
-  t.is(error.code, 'EGLNOPERMISSION');
+  t.is(error.code, 'EGLNOPUSHPERMISSION');
+  t.true(gitlab.isDone());
+});
+
+test.serial("Throw SemanticReleaseError if token doesn't have the pull permission on the repository", async (t) => {
+  const owner = 'test_user';
+  const repo = 'test_repo';
+  const env = {GITLAB_TOKEN: 'gitlab_token'};
+  const gitlab = authenticate(env)
+    .get(`/projects/${owner}%2F${repo}`)
+    .reply(200, {permissions: {project_access: {access_level: 5}, group_access: {access_level: 5}}});
+
+  const [error, ...errors] = await t.throwsAsync(
+    verify(
+      {},
+      {env, options: {repositoryUrl: `https://gitlab.com:${owner}/${repo}.git`, dryRun: true}, logger: t.context.logger}
+    )
+  );
+
+  t.is(errors.length, 0);
+  t.is(error.name, 'SemanticReleaseError');
+  t.is(error.code, 'EGLNOPULLPERMISSION');
   t.true(gitlab.isDone());
 });