We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
bokehjs' version has duplicated dev suffix
```sh
$ jq '.version' bokehjs/package.json
"2.2.0dev4-dev.4"
```
Should be `2.2.0-dev.4` instead.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `release/config.py`
Content:
```
1 # -----------------------------------------------------------------------------
2 # Copyright (c) 2012 - 2020, Anaconda, Inc., and Bokeh Contributors.
3 # All rights reserved.
4 #
5 # The full license is in the file LICENSE.txt, distributed with this software.
6 # -----------------------------------------------------------------------------
7 """
8 
9 """
10 
11 # Standard library imports
12 import re
13 from typing import Dict, Optional, Tuple
14 
15 # Bokeh imports
16 from .enums import VersionType
17 from .logger import LOG, Scrubber
18 
19 __all__ = ("Config",)
20 
21 # This excludes "local" build versions, e.g. 0.12.4+19.gf85560a
22 ANY_VERSION = re.compile(r"^((\d+)\.(\d+)\.(\d+))((dev|rc)(\d+))?$")
23 
24 FULL_VERSION = re.compile(r"^(\d+\.\d+\.\d+)$")
25 
26 
27 class Config(object):
28     def __init__(self, version: str) -> None:
29         m = ANY_VERSION.match(version)
30         if not m:
31             raise ValueError(f"Invalid version for Bokeh build/release {version!r}")
32         groups = m.groups()
33 
34         self.version: str = version
35 
36         self.base_version: str = groups[0]
37         self.base_version_tuple: Tuple[str, ...] = tuple(groups[1:4])
38         self.ext: Optional[str] = groups[4]
39         self.ext_type: str = groups[5]
40         self.ext_number: str = groups[6]
41 
42         self._secrets: Dict[str, str] = {}
43 
44     def add_secret(self, name: str, secret: str) -> None:
45         """
46 
47         """
48         if name in self._secrets:
49             raise RuntimeError()
50         LOG.add_scrubber(Scrubber(secret, name=name))
51         self._secrets[name] = secret
52 
53     @property
54     def secrets(self) -> Dict[str, str]:
55         return self._secrets
56 
57     @property
58     def prerelease(self) -> bool:
59         return self.version_type != VersionType.FULL
60 
61     @property
62     def version_type(self) -> VersionType:
63         if "rc" in self.version:
64             return VersionType.RC
65         elif "dev" in self.version:
66             return VersionType.DEV
67         else:
68             return VersionType.FULL
69 
70     @property
71     def js_version(self) -> str:
72         if self.ext is None:
73             return self.version
74         return f"{self.version}-{self.ext_type}.{self.ext_number}"
75 
76     @property
77     def release_level(self) -> str:
78         major, minor = self.base_version_tuple[:2]
79         return f"{major}.{minor}"
80 
81     @property
82     def staging_branch(self) -> str:
83         return f"staging-{self.version}"
84 
85     @property
86     def base_branch(self) -> str:
87         return f"branch-{self.release_level}"
88
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/release/config.py b/release/config.py
--- a/release/config.py
+++ b/release/config.py
@@ -71,7 +71,7 @@
     def js_version(self) -> str:
         if self.ext is None:
             return self.version
-        return f"{self.version}-{self.ext_type}.{self.ext_number}"
+        return f"{self.base_version}-{self.ext_type}.{self.ext_number}"
 
     @property
     def release_level(self) -> str:

{"golden_diff": "diff --git a/release/config.py b/release/config.py\n--- a/release/config.py\n+++ b/release/config.py\n@@ -71,7 +71,7 @@\n     def js_version(self) -> str:\n         if self.ext is None:\n             return self.version\n-        return f\"{self.version}-{self.ext_type}.{self.ext_number}\"\n+        return f\"{self.base_version}-{self.ext_type}.{self.ext_number}\"\n \n     @property\n     def release_level(self) -> str:\n", "issue": "bokehjs' version has duplicated dev suffix\n```sh\r\n$ jq '.version' bokehjs/package.json\r\n\"2.2.0dev4-dev.4\"\r\n```\r\nShould be `2.2.0-dev.4` instead.\n", "before_files": [{"content": "# -----------------------------------------------------------------------------\n# Copyright (c) 2012 - 2020, Anaconda, Inc., and Bokeh Contributors.\n# All rights reserved.\n#\n# The full license is in the file LICENSE.txt, distributed with this software.\n# -----------------------------------------------------------------------------\n\"\"\"\n\n\"\"\"\n\n# Standard library imports\nimport re\nfrom typing import Dict, Optional, Tuple\n\n# Bokeh imports\nfrom .enums import VersionType\nfrom .logger import LOG, Scrubber\n\n__all__ = (\"Config\",)\n\n# This excludes \"local\" build versions, e.g. 0.12.4+19.gf85560a\nANY_VERSION = re.compile(r\"^((\\d+)\\.(\\d+)\\.(\\d+))((dev|rc)(\\d+))?$\")\n\nFULL_VERSION = re.compile(r\"^(\\d+\\.\\d+\\.\\d+)$\")\n\n\nclass Config(object):\n    def __init__(self, version: str) -> None:\n        m = ANY_VERSION.match(version)\n        if not m:\n            raise ValueError(f\"Invalid version for Bokeh build/release {version!r}\")\n        groups = m.groups()\n\n        self.version: str = version\n\n        self.base_version: str = groups[0]\n        self.base_version_tuple: Tuple[str, ...] = tuple(groups[1:4])\n        self.ext: Optional[str] = groups[4]\n        self.ext_type: str = groups[5]\n        self.ext_number: str = groups[6]\n\n        self._secrets: Dict[str, str] = {}\n\n    def add_secret(self, name: str, secret: str) -> None:\n        \"\"\"\n\n        \"\"\"\n        if name in self._secrets:\n            raise RuntimeError()\n        LOG.add_scrubber(Scrubber(secret, name=name))\n        self._secrets[name] = secret\n\n    @property\n    def secrets(self) -> Dict[str, str]:\n        return self._secrets\n\n    @property\n    def prerelease(self) -> bool:\n        return self.version_type != VersionType.FULL\n\n    @property\n    def version_type(self) -> VersionType:\n        if \"rc\" in self.version:\n            return VersionType.RC\n        elif \"dev\" in self.version:\n            return VersionType.DEV\n        else:\n            return VersionType.FULL\n\n    @property\n    def js_version(self) -> str:\n        if self.ext is None:\n            return self.version\n        return f\"{self.version}-{self.ext_type}.{self.ext_number}\"\n\n    @property\n    def release_level(self) -> str:\n        major, minor = self.base_version_tuple[:2]\n        return f\"{major}.{minor}\"\n\n    @property\n    def staging_branch(self) -> str:\n        return f\"staging-{self.version}\"\n\n    @property\n    def base_branch(self) -> str:\n        return f\"branch-{self.release_level}\"\n", "path": "release/config.py"}], "after_files": [{"content": "# -----------------------------------------------------------------------------\n# Copyright (c) 2012 - 2020, Anaconda, Inc., and Bokeh Contributors.\n# All rights reserved.\n#\n# The full license is in the file LICENSE.txt, distributed with this software.\n# -----------------------------------------------------------------------------\n\"\"\"\n\n\"\"\"\n\n# Standard library imports\nimport re\nfrom typing import Dict, Optional, Tuple\n\n# Bokeh imports\nfrom .enums import VersionType\nfrom .logger import LOG, Scrubber\n\n__all__ = (\"Config\",)\n\n# This excludes \"local\" build versions, e.g. 0.12.4+19.gf85560a\nANY_VERSION = re.compile(r\"^((\\d+)\\.(\\d+)\\.(\\d+))((dev|rc)(\\d+))?$\")\n\nFULL_VERSION = re.compile(r\"^(\\d+\\.\\d+\\.\\d+)$\")\n\n\nclass Config(object):\n    def __init__(self, version: str) -> None:\n        m = ANY_VERSION.match(version)\n        if not m:\n            raise ValueError(f\"Invalid version for Bokeh build/release {version!r}\")\n        groups = m.groups()\n\n        self.version: str = version\n\n        self.base_version: str = groups[0]\n        self.base_version_tuple: Tuple[str, ...] = tuple(groups[1:4])\n        self.ext: Optional[str] = groups[4]\n        self.ext_type: str = groups[5]\n        self.ext_number: str = groups[6]\n\n        self._secrets: Dict[str, str] = {}\n\n    def add_secret(self, name: str, secret: str) -> None:\n        \"\"\"\n\n        \"\"\"\n        if name in self._secrets:\n            raise RuntimeError()\n        LOG.add_scrubber(Scrubber(secret, name=name))\n        self._secrets[name] = secret\n\n    @property\n    def secrets(self) -> Dict[str, str]:\n        return self._secrets\n\n    @property\n    def prerelease(self) -> bool:\n        return self.version_type != VersionType.FULL\n\n    @property\n    def version_type(self) -> VersionType:\n        if \"rc\" in self.version:\n            return VersionType.RC\n        elif \"dev\" in self.version:\n            return VersionType.DEV\n        else:\n            return VersionType.FULL\n\n    @property\n    def js_version(self) -> str:\n        if self.ext is None:\n            return self.version\n        return f\"{self.base_version}-{self.ext_type}.{self.ext_number}\"\n\n    @property\n    def release_level(self) -> str:\n        major, minor = self.base_version_tuple[:2]\n        return f\"{major}.{minor}\"\n\n    @property\n    def staging_branch(self) -> str:\n        return f\"staging-{self.version}\"\n\n    @property\n    def base_branch(self) -> str:\n        return f\"branch-{self.release_level}\"\n", "path": "release/config.py"}]}