##// END OF EJS Templates
docs: updated documentation structure
marcink -
r3693:f470fd2e new-ui
parent child Browse files
Show More
@@ -0,0 +1,28 b''
1 .. _repo-admin-set:
2 .. _permissions-info-add-group-ref:
3
4 Repository Administration
5 =========================
6
7 Repository permissions in |RCE| can be managed in a number of different ways.
8 This overview should give you an insight into how you could adopt particular
9 settings for your needs:
10
11 * Global |repo| permissions: This allows you to set the default permissions
12 for each new |repo| created within |RCE|, see :ref:`repo-default-ref`. All
13 |repos| created will inherit these permissions unless explicitly configured.
14 * Individual |repo| permissions: To set individual |repo| permissions,
15 see :ref:`set-repo-perms`.
16 * Repository Group permissions: This allows you to define the permissions for
17 a group, and all |repos| created within that group will inherit the same
18 permissions.
19
20 .. toctree::
21
22 repo_admin/repo-perm-steps
23 repo_admin/repo-extra-fields
24 repo_admin/repo-hooks
25 repo_admin/repo-issue-tracker
26 repo_admin/repo-vcs
27 repo_admin/restore-deleted-repositories
28 repo_admin/repo-admin-tasks No newline at end of file
@@ -0,0 +1,24 b''
1 .. _repo-admin-tasks:
2
3 Common Admin Tasks for Repositories
4 -----------------------------------
5
6
7 Manually Force Delete Repository
8 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9
10 In case of attached forks or pull-requests repositories should be archived.
11 Here is how to force delete a repository and remove all dependent objects
12
13
14 .. code-block:: bash
15
16 # starts the ishell interactive prompt
17 $ rccontrol ishell enterprise-1
18
19 .. code-block:: python
20
21 In [4]: from rhodecode.model.repo import RepoModel
22 In [3]: repo = Repository.get_by_repo_name('test_repos/repo_with_prs')
23 In [5]: RepoModel().delete(repo, forks='detach', pull_requests='delete')
24 In [6]: Session().commit()
@@ -0,0 +1,35 b''
1 .. _search-methods-ref:
2
3 search methods
4 ==============
5
6 search
7 ------
8
9 .. py:function:: search(apiuser, search_query, search_type, page_limit=<Optional:10>, page=<Optional:1>, search_sort=<Optional:'newfirst'>, repo_name=<Optional:None>, repo_group_name=<Optional:None>)
10
11 Fetch Full Text Search results using API.
12
13 :param apiuser: This is filled automatically from the |authtoken|.
14 :type apiuser: AuthUser
15 :param search_query: Search query.
16 :type search_query: str
17 :param search_type: Search type. The following are valid options:
18 * commit
19 * content
20 * path
21 :type search_type: str
22 :param page_limit: Page item limit, from 1 to 500. Default 10 items.
23 :type page_limit: Optional(int)
24 :param page: Page number. Default first page.
25 :type page: Optional(int)
26 :param search_sort: Search sort order. Default newfirst. The following are valid options:
27 * newfirst
28 * oldfirst
29 :type search_sort: Optional(str)
30 :param repo_name: Filter by one repo. Default is all.
31 :type repo_name: Optional(str)
32 :param repo_group_name: Filter by one repo group. Default is all.
33 :type repo_group_name: Optional(str)
34
35
@@ -1,77 +1,77 b''
1 1 .. _repo-xtra:
2 2
3 3 Repository Extra Fields
4 4 =======================
5 5
6 6 Extra fields attached to a |repo| allow you to configure additional fields for
7 7 each repository. This allows storing custom data per-repository.
8 8
9 9 It can be used in :ref:`integrations-webhook` or in |RCX|.
10 10 To read more about |RCX|, see the :ref:`integrations-rcextensions` section.
11 11
12 12
13 13 Enabling Extra Fields
14 14 ---------------------
15 15
16 16 To enable extra fields on |repos|, use the following steps:
17 17
18 18 1. Go to the :menuselection:`Admin --> Settings --> Visual` page.
19 19 2. Check the :guilabel:`Use repository extra fields` box.
20 20 3. Save your changes.
21 21
22 22
23 23 Configuring Extra Fields
24 24 ------------------------
25 25
26 26 To configure extra fields per repository, use the following steps:
27 27
28 28 1. Go to :menuselection:`Admin --> Repositories` and select :guilabel:`Edit`
29 29 beside the |repo| to which you wish to add extra fields.
30 30 2. On the |repo| settings page, select the :guilabel:`Extra fields` tab.
31 31
32 .. image:: ../images/extra-repo-fields.png
32 .. image:: ../../images/extra-repo-fields.png
33 33
34 34 The most important is the `New field key` variable which under the value will
35 35 be stored. It needs to be unique for each repository. The label and description
36 36 will be generated in repository settings where users can actually save some
37 37 values inside generated extra fields.
38 38
39 39
40 40 Example Usage in extensions
41 41 ---------------------------
42 42
43 43 To use the extra fields in an extension, see the example below. For more
44 44 information and examples, see the :ref:`extensions-hooks-ref` section.
45 45
46 46 .. code-block:: python
47 47
48 48 call = load_extension('http_notify.py')
49 49 if call:
50 50 url = 'http://default.url' # <url for post data>
51 51
52 52 # possibly extract the URL from extra fields
53 53 call = load_extension('extra_fields.py')
54 54 if call:
55 55 repo_extra_fields = call(**kwargs)
56 56 # now update if we have extra fields, they have precedence
57 57 # this way users can store any configuration inside the database per
58 58 # repo
59 59 for key, data in repo_extra_fields.items():
60 60 kwargs[key] = data['field_value']
61 61
62 62 # an endpoint url data will be sent to, fetched from extra fields
63 63 # if exists, or fallback to default
64 64 kwargs['URL'] = kwargs.pop('webhook_url', None) or url
65 65
66 66 # fetch pushed commits, from commit_ids list
67 67 call = load_extension('extract_commits.py')
68 68 extracted_commits = {}
69 69 if call:
70 70 extracted_commits = call(**kwargs)
71 71 # store the commits for the next call chain
72 72 kwargs['COMMITS'] = extracted_commits
73 73
74 74 # set additional keys and values to be sent via POST to given URL
75 75 kwargs['caller_type'] = 'rhodecode'
76 76 kwargs['date'] = time.time() # import time before
77 77 call(**kwargs)
1 NO CONTENT: file renamed from docs/admin/repo-hooks.rst to docs/admin/repo_admin/repo-hooks.rst
1 NO CONTENT: file renamed from docs/admin/repo-issue-tracker.rst to docs/admin/repo_admin/repo-issue-tracker.rst
1 NO CONTENT: file renamed from docs/admin/repo-perm-steps.rst to docs/admin/repo_admin/repo-perm-steps.rst
1 NO CONTENT: file renamed from docs/admin/repo-vcs.rst to docs/admin/repo_admin/repo-vcs.rst
1 NO CONTENT: file renamed from docs/admin/restore-deleted-repositories.rst to docs/admin/repo_admin/restore-deleted-repositories.rst
@@ -1,34 +1,32 b''
1 1 .. _rhodecode-admin-ref:
2 2
3 3 System Administration
4 4 =====================
5 5
6 6 The following are the most common system administration tasks.
7 7
8 8 .. only:: latex
9 9
10 10 * :ref:`vcs-server`
11 11 * :ref:`apache-ws-ref`
12 12 * :ref:`nginx-ws-ref`
13 13 * :ref:`rhodecode-tuning-ref`
14 14 * :ref:`indexing-ref`
15 15 * :ref:`rhodecode-reset-ref`
16 16
17 17 .. toctree::
18 18
19 config-files-overview
20 vcs-server
21 svn-http
22 svn-path-permissions
23 gunicorn-ssl-support
24 apache-config
25 nginx-config
26 backup-restore
27 tuning-rhodecode
28 indexing
29 reset-information
30 enable-debug
31 admin-tricks
32 cleanup-cmds
33 restore-deleted-repositories
34
19 system_admin/config-files-overview
20 system_admin/vcs-server
21 system_admin/svn-http
22 system_admin/svn-path-permissions
23 system_admin/gunicorn-ssl-support
24 system_admin/apache-config
25 system_admin/nginx-config
26 system_admin/backup-restore
27 system_admin/tuning-rhodecode
28 system_admin/indexing
29 system_admin/reset-information
30 system_admin/enable-debug
31 system_admin/admin-tricks
32 system_admin/cleanup-cmds
@@ -1,264 +1,264 b''
1 1 .. _admin-tricks:
2 2
3 3 One-time Admin Tasks
4 4 --------------------
5 5
6 6 * :ref:`web-analytics`
7 7 * :ref:`admin-tricks-license`
8 8 * :ref:`announcements`
9 9 * :ref:`md-rst`
10 10 * :ref:`repo-stats`
11 11 * :ref:`server-side-merge`
12 12 * :ref:`remap-rescan`
13 13 * :ref:`custom-hooks`
14 14 * :ref:`clear-repo-cache`
15 15 * :ref:`set-repo-pub`
16 16 * :ref:`ping`
17 17
18 18 .. _web-analytics:
19 19
20 20 Adding Web Analytics
21 21 ^^^^^^^^^^^^^^^^^^^^
22 22
23 23 If you wish to add a Google Analytics, or any other kind of tracker to your
24 24 |RCE| instance you can add the necessary codes to the header or footer
25 25 section of each instance using the following steps:
26 26
27 27 1. From the |RCE| interface, select
28 28 :menuselection:`Admin --> Settings --> Global`
29 29 2. To add a tracking code to you instance, enter it in the header or footer
30 30 section and select **Save**
31 31
32 32 Use the example templates in the drop-down menu to set up your configuration.
33 33
34 34 .. _admin-tricks-license:
35 35
36 36 Licence Key Management
37 37 ^^^^^^^^^^^^^^^^^^^^^^
38 38
39 39 To manage your license key, go to
40 40 :menuselection:`Admin --> Settings --> License`.
41 41 On this page you can see the license key details. If you need a new license,
42 42 or have questions about your current one, contact support@rhodecode.com
43 43
44 44 .. _announcements:
45 45
46 46 Server-wide Announcements
47 47 ^^^^^^^^^^^^^^^^^^^^^^^^^
48 48
49 49 If you need to make a server-wide announcement to all users,
50 50 you can add a message to be displayed using the following steps:
51 51
52 52 1. From the |RCE| interface, select
53 53 :menuselection:`Admin --> Settings --> Global`
54 54 2. To add a message that will be displayed to all users,
55 55 select :guilabel:`Server Announcement` from the drop-down menu and
56 56 change the ``var message = "TYPE YOUR MESSAGE HERE";`` example line.
57 57 3. Select :guilabel:`Save`, and you will see the message once your page
58 58 refreshes.
59 59
60 .. image:: ../images/server-wide-announcement.png
60 .. image:: ../../images/server-wide-announcement.png
61 61 :alt: Server Wide Announcement
62 62
63 63 .. _md-rst:
64 64
65 65
66 66 Suppress license warnings or errors
67 67 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68 68
69 69 In case you're running on maximum allowed users, RhodeCode will display a
70 70 warning message on pages that you're close to the license limits.
71 71 It's often not desired to show that all the time. Here's how you can suppress
72 72 the license messages.
73 73
74 74 1. From the |RCE| interface, select
75 75 :menuselection:`Admin --> Settings --> Global`
76 76 2. Select :guilabel:`Flash message filtering` from the drop-down menu.
77 77 3. Select :guilabel:`Save`, and you will no longer see the license message
78 78 once your page refreshes.
79 79
80 80 .. _admin-tricks-suppress-license-messages:
81 81
82 82
83 83 Markdown or RST Rendering
84 84 ^^^^^^^^^^^^^^^^^^^^^^^^^
85 85
86 86 |RCE| can use `Markdown`_ or `reStructured Text`_ in commit message,
87 87 code review messages, and inline comments. To set the default to either,
88 88 select your preference from the drop-down menu on the
89 89 :menuselection:`Admin --> Settings --> Visual` page and select
90 90 :guilabel:`Save settings`.
91 91
92 92 .. _repo-stats:
93 93
94 94 Enabling Repository Statistics
95 95 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
96 96
97 97 To enable |repo| statistics, use the following steps:
98 98
99 99 1. From the |RCE| interface, open
100 100 :menuselection:`Admin --> Repositories` and select
101 101 :guilabel:`Edit` beside the |repo| for which you wish to enable statistics.
102 102 2. Check the :guilabel:`Enable statistics` box, and select :guilabel:`Save`
103 103
104 104 .. _server-side-merge:
105 105
106 106 Enabling Server-side Merging
107 107 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
108 108
109 109 To enable server-side merging, use the following steps:
110 110
111 111 1. From the |RCE| interface, open :menuselection:`Admin --> Settings --> VCS`
112 112 2. Check the :guilabel:`Server-side merge` box, and select
113 113 :guilabel:`Save Settings`
114 114
115 115 If you encounter slow performance with server-side merging enabled, check the
116 116 speed at which your server is performing actions. When server-side merging is
117 117 enabled, the following actions occurs on the server.
118 118
119 119 * A |pr| is created in the database.
120 120 * A shadow |repo| is created as a working environment for the |pr|.
121 121 * On display, |RCE| checks if the |pr| can be merged.
122 122
123 123 To check how fast the shadow |repo| creation is occurring on your server, use
124 124 the following steps:
125 125
126 126 1. Log into your server and create a directory in your |repos| folder.
127 127 2. Clone a |repo| that is showing slow performance and time the action.
128 128
129 129 .. code-block:: bash
130 130
131 131 # One option is to use the time command
132 132 $ time hg clone SOURCE_REPO TARGET
133 133
134 134 .. _remap-rescan:
135 135
136 136 Remap and Rescan Repositories
137 137 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
138 138
139 139 You may want to Remap and rescan the |repos| that |RCE| is managing to ensure
140 140 the system is always up-to-date. This is useful after importing, deleting,
141 141 or carrying out general cleaning up operations. To do this use the
142 142 following steps:
143 143
144 144 1. From the |RCE|, open
145 145 :menuselection:`Admin --> Settings --> Remap and rescan`
146 146 2. Click :guilabel:`Rescan Repositories`
147 147
148 148 Check the additional options if needed:
149 149
150 150 * :guilabel:`Destroy old data`: Useful for purging deleted repository
151 151 information from the database.
152 152 * :guilabel:`Invalidate cache for all repositories`: Use this to completely
153 153 remap all |repos|. Useful when importing or migrating |repos| to ensure all
154 154 new information is picked up.
155 155
156 156 .. _custom-hooks:
157 157
158 158 Adding Custom Hooks
159 159 ^^^^^^^^^^^^^^^^^^^
160 160
161 161 To add custom hooks to your instance, use the following steps:
162 162
163 163 1. Open :menuselection:`Admin --> Settings --> Hooks`
164 164 2. Add your custom hook details, you can use a file path to specify custom
165 165 hook scripts, for example:
166 166 ``pretxnchangegroup.example`` with value ``python:/path/to/custom_hook.py:my_func_name``
167 167 3. Select :guilabel:`Save`
168 168
169 169 Also, see the RhodeCode Extensions section of the :ref:`rc-tools` guide. RhodeCode
170 170 Extensions can be used to add additional hooks to your instance and comes
171 171 with a number of pre-built plugins if you chose to install them.
172 172
173 173 .. _clear-repo-cache:
174 174
175 175 Clearing |repo| cache
176 176 ^^^^^^^^^^^^^^^^^^^^^
177 177
178 178 If you need to clear the cache for a particular |repo|, use the following steps:
179 179
180 180 1. Open :menuselection:`Admin --> Repositories` and select :guilabel:`Edit`
181 181 beside the |repo| whose cache you wish to clear.
182 182 2. On the |repo| settings page, go to the :guilabel:`Caches` tab and select
183 183 :guilabel:`Invalidate repository cache`.
184 184
185 185 .. _set-lang:
186 186
187 187 Changing Default Language
188 188 ^^^^^^^^^^^^^^^^^^^^^^^^^
189 189
190 190 To change the default language of a |RCE| instance, change the language code
191 191 in the :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. To
192 192 do this, use the following steps.
193 193
194 194 1. Open the :file:`rhodecode.ini` file and set the required language code.
195 195
196 196 .. code-block:: ini
197 197
198 198 ## Optional Languages
199 199 ## en(default), de, fr, it, ja, pl, pt, ru, zh
200 200 lang = de
201 201
202 202 2. Restart the |RCE| instance and check that the language has been updated.
203 203
204 204 .. code-block:: bash
205 205
206 206 $ rccontrol restart enterprise-2
207 207 Instance "enterprise-2" successfully stopped.
208 208 Instance "enterprise-2" successfully started.
209 209
210 .. image:: ../images/language.png
210 .. image:: ../../images/language.png
211 211
212 212 .. _set-repo-pub:
213 213
214 214 Setting Repositories to Publish
215 215 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
216 216
217 217 To automatically promote your local |repos| to public after pushing to |RCE|,
218 218 enable the :guilabel:`Set repositories as publishing` option on the
219 219 :menuselection:`Admin --> Settings --> VCS` page.
220 220
221 221 .. note::
222 222
223 223 This option is enabled by default on most |RCE| versions, but if upgrading
224 224 from a 1.7.x version it could be disabled on upgrade due to inheriting
225 225 older default settings.
226 226
227 227 .. _ping:
228 228
229 229 Pinging the |RCE| Server
230 230 ^^^^^^^^^^^^^^^^^^^^^^^^
231 231
232 232 You can check the IP Address of your |RCE| instance using the
233 233 following URL: ``{instance-URL}/_admin/ping``.
234 234
235 235 .. code-block:: bash
236 236
237 237 $ curl https://your.rhodecode.url/_admin/ping
238 238 pong[rce-7880] => 203.0.113.23
239 239
240 240 .. _Markdown: http://daringfireball.net/projects/markdown/
241 241 .. _reStructured Text: http://docutils.sourceforge.net/docs/index.html
242 242
243 243
244 244 Unarchiving a repository
245 245 ^^^^^^^^^^^^^^^^^^^^^^^^^
246 246
247 247 Archive operation for the repository is similar as delete. Archive keeps the data for future references
248 248 but makes the repository read-only. After archiving the repository it shouldn't be modified in any way.
249 249 This is why repository settings are disabled for an archived repository.
250 250
251 251 If there's a need for unarchiving a repository for some reasons, the interactive
252 252 ishell interface should be used.
253 253
254 254 .. code-block:: bash
255 255
256 256 # Open iShell from the terminal
257 257 $ rccontrol ishell enterprise-1/community-1
258 258
259 259 .. code-block:: python
260 260
261 261 # Set repository as un-archived
262 262 In [1]: repo = Repository.get_by_repo_name('SOME_REPO_NAME')
263 263 In [2]: repo.archived = False
264 264 In [3]: Session().add(repo);Session().commit()
@@ -1,14 +1,14 b''
1 1 .. _apache-ws-ref:
2 2
3 3 Apache HTTP Server Configuration
4 4 --------------------------------
5 5
6 6 To set up your Apache Web Server for optimal performance and security, use
7 7 the information in the following sections.
8 8
9 9 .. toctree::
10 10
11 apache-conf-example
12 apache-diffie-hellman
13 apache-subdirectory
14 apache-wsgi-coding
11 apache/apache-conf-example
12 apache/apache-diffie-hellman
13 apache/apache-subdirectory
14 apache/apache-wsgi-coding
1 NO CONTENT: file renamed from docs/admin/apache-conf-example.rst to docs/admin/system_admin/apache/apache-conf-example.rst
1 NO CONTENT: file renamed from docs/admin/apache-diffie-hellman.rst to docs/admin/system_admin/apache/apache-diffie-hellman.rst
1 NO CONTENT: file renamed from docs/admin/apache-subdirectory.rst to docs/admin/system_admin/apache/apache-subdirectory.rst
1 NO CONTENT: file renamed from docs/admin/apache-wsgi-coding.rst to docs/admin/system_admin/apache/apache-wsgi-coding.rst
1 NO CONTENT: file renamed from docs/admin/backup-restore.rst to docs/admin/system_admin/backup-restore.rst
1 NO CONTENT: file renamed from docs/admin/cleanup-cmds.rst to docs/admin/system_admin/cleanup-cmds.rst
1 NO CONTENT: file renamed from docs/admin/config-files-overview.rst to docs/admin/system_admin/config-files-overview.rst
1 NO CONTENT: file renamed from docs/admin/enable-debug.rst to docs/admin/system_admin/enable-debug.rst
1 NO CONTENT: file renamed from docs/admin/gunicorn-ssl-support.rst to docs/admin/system_admin/gunicorn-ssl-support.rst
1 NO CONTENT: file renamed from docs/admin/indexing.rst to docs/admin/system_admin/indexing.rst
@@ -1,14 +1,14 b''
1 1 .. _nginx-ws-ref:
2 2
3 3 Nginx HTTP Server Configuration
4 4 -------------------------------
5 5
6 6 To set up your Nginx Web Server for optimal performance and security, use
7 7 the information in the following sections.
8 8
9 9 .. toctree::
10 10
11 nginx-config-example
12 nginx-diffie-hellman
13 nginx-proxy-conf
14 nginx-url-prefix
11 nginx/nginx-config-example
12 nginx/nginx-diffie-hellman
13 nginx/nginx-proxy-conf
14 nginx/nginx-url-prefix
1 NO CONTENT: file renamed from docs/admin/nginx-config-example.rst to docs/admin/system_admin/nginx/nginx-config-example.rst
1 NO CONTENT: file renamed from docs/admin/nginx-diffie-hellman.rst to docs/admin/system_admin/nginx/nginx-diffie-hellman.rst
1 NO CONTENT: file renamed from docs/admin/nginx-proxy-conf.rst to docs/admin/system_admin/nginx/nginx-proxy-conf.rst
1 NO CONTENT: file renamed from docs/admin/nginx-url-prefix.rst to docs/admin/system_admin/nginx/nginx-url-prefix.rst
1 NO CONTENT: file renamed from docs/admin/reset-information.rst to docs/admin/system_admin/reset-information.rst
1 NO CONTENT: file renamed from docs/admin/svn-http.rst to docs/admin/system_admin/svn-http.rst
1 NO CONTENT: file renamed from docs/admin/svn-path-permissions.rst to docs/admin/system_admin/svn-path-permissions.rst
@@ -1,21 +1,21 b''
1 1 .. _rhodecode-tuning-ref:
2 2
3 3 Tuning |RCE|
4 4 ============
5 5
6 6 To customize your |RCE| |version| installation for maximum performance you
7 7 may find some of the following methods useful.
8 8
9 9 .. toctree::
10 10
11 tuning-gunicorn
12 tuning-vcs-memory-cache
13 tuning-user-sessions-performance
14 tuning-increase-db-performance
15 tuning-scale-horizontally-cluster
16 tuning-mount-cache-memory
17 tuning-change-encoding
18 tuning-change-large-file-dir
19 tuning-change-lfs-dir
20 tuning-hg-auth-loop
11 tuning/tuning-gunicorn
12 tuning/tuning-vcs-memory-cache
13 tuning/tuning-user-sessions-performance
14 tuning/tuning-increase-db-performance
15 tuning/tuning-scale-horizontally-cluster
16 tuning/tuning-mount-cache-memory
17 tuning/tuning-change-encoding
18 tuning/tuning-change-large-file-dir
19 tuning/tuning-change-lfs-dir
20 tuning/tuning-hg-auth-loop
21 21
1 NO CONTENT: file renamed from docs/admin/tuning-change-encoding.rst to docs/admin/system_admin/tuning/tuning-change-encoding.rst
1 NO CONTENT: file renamed from docs/admin/tuning-change-large-file-dir.rst to docs/admin/system_admin/tuning/tuning-change-large-file-dir.rst
1 NO CONTENT: file renamed from docs/admin/tuning-change-lfs-dir.rst to docs/admin/system_admin/tuning/tuning-change-lfs-dir.rst
@@ -1,126 +1,126 b''
1 1 .. _increase-gunicorn:
2 2
3 3 Configure Gunicorn Workers
4 4 --------------------------
5 5
6 6
7 7 |RCE| comes with `Gunicorn`_ which is a Python WSGI HTTP Server for UNIX.
8 8
9 9 To improve |RCE| performance you can increase the number of `Gunicorn`_ workers.
10 10 This allows to handle more connections concurrently, and provide better
11 11 responsiveness and performance.
12 12
13 13 By default during installation |RCC| tries to detect how many CPUs are
14 14 available in the system, and set the number workers based on that information.
15 15 However sometimes it's better to manually set the number of workers.
16 16
17 17 To do this, use the following steps:
18 18
19 19 1. Open the :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file.
20 20 2. In the ``[server:main]`` section, change the number of Gunicorn
21 21 ``workers`` using the following default formula :math:`(2 * Cores) + 1`.
22 22 We however not recommend using more than 8-12 workers per server. It's better
23 23 to start using the :ref:`scale-horizontal-cluster` in case that performance
24 24 with 8-12 workers is not enough.
25 25
26 26 .. code-block:: ini
27 27
28 28 use = egg:gunicorn#main
29 29 ## Sets the number of process workers. You must set `instance_id = *`
30 30 ## when this option is set to more than one worker, recommended
31 31 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
32 32 ## The `instance_id = *` must be set in the [app:main] section below
33 33 workers = 4
34 34 ## process name
35 35 proc_name = rhodecode
36 36 ## type of worker class, one of sync, gevent
37 37 ## recommended for bigger setup is using of of other than sync one
38 38 worker_class = sync
39 39 ## The maximum number of simultaneous clients. Valid only for Gevent
40 40 #worker_connections = 10
41 41 ## max number of requests that worker will handle before being gracefully
42 42 ## restarted, could prevent memory leaks
43 43 max_requests = 1000
44 44 max_requests_jitter = 30
45 ## amount of time a worker can spend with handling a request before it
45 ## amount of time a worker can spend with handling a request tuning-change-lfs-dir.before it
46 46 ## gets killed and restarted. Set to 6hrs
47 47 timeout = 21600
48 48
49 49 3. In the ``[app:main]`` section, set the ``instance_id`` property to ``*``.
50 50
51 51 .. code-block:: ini
52 52
53 53 # In the [app:main] section
54 54 [app:main]
55 55 # You must set `instance_id = *`
56 56 instance_id = *
57 57
58 58 4. Change the VCSServer workers too. Open the
59 59 :file:`home/{user}/.rccontrol/{instance-id}/vcsserver.ini` file.
60 60
61 61 5. In the ``[server:main]`` section, increase the number of Gunicorn
62 62 ``workers`` using the following formula :math:`(2 * Cores) + 1`.
63 63
64 64 .. code-block:: ini
65 65
66 66 ## run with gunicorn --log-config vcsserver.ini --paste vcsserver.ini
67 67 use = egg:gunicorn#main
68 68 ## Sets the number of process workers. Recommended
69 69 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
70 70 workers = 4
71 71 ## process name
72 72 proc_name = rhodecode_vcsserver
73 73 ## type of worker class, currently `sync` is the only option allowed.
74 74 worker_class = sync
75 75 ## The maximum number of simultaneous clients. Valid only for Gevent
76 76 #worker_connections = 10
77 77 ## max number of requests that worker will handle before being gracefully
78 78 ## restarted, could prevent memory leaks
79 79 max_requests = 1000
80 80 max_requests_jitter = 30
81 81 ## amount of time a worker can spend with handling a request before it
82 82 ## gets killed and restarted. Set to 6hrs
83 83 timeout = 21600
84 84
85 85 6. Save your changes.
86 86 7. Restart your |RCE| instances, using the following command:
87 87
88 88 .. code-block:: bash
89 89
90 90 $ rccontrol restart '*'
91 91
92 92
93 93 Gunicorn Gevent Backend
94 94 -----------------------
95 95
96 96 Gevent is an asynchronous worker type for Gunicorn. It allows accepting multiple
97 97 connections on a single `Gunicorn`_ worker. This means you can handle 100s
98 98 of concurrent clones, or API calls using just few workers. A setting called
99 99 `worker_connections` defines on how many connections each worker can
100 100 handle using `Gevent`.
101 101
102 102
103 103 To enable `Gevent` on |RCE| do the following:
104 104
105 105
106 106 1. Open the :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file.
107 107 2. In the ``[server:main]`` section, change `worker_class` for Gunicorn.
108 108
109 109
110 110 .. code-block:: ini
111 111
112 112 ## type of worker class, one of sync, gevent
113 113 ## recommended for bigger setup is using of of other than sync one
114 114 worker_class = gevent
115 115 ## The maximum number of simultaneous clients. Valid only for Gevent
116 116 worker_connections = 30
117 117
118 118
119 119 .. note::
120 120
121 121 `Gevent` is currently only supported for Enterprise/Community instances.
122 122 VCSServer doesn't yet support gevent.
123 123
124 124
125 125
126 126 .. _Gunicorn: http://gunicorn.org/
1 NO CONTENT: file renamed from docs/admin/tuning-hg-auth-loop.rst to docs/admin/system_admin/tuning/tuning-hg-auth-loop.rst
1 NO CONTENT: file renamed from docs/admin/tuning-increase-db-performance.rst to docs/admin/system_admin/tuning/tuning-increase-db-performance.rst
1 NO CONTENT: file renamed from docs/admin/tuning-mount-cache-memory.rst to docs/admin/system_admin/tuning/tuning-mount-cache-memory.rst
1 NO CONTENT: file renamed from docs/admin/tuning-scale-horizontally-cluster.rst to docs/admin/system_admin/tuning/tuning-scale-horizontally-cluster.rst
1 NO CONTENT: file renamed from docs/admin/tuning-user-sessions-performance.rst to docs/admin/system_admin/tuning/tuning-user-sessions-performance.rst
1 NO CONTENT: file renamed from docs/admin/tuning-vcs-memory-cache.rst to docs/admin/system_admin/tuning/tuning-vcs-memory-cache.rst
1 NO CONTENT: file renamed from docs/admin/vcs-server.rst to docs/admin/system_admin/vcs-server.rst
@@ -1,209 +1,210 b''
1 1 .. _api:
2 2
3 3 API Documentation
4 4 =================
5 5
6 6 The |RCE| API uses a single scheme for calling all API methods. The API is
7 7 implemented with JSON protocol in both directions. To send API requests to
8 8 your instance of |RCE|, use the following URL format
9 9 ``<your_server>/_admin``
10 10
11 11 .. note::
12 12
13 13 To use the API, you should configure the :file:`~/.rhoderc` file with
14 14 access details per instance. For more information, see
15 15 :ref:`config-rhoderc`.
16 16
17 17
18 18 API ACCESS FOR WEB VIEWS
19 19 ------------------------
20 20
21 21 API access can also be turned on for each web view in |RCE| that is
22 22 decorated with a `@LoginRequired` decorator. To enable API access, change
23 23 the standard login decorator to `@LoginRequired(api_access=True)`.
24 24
25 25 From |RCE| version 1.7.0 you can configure a white list
26 26 of views that have API access enabled by default. To enable these,
27 27 edit the |RCE| configuration ``.ini`` file. The default location is:
28 28
29 29 * |RCE| Pre-2.2.7 :file:`root/rhodecode/data/production.ini`
30 30 * |RCE| 3.0 :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini`
31 31
32 32 To configure the white list, edit this section of the file. In this
33 33 configuration example, API access is granted to the patch/diff raw file and
34 34 archive.
35 35
36 36 .. code-block:: ini
37 37
38 38 ## List of controllers (using glob syntax) that AUTH TOKENS could be used for access.
39 39 ## Adding ?auth_token = <token> to the url authenticates this request as if it
40 40 ## came from the the logged in user who own this authentication token.
41 41 ##
42 42 ## Syntax is <ControllerClass>:<function_pattern>.
43 43 ## The list should be "," separated and on a single line.
44 44 ##
45 45 api_access_controllers_whitelist = RepoCommitsView:repo_commit_raw,RepoCommitsView:repo_commit_patch,RepoCommitsView:repo_commit_download
46 46
47 47 After this change, a |RCE| view can be accessed without login by adding a
48 48 GET parameter ``?auth_token=<auth_token>`` to a url. For example to
49 49 access the raw diff.
50 50
51 51 .. code-block:: html
52 52
53 53 http://<server>/<repo>/changeset-diff/<sha>?auth_token=<auth_token>
54 54
55 55 By default this is only enabled on RSS/ATOM feed views. Exposing raw diffs is a
56 56 good way to integrate with 3rd party services like code review, or build farms
57 57 that could download archives.
58 58
59 59 API ACCESS
60 60 ----------
61 61
62 62 All clients are required to send JSON-RPC spec JSON data.
63 63
64 64 .. code-block:: bash
65 65
66 66 {
67 67 "id:"<id>",
68 68 "auth_token":"<auth_token>",
69 69 "method":"<method_name>",
70 70 "args":{"<arg_key>":"<arg_val>"}
71 71 }
72 72
73 73 Example call for auto pulling from remote repositories using curl:
74 74
75 75 .. code-block:: bash
76 76
77 77 curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"id":1,
78 78 "auth_token":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull", "args":{"repoid":"CPython"}}'
79 79
80 80 Provide those parameters:
81 81 - **id** A value of any type, which is used to match the response with the
82 82 request that it is replying to.
83 83 - **auth_token** for access and permission validation.
84 84 - **method** is name of method to call
85 85 - **args** is an ``key:value`` list of arguments to pass to method
86 86
87 87 .. note::
88 88
89 89 To get your |authtoken|, from the |RCE| interface,
90 90 go to:
91 91 :menuselection:`username --> My account --> Auth tokens`
92 92
93 93 For security reasons you should always create a dedicated |authtoken| for
94 94 API use only.
95 95
96 96
97 97 The |RCE| API will always return a JSON-RPC response:
98 98
99 99 .. code-block:: bash
100 100
101 101 {
102 102 "id": <id>, # matching id sent by request
103 103 "result": "<result>"|null, # JSON formatted result, null if any errors
104 104 "error": "null"|<error_message> # JSON formatted error (if any)
105 105 }
106 106
107 107 All responses from API will be with `HTTP/1.0 200 OK` status code.
108 108 If there is an error when calling the API, the *error* key will contain a
109 109 failure description and the *result* will be `null`.
110 110
111 111 API CLIENT
112 112 ----------
113 113
114 114 To install the |RCE| API, see :ref:`install-tools`. To configure the API per
115 115 instance, see the :ref:`rc-tools` section as you need to configure a
116 116 :file:`~/.rhoderc` file with your |authtokens|.
117 117
118 118 Once you have set up your instance API access, use the following examples to
119 119 get started.
120 120
121 121 .. code-block:: bash
122 122
123 123 # Getting the 'rhodecode' repository
124 124 # from a RhodeCode Enterprise instance
125 125 rhodecode-api --instance-name=enterprise-1 get_repo repoid:rhodecode
126 126
127 127 Calling method get_repo => http://127.0.0.1:5000
128 128 Server response
129 129 {
130 130 <json data>
131 131 }
132 132
133 133 # Creating a new mercurial repository called 'brand-new'
134 134 # with a description 'Repo-description'
135 135 rhodecode-api --instance-name=enterprise-1 create_repo repo_name:brand-new repo_type:hg description:Repo-description
136 136 {
137 137 "error": null,
138 138 "id": 1110,
139 139 "result": {
140 140 "msg": "Created new repository `brand-new`",
141 141 "success": true,
142 142 "task": null
143 143 }
144 144 }
145 145
146 146 A broken example, what not to do.
147 147
148 148 .. code-block:: bash
149 149
150 150 # A call missing the required arguments
151 151 # and not specifying the instance
152 152 rhodecode-api get_repo
153 153
154 154 Calling method get_repo => http://127.0.0.1:5000
155 155 Server response
156 156 "Missing non optional `repoid` arg in JSON DATA"
157 157
158 158 You can specify pure JSON using the ``--format`` parameter.
159 159
160 160 .. code-block:: bash
161 161
162 162 rhodecode-api --format=json get_repo repoid:rhodecode
163 163
164 164 In such case only output that this function shows is pure JSON, we can use that
165 165 and pipe output to some json formatter.
166 166
167 167 If output is in pure JSON format, you can pipe output to a JSON formatter.
168 168
169 169 .. code-block:: bash
170 170
171 171 rhodecode-api --instance-name=enterprise-1 --format=json get_repo repoid:rhodecode | python -m json.tool
172 172
173 173 API METHODS
174 174 -----------
175 175
176 176 Each method by default required following arguments.
177 177
178 178 .. code-block:: bash
179 179
180 180 id : "<id_for_response>"
181 181 auth_token : "<auth_token>"
182 182 method : "<method name>"
183 183 args : {}
184 184
185 185 Use each **param** from docs and put it in args, Optional parameters
186 186 are not required in args.
187 187
188 188 .. code-block:: bash
189 189
190 190 args: {"repoid": "rhodecode"}
191 191
192 192 .. Note: From this point on things are generated by the script in
193 193 `scripts/fabfile.py`. To change things below, update the docstrings in the
194 194 ApiController.
195 195
196 196 .. --- API DEFS MARKER ---
197 197 .. toctree::
198 198
199 199 methods/repo-methods
200 200 methods/store-methods
201 201 methods/license-methods
202 202 methods/deprecated-methods
203 203 methods/gist-methods
204 204 methods/pull-request-methods
205 205 methods/repo-methods
206 206 methods/repo-group-methods
207 methods/search-methods
207 208 methods/server-methods
208 209 methods/user-methods
209 210 methods/user-group-methods
@@ -1,1134 +1,1133 b''
1 1 .. _repo-methods-ref:
2 2
3 3 repo methods
4 4 ============
5 5
6 6 add_field_to_repo
7 7 -----------------
8 8
9 9 .. py:function:: add_field_to_repo(apiuser, repoid, key, label=<Optional:''>, description=<Optional:''>)
10 10
11 11 Adds an extra field to a repository.
12 12
13 13 This command can only be run using an |authtoken| with at least
14 14 write permissions to the |repo|.
15 15
16 16 :param apiuser: This is filled automatically from the |authtoken|.
17 17 :type apiuser: AuthUser
18 18 :param repoid: Set the repository name or repository id.
19 19 :type repoid: str or int
20 20 :param key: Create a unique field key for this repository.
21 21 :type key: str
22 22 :param label:
23 23 :type label: Optional(str)
24 24 :param description:
25 25 :type description: Optional(str)
26 26
27 27
28 28 comment_commit
29 29 --------------
30 30
31 31 .. py:function:: comment_commit(apiuser, repoid, commit_id, message, status=<Optional:None>, comment_type=<Optional:u'note'>, resolves_comment_id=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
32 32
33 33 Set a commit comment, and optionally change the status of the commit.
34 34
35 35 :param apiuser: This is filled automatically from the |authtoken|.
36 36 :type apiuser: AuthUser
37 37 :param repoid: Set the repository name or repository ID.
38 38 :type repoid: str or int
39 39 :param commit_id: Specify the commit_id for which to set a comment.
40 40 :type commit_id: str
41 41 :param message: The comment text.
42 42 :type message: str
43 43 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
44 44 'approved', 'rejected', 'under_review'
45 45 :type status: str
46 46 :param comment_type: Comment type, one of: 'note', 'todo'
47 47 :type comment_type: Optional(str), default: 'note'
48 48 :param userid: Set the user name of the comment creator.
49 49 :type userid: Optional(str or int)
50 50
51 51 Example error output:
52 52
53 53 .. code-block:: bash
54 54
55 55 {
56 56 "id" : <id_given_in_input>,
57 57 "result" : {
58 58 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
59 59 "status_change": null or <status>,
60 60 "success": true
61 61 },
62 62 "error" : null
63 63 }
64 64
65 65
66 66 create_repo
67 67 -----------
68 68
69 69 .. py:function:: create_repo(apiuser, repo_name, repo_type, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, push_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, enable_statistics=<Optional:False>, enable_locking=<Optional:False>, enable_downloads=<Optional:False>, copy_permissions=<Optional:False>)
70 70
71 71 Creates a repository.
72 72
73 73 * If the repository name contains "/", repository will be created inside
74 74 a repository group or nested repository groups
75 75
76 76 For example "foo/bar/repo1" will create |repo| called "repo1" inside
77 77 group "foo/bar". You have to have permissions to access and write to
78 78 the last repository group ("bar" in this example)
79 79
80 80 This command can only be run using an |authtoken| with at least
81 81 permissions to create repositories, or write permissions to
82 82 parent repository groups.
83 83
84 84 :param apiuser: This is filled automatically from the |authtoken|.
85 85 :type apiuser: AuthUser
86 86 :param repo_name: Set the repository name.
87 87 :type repo_name: str
88 88 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
89 89 :type repo_type: str
90 90 :param owner: user_id or username
91 91 :type owner: Optional(str)
92 92 :param description: Set the repository description.
93 93 :type description: Optional(str)
94 94 :param private: set repository as private
95 95 :type private: bool
96 96 :param clone_uri: set clone_uri
97 97 :type clone_uri: str
98 98 :param push_uri: set push_uri
99 99 :type push_uri: str
100 100 :param landing_rev: <rev_type>:<rev>
101 101 :type landing_rev: str
102 102 :param enable_locking:
103 103 :type enable_locking: bool
104 104 :param enable_downloads:
105 105 :type enable_downloads: bool
106 106 :param enable_statistics:
107 107 :type enable_statistics: bool
108 108 :param copy_permissions: Copy permission from group in which the
109 109 repository is being created.
110 110 :type copy_permissions: bool
111 111
112 112
113 113 Example output:
114 114
115 115 .. code-block:: bash
116 116
117 117 id : <id_given_in_input>
118 118 result: {
119 119 "msg": "Created new repository `<reponame>`",
120 120 "success": true,
121 121 "task": "<celery task id or None if done sync>"
122 122 }
123 123 error: null
124 124
125 125
126 126 Example error output:
127 127
128 128 .. code-block:: bash
129 129
130 130 id : <id_given_in_input>
131 131 result : null
132 132 error : {
133 133 'failed to create repository `<repo_name>`'
134 134 }
135 135
136 136
137 137 delete_repo
138 138 -----------
139 139
140 140 .. py:function:: delete_repo(apiuser, repoid, forks=<Optional:''>)
141 141
142 142 Deletes a repository.
143 143
144 144 * When the `forks` parameter is set it's possible to detach or delete
145 145 forks of deleted repository.
146 146
147 147 This command can only be run using an |authtoken| with admin
148 148 permissions on the |repo|.
149 149
150 150 :param apiuser: This is filled automatically from the |authtoken|.
151 151 :type apiuser: AuthUser
152 152 :param repoid: Set the repository name or repository ID.
153 153 :type repoid: str or int
154 154 :param forks: Set to `detach` or `delete` forks from the |repo|.
155 155 :type forks: Optional(str)
156 156
157 157 Example error output:
158 158
159 159 .. code-block:: bash
160 160
161 161 id : <id_given_in_input>
162 162 result: {
163 163 "msg": "Deleted repository `<reponame>`",
164 164 "success": true
165 165 }
166 166 error: null
167 167
168 168
169 169 fork_repo
170 170 ---------
171 171
172 172 .. py:function:: fork_repo(apiuser, repoid, fork_name, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, copy_permissions=<Optional:False>)
173 173
174 174 Creates a fork of the specified |repo|.
175 175
176 176 * If the fork_name contains "/", fork will be created inside
177 177 a repository group or nested repository groups
178 178
179 179 For example "foo/bar/fork-repo" will create fork called "fork-repo"
180 180 inside group "foo/bar". You have to have permissions to access and
181 181 write to the last repository group ("bar" in this example)
182 182
183 183 This command can only be run using an |authtoken| with minimum
184 184 read permissions of the forked repo, create fork permissions for an user.
185 185
186 186 :param apiuser: This is filled automatically from the |authtoken|.
187 187 :type apiuser: AuthUser
188 188 :param repoid: Set repository name or repository ID.
189 189 :type repoid: str or int
190 190 :param fork_name: Set the fork name, including it's repository group membership.
191 191 :type fork_name: str
192 192 :param owner: Set the fork owner.
193 193 :type owner: str
194 194 :param description: Set the fork description.
195 195 :type description: str
196 196 :param copy_permissions: Copy permissions from parent |repo|. The
197 197 default is False.
198 198 :type copy_permissions: bool
199 199 :param private: Make the fork private. The default is False.
200 200 :type private: bool
201 201 :param landing_rev: Set the landing revision. The default is tip.
202 202
203 203 Example output:
204 204
205 205 .. code-block:: bash
206 206
207 207 id : <id_for_response>
208 208 api_key : "<api_key>"
209 209 args: {
210 210 "repoid" : "<reponame or repo_id>",
211 211 "fork_name": "<forkname>",
212 212 "owner": "<username or user_id = Optional(=apiuser)>",
213 213 "description": "<description>",
214 214 "copy_permissions": "<bool>",
215 215 "private": "<bool>",
216 216 "landing_rev": "<landing_rev>"
217 217 }
218 218
219 219 Example error output:
220 220
221 221 .. code-block:: bash
222 222
223 223 id : <id_given_in_input>
224 224 result: {
225 225 "msg": "Created fork of `<reponame>` as `<forkname>`",
226 226 "success": true,
227 227 "task": "<celery task id or None if done sync>"
228 228 }
229 229 error: null
230 230
231 231
232 232 get_repo
233 233 --------
234 234
235 235 .. py:function:: get_repo(apiuser, repoid, cache=<Optional:True>)
236 236
237 237 Gets an existing repository by its name or repository_id.
238 238
239 239 The members section so the output returns users groups or users
240 240 associated with that repository.
241 241
242 242 This command can only be run using an |authtoken| with admin rights,
243 243 or users with at least read rights to the |repo|.
244 244
245 245 :param apiuser: This is filled automatically from the |authtoken|.
246 246 :type apiuser: AuthUser
247 247 :param repoid: The repository name or repository id.
248 248 :type repoid: str or int
249 249 :param cache: use the cached value for last changeset
250 250 :type: cache: Optional(bool)
251 251
252 252 Example output:
253 253
254 254 .. code-block:: bash
255 255
256 256 {
257 257 "error": null,
258 258 "id": <repo_id>,
259 259 "result": {
260 260 "clone_uri": null,
261 261 "created_on": "timestamp",
262 262 "description": "repo description",
263 263 "enable_downloads": false,
264 264 "enable_locking": false,
265 265 "enable_statistics": false,
266 266 "followers": [
267 267 {
268 268 "active": true,
269 269 "admin": false,
270 270 "api_key": "****************************************",
271 271 "api_keys": [
272 272 "****************************************"
273 273 ],
274 274 "email": "user@example.com",
275 275 "emails": [
276 276 "user@example.com"
277 277 ],
278 278 "extern_name": "rhodecode",
279 279 "extern_type": "rhodecode",
280 280 "firstname": "username",
281 281 "ip_addresses": [],
282 282 "language": null,
283 283 "last_login": "2015-09-16T17:16:35.854",
284 284 "lastname": "surname",
285 285 "user_id": <user_id>,
286 286 "username": "name"
287 287 }
288 288 ],
289 289 "fork_of": "parent-repo",
290 290 "landing_rev": [
291 291 "rev",
292 292 "tip"
293 293 ],
294 294 "last_changeset": {
295 295 "author": "User <user@example.com>",
296 296 "branch": "default",
297 297 "date": "timestamp",
298 298 "message": "last commit message",
299 299 "parents": [
300 300 {
301 301 "raw_id": "commit-id"
302 302 }
303 303 ],
304 304 "raw_id": "commit-id",
305 305 "revision": <revision number>,
306 306 "short_id": "short id"
307 307 },
308 308 "lock_reason": null,
309 309 "locked_by": null,
310 310 "locked_date": null,
311 311 "owner": "owner-name",
312 312 "permissions": [
313 313 {
314 314 "name": "super-admin-name",
315 315 "origin": "super-admin",
316 316 "permission": "repository.admin",
317 317 "type": "user"
318 318 },
319 319 {
320 320 "name": "owner-name",
321 321 "origin": "owner",
322 322 "permission": "repository.admin",
323 323 "type": "user"
324 324 },
325 325 {
326 326 "name": "user-group-name",
327 327 "origin": "permission",
328 328 "permission": "repository.write",
329 329 "type": "user_group"
330 330 }
331 331 ],
332 332 "private": true,
333 333 "repo_id": 676,
334 334 "repo_name": "user-group/repo-name",
335 335 "repo_type": "hg"
336 336 }
337 337 }
338 338
339 339
340 340 get_repo_changeset
341 341 ------------------
342 342
343 343 .. py:function:: get_repo_changeset(apiuser, repoid, revision, details=<Optional:'basic'>)
344 344
345 345 Returns information about a changeset.
346 346
347 347 Additionally parameters define the amount of details returned by
348 348 this function.
349 349
350 350 This command can only be run using an |authtoken| with admin rights,
351 351 or users with at least read rights to the |repo|.
352 352
353 353 :param apiuser: This is filled automatically from the |authtoken|.
354 354 :type apiuser: AuthUser
355 355 :param repoid: The repository name or repository id
356 356 :type repoid: str or int
357 357 :param revision: revision for which listing should be done
358 358 :type revision: str
359 359 :param details: details can be 'basic|extended|full' full gives diff
360 360 info details like the diff itself, and number of changed files etc.
361 361 :type details: Optional(str)
362 362
363 363
364 364 get_repo_changesets
365 365 -------------------
366 366
367 367 .. py:function:: get_repo_changesets(apiuser, repoid, start_rev, limit, details=<Optional:'basic'>)
368 368
369 369 Returns a set of commits limited by the number starting
370 370 from the `start_rev` option.
371 371
372 372 Additional parameters define the amount of details returned by this
373 373 function.
374 374
375 375 This command can only be run using an |authtoken| with admin rights,
376 376 or users with at least read rights to |repos|.
377 377
378 378 :param apiuser: This is filled automatically from the |authtoken|.
379 379 :type apiuser: AuthUser
380 380 :param repoid: The repository name or repository ID.
381 381 :type repoid: str or int
382 382 :param start_rev: The starting revision from where to get changesets.
383 383 :type start_rev: str
384 384 :param limit: Limit the number of commits to this amount
385 385 :type limit: str or int
386 386 :param details: Set the level of detail returned. Valid option are:
387 387 ``basic``, ``extended`` and ``full``.
388 388 :type details: Optional(str)
389 389
390 390 .. note::
391 391
392 392 Setting the parameter `details` to the value ``full`` is extensive
393 393 and returns details like the diff itself, and the number
394 394 of changed files.
395 395
396 396
397 397 get_repo_comments
398 398 -----------------
399 399
400 400 .. py:function:: get_repo_comments(apiuser, repoid, commit_id=<Optional:None>, comment_type=<Optional:None>, userid=<Optional:None>)
401 401
402 402 Get all comments for a repository
403 403
404 404 :param apiuser: This is filled automatically from the |authtoken|.
405 405 :type apiuser: AuthUser
406 406 :param repoid: Set the repository name or repository ID.
407 407 :type repoid: str or int
408 408 :param commit_id: Optionally filter the comments by the commit_id
409 409 :type commit_id: Optional(str), default: None
410 410 :param comment_type: Optionally filter the comments by the comment_type
411 411 one of: 'note', 'todo'
412 412 :type comment_type: Optional(str), default: None
413 413 :param userid: Optionally filter the comments by the author of comment
414 414 :type userid: Optional(str or int), Default: None
415 415
416 416 Example error output:
417 417
418 418 .. code-block:: bash
419 419
420 420 {
421 421 "id" : <id_given_in_input>,
422 422 "result" : [
423 423 {
424 424 "comment_author": <USER_DETAILS>,
425 425 "comment_created_on": "2017-02-01T14:38:16.309",
426 426 "comment_f_path": "file.txt",
427 427 "comment_id": 282,
428 428 "comment_lineno": "n1",
429 429 "comment_resolved_by": null,
430 430 "comment_status": [],
431 431 "comment_text": "This file needs a header",
432 432 "comment_type": "todo"
433 433 }
434 434 ],
435 435 "error" : null
436 436 }
437 437
438 438
439 439 get_repo_file
440 440 -------------
441 441
442 442 .. py:function:: get_repo_file(apiuser, repoid, commit_id, file_path, max_file_bytes=<Optional:None>, details=<Optional:'basic'>, cache=<Optional:True>)
443 443
444 444 Returns a single file from repository at given revision.
445 445
446 446 This command can only be run using an |authtoken| with admin rights,
447 447 or users with at least read rights to |repos|.
448 448
449 449 :param apiuser: This is filled automatically from the |authtoken|.
450 450 :type apiuser: AuthUser
451 451 :param repoid: The repository name or repository ID.
452 452 :type repoid: str or int
453 453 :param commit_id: The revision for which listing should be done.
454 454 :type commit_id: str
455 455 :param file_path: The path from which to start displaying.
456 456 :type file_path: str
457 457 :param details: Returns different set of information about nodes.
458 458 The valid options are ``minimal`` ``basic`` and ``full``.
459 459 :type details: Optional(str)
460 460 :param max_file_bytes: Only return file content under this file size bytes
461 461 :type max_file_bytes: Optional(int)
462 462 :param cache: Use internal caches for fetching files. If disabled fetching
463 463 files is slower but more memory efficient
464 464 :type cache: Optional(bool)
465
465 466 Example output:
466 467
467 468 .. code-block:: bash
468 469
469 470 id : <id_given_in_input>
470 471 result: {
471 472 "binary": false,
472 473 "extension": "py",
473 474 "lines": 35,
474 475 "content": "....",
475 476 "md5": "76318336366b0f17ee249e11b0c99c41",
476 477 "mimetype": "text/x-python",
477 478 "name": "python.py",
478 479 "size": 817,
479 480 "type": "file",
480 481 }
481 482 error: null
482 483
483 484
484 485 get_repo_fts_tree
485 486 -----------------
486 487
487 488 .. py:function:: get_repo_fts_tree(apiuser, repoid, commit_id, root_path)
488 489
489 490 Returns a list of tree nodes for path at given revision. This api is built
490 491 strictly for usage in full text search building, and shouldn't be consumed
491 492
492 493 This command can only be run using an |authtoken| with admin rights,
493 494 or users with at least read rights to |repos|.
494 495
495 496
496 497 get_repo_nodes
497 498 --------------
498 499
499 500 .. py:function:: get_repo_nodes(apiuser, repoid, revision, root_path, ret_type=<Optional:'all'>, details=<Optional:'basic'>, max_file_bytes=<Optional:None>)
500 501
501 502 Returns a list of nodes and children in a flat list for a given
502 503 path at given revision.
503 504
504 505 It's possible to specify ret_type to show only `files` or `dirs`.
505 506
506 507 This command can only be run using an |authtoken| with admin rights,
507 508 or users with at least read rights to |repos|.
508 509
509 510 :param apiuser: This is filled automatically from the |authtoken|.
510 511 :type apiuser: AuthUser
511 512 :param repoid: The repository name or repository ID.
512 513 :type repoid: str or int
513 514 :param revision: The revision for which listing should be done.
514 515 :type revision: str
515 516 :param root_path: The path from which to start displaying.
516 517 :type root_path: str
517 518 :param ret_type: Set the return type. Valid options are
518 519 ``all`` (default), ``files`` and ``dirs``.
519 520 :type ret_type: Optional(str)
520 521 :param details: Returns extended information about nodes, such as
521 522 md5, binary, and or content.
522 523 The valid options are ``basic`` and ``full``.
523 524 :type details: Optional(str)
524 525 :param max_file_bytes: Only return file content under this file size bytes
525 526 :type details: Optional(int)
526 527
527 528 Example output:
528 529
529 530 .. code-block:: bash
530 531
531 532 id : <id_given_in_input>
532 533 result: [
533 534 {
534 535 "binary": false,
535 "content": "File line
536 Line2
537 ",
536 "content": "File line",
538 537 "extension": "md",
539 538 "lines": 2,
540 539 "md5": "059fa5d29b19c0657e384749480f6422",
541 540 "mimetype": "text/x-minidsrc",
542 541 "name": "file.md",
543 542 "size": 580,
544 543 "type": "file"
545 544 },
546 545 ...
547 546 ]
548 547 error: null
549 548
550 549
551 550 get_repo_refs
552 551 -------------
553 552
554 553 .. py:function:: get_repo_refs(apiuser, repoid)
555 554
556 555 Returns a dictionary of current references. It returns
557 556 bookmarks, branches, closed_branches, and tags for given repository
558 557
559 558 It's possible to specify ret_type to show only `files` or `dirs`.
560 559
561 560 This command can only be run using an |authtoken| with admin rights,
562 561 or users with at least read rights to |repos|.
563 562
564 563 :param apiuser: This is filled automatically from the |authtoken|.
565 564 :type apiuser: AuthUser
566 565 :param repoid: The repository name or repository ID.
567 566 :type repoid: str or int
568 567
569 568 Example output:
570 569
571 570 .. code-block:: bash
572 571
573 572 id : <id_given_in_input>
574 573 "result": {
575 574 "bookmarks": {
576 575 "dev": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
577 576 "master": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
578 577 },
579 578 "branches": {
580 579 "default": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
581 580 "stable": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
582 581 },
583 582 "branches_closed": {},
584 583 "tags": {
585 584 "tip": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
586 585 "v4.4.0": "1232313f9e6adac5ce5399c2a891dc1e72b79022",
587 586 "v4.4.1": "cbb9f1d329ae5768379cdec55a62ebdd546c4e27",
588 587 "v4.4.2": "24ffe44a27fcd1c5b6936144e176b9f6dd2f3a17",
589 588 }
590 589 }
591 590 error: null
592 591
593 592
594 593 get_repo_settings
595 594 -----------------
596 595
597 596 .. py:function:: get_repo_settings(apiuser, repoid, key=<Optional:None>)
598 597
599 598 Returns all settings for a repository. If key is given it only returns the
600 599 setting identified by the key or null.
601 600
602 601 :param apiuser: This is filled automatically from the |authtoken|.
603 602 :type apiuser: AuthUser
604 603 :param repoid: The repository name or repository id.
605 604 :type repoid: str or int
606 605 :param key: Key of the setting to return.
607 606 :type: key: Optional(str)
608 607
609 608 Example output:
610 609
611 610 .. code-block:: bash
612 611
613 612 {
614 613 "error": null,
615 614 "id": 237,
616 615 "result": {
617 616 "extensions_largefiles": true,
618 617 "extensions_evolve": true,
619 618 "hooks_changegroup_push_logger": true,
620 619 "hooks_changegroup_repo_size": false,
621 620 "hooks_outgoing_pull_logger": true,
622 621 "phases_publish": "True",
623 622 "rhodecode_hg_use_rebase_for_merging": true,
624 623 "rhodecode_pr_merge_enabled": true,
625 624 "rhodecode_use_outdated_comments": true
626 625 }
627 626 }
628 627
629 628
630 629 get_repos
631 630 ---------
632 631
633 632 .. py:function:: get_repos(apiuser, root=<Optional:None>, traverse=<Optional:True>)
634 633
635 634 Lists all existing repositories.
636 635
637 636 This command can only be run using an |authtoken| with admin rights,
638 637 or users with at least read rights to |repos|.
639 638
640 639 :param apiuser: This is filled automatically from the |authtoken|.
641 640 :type apiuser: AuthUser
642 641 :param root: specify root repository group to fetch repositories.
643 642 filters the returned repositories to be members of given root group.
644 643 :type root: Optional(None)
645 644 :param traverse: traverse given root into subrepositories. With this flag
646 645 set to False, it will only return top-level repositories from `root`.
647 646 if root is empty it will return just top-level repositories.
648 647 :type traverse: Optional(True)
649 648
650 649
651 650 Example output:
652 651
653 652 .. code-block:: bash
654 653
655 654 id : <id_given_in_input>
656 655 result: [
657 656 {
658 657 "repo_id" : "<repo_id>",
659 658 "repo_name" : "<reponame>"
660 659 "repo_type" : "<repo_type>",
661 660 "clone_uri" : "<clone_uri>",
662 661 "private": : "<bool>",
663 662 "created_on" : "<datetimecreated>",
664 663 "description" : "<description>",
665 664 "landing_rev": "<landing_rev>",
666 665 "owner": "<repo_owner>",
667 666 "fork_of": "<name_of_fork_parent>",
668 667 "enable_downloads": "<bool>",
669 668 "enable_locking": "<bool>",
670 669 "enable_statistics": "<bool>",
671 670 },
672 671 ...
673 672 ]
674 673 error: null
675 674
676 675
677 676 grant_user_group_permission
678 677 ---------------------------
679 678
680 679 .. py:function:: grant_user_group_permission(apiuser, repoid, usergroupid, perm)
681 680
682 681 Grant permission for a user group on the specified repository,
683 682 or update existing permissions.
684 683
685 684 This command can only be run using an |authtoken| with admin
686 685 permissions on the |repo|.
687 686
688 687 :param apiuser: This is filled automatically from the |authtoken|.
689 688 :type apiuser: AuthUser
690 689 :param repoid: Set the repository name or repository ID.
691 690 :type repoid: str or int
692 691 :param usergroupid: Specify the ID of the user group.
693 692 :type usergroupid: str or int
694 693 :param perm: Set the user group permissions using the following
695 694 format: (repository.(none|read|write|admin))
696 695 :type perm: str
697 696
698 697 Example output:
699 698
700 699 .. code-block:: bash
701 700
702 701 id : <id_given_in_input>
703 702 result : {
704 703 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
705 704 "success": true
706 705
707 706 }
708 707 error : null
709 708
710 709 Example error output:
711 710
712 711 .. code-block:: bash
713 712
714 713 id : <id_given_in_input>
715 714 result : null
716 715 error : {
717 716 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
718 717 }
719 718
720 719
721 720 grant_user_permission
722 721 ---------------------
723 722
724 723 .. py:function:: grant_user_permission(apiuser, repoid, userid, perm)
725 724
726 725 Grant permissions for the specified user on the given repository,
727 726 or update existing permissions if found.
728 727
729 728 This command can only be run using an |authtoken| with admin
730 729 permissions on the |repo|.
731 730
732 731 :param apiuser: This is filled automatically from the |authtoken|.
733 732 :type apiuser: AuthUser
734 733 :param repoid: Set the repository name or repository ID.
735 734 :type repoid: str or int
736 735 :param userid: Set the user name.
737 736 :type userid: str
738 737 :param perm: Set the user permissions, using the following format
739 738 ``(repository.(none|read|write|admin))``
740 739 :type perm: str
741 740
742 741 Example output:
743 742
744 743 .. code-block:: bash
745 744
746 745 id : <id_given_in_input>
747 746 result: {
748 747 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
749 748 "success": true
750 749 }
751 750 error: null
752 751
753 752
754 753 invalidate_cache
755 754 ----------------
756 755
757 756 .. py:function:: invalidate_cache(apiuser, repoid, delete_keys=<Optional:False>)
758 757
759 758 Invalidates the cache for the specified repository.
760 759
761 760 This command can only be run using an |authtoken| with admin rights to
762 761 the specified repository.
763 762
764 763 This command takes the following options:
765 764
766 765 :param apiuser: This is filled automatically from |authtoken|.
767 766 :type apiuser: AuthUser
768 767 :param repoid: Sets the repository name or repository ID.
769 768 :type repoid: str or int
770 769 :param delete_keys: This deletes the invalidated keys instead of
771 770 just flagging them.
772 771 :type delete_keys: Optional(``True`` | ``False``)
773 772
774 773 Example output:
775 774
776 775 .. code-block:: bash
777 776
778 777 id : <id_given_in_input>
779 778 result : {
780 779 'msg': Cache for repository `<repository name>` was invalidated,
781 780 'repository': <repository name>
782 781 }
783 782 error : null
784 783
785 784 Example error output:
786 785
787 786 .. code-block:: bash
788 787
789 788 id : <id_given_in_input>
790 789 result : null
791 790 error : {
792 791 'Error occurred during cache invalidation action'
793 792 }
794 793
795 794
796 795 lock
797 796 ----
798 797
799 798 .. py:function:: lock(apiuser, repoid, locked=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
800 799
801 800 Sets the lock state of the specified |repo| by the given user.
802 801 From more information, see :ref:`repo-locking`.
803 802
804 803 * If the ``userid`` option is not set, the repository is locked to the
805 804 user who called the method.
806 805 * If the ``locked`` parameter is not set, the current lock state of the
807 806 repository is displayed.
808 807
809 808 This command can only be run using an |authtoken| with admin rights to
810 809 the specified repository.
811 810
812 811 This command takes the following options:
813 812
814 813 :param apiuser: This is filled automatically from the |authtoken|.
815 814 :type apiuser: AuthUser
816 815 :param repoid: Sets the repository name or repository ID.
817 816 :type repoid: str or int
818 817 :param locked: Sets the lock state.
819 818 :type locked: Optional(``True`` | ``False``)
820 819 :param userid: Set the repository lock to this user.
821 820 :type userid: Optional(str or int)
822 821
823 822 Example error output:
824 823
825 824 .. code-block:: bash
826 825
827 826 id : <id_given_in_input>
828 827 result : {
829 828 'repo': '<reponame>',
830 829 'locked': <bool: lock state>,
831 830 'locked_since': <int: lock timestamp>,
832 831 'locked_by': <username of person who made the lock>,
833 832 'lock_reason': <str: reason for locking>,
834 833 'lock_state_changed': <bool: True if lock state has been changed in this request>,
835 834 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
836 835 or
837 836 'msg': 'Repo `<repository name>` not locked.'
838 837 or
839 838 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
840 839 }
841 840 error : null
842 841
843 842 Example error output:
844 843
845 844 .. code-block:: bash
846 845
847 846 id : <id_given_in_input>
848 847 result : null
849 848 error : {
850 849 'Error occurred locking repository `<reponame>`'
851 850 }
852 851
853 852
854 853 maintenance
855 854 -----------
856 855
857 856 .. py:function:: maintenance(apiuser, repoid)
858 857
859 858 Triggers a maintenance on the given repository.
860 859
861 860 This command can only be run using an |authtoken| with admin
862 861 rights to the specified repository. For more information,
863 862 see :ref:`config-token-ref`.
864 863
865 864 This command takes the following options:
866 865
867 866 :param apiuser: This is filled automatically from the |authtoken|.
868 867 :type apiuser: AuthUser
869 868 :param repoid: The repository name or repository ID.
870 869 :type repoid: str or int
871 870
872 871 Example output:
873 872
874 873 .. code-block:: bash
875 874
876 875 id : <id_given_in_input>
877 876 result : {
878 877 "msg": "executed maintenance command",
879 878 "executed_actions": [
880 879 <action_message>, <action_message2>...
881 880 ],
882 881 "repository": "<repository name>"
883 882 }
884 883 error : null
885 884
886 885 Example error output:
887 886
888 887 .. code-block:: bash
889 888
890 889 id : <id_given_in_input>
891 890 result : null
892 891 error : {
893 892 "Unable to execute maintenance on `<reponame>`"
894 893 }
895 894
896 895
897 896 pull
898 897 ----
899 898
900 899 .. py:function:: pull(apiuser, repoid, remote_uri=<Optional:None>)
901 900
902 901 Triggers a pull on the given repository from a remote location. You
903 902 can use this to keep remote repositories up-to-date.
904 903
905 904 This command can only be run using an |authtoken| with admin
906 905 rights to the specified repository. For more information,
907 906 see :ref:`config-token-ref`.
908 907
909 908 This command takes the following options:
910 909
911 910 :param apiuser: This is filled automatically from the |authtoken|.
912 911 :type apiuser: AuthUser
913 912 :param repoid: The repository name or repository ID.
914 913 :type repoid: str or int
915 914 :param remote_uri: Optional remote URI to pass in for pull
916 915 :type remote_uri: str
917 916
918 917 Example output:
919 918
920 919 .. code-block:: bash
921 920
922 921 id : <id_given_in_input>
923 922 result : {
924 923 "msg": "Pulled from url `<remote_url>` on repo `<repository name>`"
925 924 "repository": "<repository name>"
926 925 }
927 926 error : null
928 927
929 928 Example error output:
930 929
931 930 .. code-block:: bash
932 931
933 932 id : <id_given_in_input>
934 933 result : null
935 934 error : {
936 935 "Unable to push changes from `<remote_url>`"
937 936 }
938 937
939 938
940 939 remove_field_from_repo
941 940 ----------------------
942 941
943 942 .. py:function:: remove_field_from_repo(apiuser, repoid, key)
944 943
945 944 Removes an extra field from a repository.
946 945
947 946 This command can only be run using an |authtoken| with at least
948 947 write permissions to the |repo|.
949 948
950 949 :param apiuser: This is filled automatically from the |authtoken|.
951 950 :type apiuser: AuthUser
952 951 :param repoid: Set the repository name or repository ID.
953 952 :type repoid: str or int
954 953 :param key: Set the unique field key for this repository.
955 954 :type key: str
956 955
957 956
958 957 revoke_user_group_permission
959 958 ----------------------------
960 959
961 960 .. py:function:: revoke_user_group_permission(apiuser, repoid, usergroupid)
962 961
963 962 Revoke the permissions of a user group on a given repository.
964 963
965 964 This command can only be run using an |authtoken| with admin
966 965 permissions on the |repo|.
967 966
968 967 :param apiuser: This is filled automatically from the |authtoken|.
969 968 :type apiuser: AuthUser
970 969 :param repoid: Set the repository name or repository ID.
971 970 :type repoid: str or int
972 971 :param usergroupid: Specify the user group ID.
973 972 :type usergroupid: str or int
974 973
975 974 Example output:
976 975
977 976 .. code-block:: bash
978 977
979 978 id : <id_given_in_input>
980 979 result: {
981 980 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
982 981 "success": true
983 982 }
984 983 error: null
985 984
986 985
987 986 revoke_user_permission
988 987 ----------------------
989 988
990 989 .. py:function:: revoke_user_permission(apiuser, repoid, userid)
991 990
992 991 Revoke permission for a user on the specified repository.
993 992
994 993 This command can only be run using an |authtoken| with admin
995 994 permissions on the |repo|.
996 995
997 996 :param apiuser: This is filled automatically from the |authtoken|.
998 997 :type apiuser: AuthUser
999 998 :param repoid: Set the repository name or repository ID.
1000 999 :type repoid: str or int
1001 1000 :param userid: Set the user name of revoked user.
1002 1001 :type userid: str or int
1003 1002
1004 1003 Example error output:
1005 1004
1006 1005 .. code-block:: bash
1007 1006
1008 1007 id : <id_given_in_input>
1009 1008 result: {
1010 1009 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1011 1010 "success": true
1012 1011 }
1013 1012 error: null
1014 1013
1015 1014
1016 1015 set_repo_settings
1017 1016 -----------------
1018 1017
1019 1018 .. py:function:: set_repo_settings(apiuser, repoid, settings)
1020 1019
1021 1020 Update repository settings. Returns true on success.
1022 1021
1023 1022 :param apiuser: This is filled automatically from the |authtoken|.
1024 1023 :type apiuser: AuthUser
1025 1024 :param repoid: The repository name or repository id.
1026 1025 :type repoid: str or int
1027 1026 :param settings: The new settings for the repository.
1028 1027 :type: settings: dict
1029 1028
1030 1029 Example output:
1031 1030
1032 1031 .. code-block:: bash
1033 1032
1034 1033 {
1035 1034 "error": null,
1036 1035 "id": 237,
1037 1036 "result": true
1038 1037 }
1039 1038
1040 1039
1041 1040 strip
1042 1041 -----
1043 1042
1044 1043 .. py:function:: strip(apiuser, repoid, revision, branch)
1045 1044
1046 1045 Strips the given revision from the specified repository.
1047 1046
1048 1047 * This will remove the revision and all of its decendants.
1049 1048
1050 1049 This command can only be run using an |authtoken| with admin rights to
1051 1050 the specified repository.
1052 1051
1053 1052 This command takes the following options:
1054 1053
1055 1054 :param apiuser: This is filled automatically from the |authtoken|.
1056 1055 :type apiuser: AuthUser
1057 1056 :param repoid: The repository name or repository ID.
1058 1057 :type repoid: str or int
1059 1058 :param revision: The revision you wish to strip.
1060 1059 :type revision: str
1061 1060 :param branch: The branch from which to strip the revision.
1062 1061 :type branch: str
1063 1062
1064 1063 Example output:
1065 1064
1066 1065 .. code-block:: bash
1067 1066
1068 1067 id : <id_given_in_input>
1069 1068 result : {
1070 1069 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
1071 1070 "repository": "<repository name>"
1072 1071 }
1073 1072 error : null
1074 1073
1075 1074 Example error output:
1076 1075
1077 1076 .. code-block:: bash
1078 1077
1079 1078 id : <id_given_in_input>
1080 1079 result : null
1081 1080 error : {
1082 1081 "Unable to strip commit <commit_hash> from repo `<repository name>`"
1083 1082 }
1084 1083
1085 1084
1086 1085 update_repo
1087 1086 -----------
1088 1087
1089 1088 .. py:function:: update_repo(apiuser, repoid, repo_name=<Optional:None>, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, push_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, fork_of=<Optional:None>, enable_statistics=<Optional:False>, enable_locking=<Optional:False>, enable_downloads=<Optional:False>, fields=<Optional:''>)
1090 1089
1091 1090 Updates a repository with the given information.
1092 1091
1093 1092 This command can only be run using an |authtoken| with at least
1094 1093 admin permissions to the |repo|.
1095 1094
1096 1095 * If the repository name contains "/", repository will be updated
1097 1096 accordingly with a repository group or nested repository groups
1098 1097
1099 1098 For example repoid=repo-test name="foo/bar/repo-test" will update |repo|
1100 1099 called "repo-test" and place it inside group "foo/bar".
1101 1100 You have to have permissions to access and write to the last repository
1102 1101 group ("bar" in this example)
1103 1102
1104 1103 :param apiuser: This is filled automatically from the |authtoken|.
1105 1104 :type apiuser: AuthUser
1106 1105 :param repoid: repository name or repository ID.
1107 1106 :type repoid: str or int
1108 1107 :param repo_name: Update the |repo| name, including the
1109 1108 repository group it's in.
1110 1109 :type repo_name: str
1111 1110 :param owner: Set the |repo| owner.
1112 1111 :type owner: str
1113 1112 :param fork_of: Set the |repo| as fork of another |repo|.
1114 1113 :type fork_of: str
1115 1114 :param description: Update the |repo| description.
1116 1115 :type description: str
1117 1116 :param private: Set the |repo| as private. (True | False)
1118 1117 :type private: bool
1119 1118 :param clone_uri: Update the |repo| clone URI.
1120 1119 :type clone_uri: str
1121 1120 :param landing_rev: Set the |repo| landing revision. Default is ``rev:tip``.
1122 1121 :type landing_rev: str
1123 1122 :param enable_statistics: Enable statistics on the |repo|, (True | False).
1124 1123 :type enable_statistics: bool
1125 1124 :param enable_locking: Enable |repo| locking.
1126 1125 :type enable_locking: bool
1127 1126 :param enable_downloads: Enable downloads from the |repo|, (True | False).
1128 1127 :type enable_downloads: bool
1129 1128 :param fields: Add extra fields to the |repo|. Use the following
1130 1129 example format: ``field_key=field_val,field_key2=fieldval2``.
1131 1130 Escape ', ' with \,
1132 1131 :type fields: str
1133 1132
1134 1133
@@ -1,87 +1,87 b''
1 1 |RCE|
2 2 =====
3 3
4 4 |RCE| is a high-performance source code management and collaboration system.
5 5 It enables you to develop projects securely behind the firewall while
6 6 providing collaboration tools that work with |git|, |hg|,
7 7 and |svn| |repos|. The user interface allows you to create, edit,
8 8 and commit files and |repos| while managing their security permissions.
9 9
10 10 |RCE| provides the following features:
11 11
12 12 * Source code management.
13 13 * Extended permissions management.
14 14 * Integrated code collaboration tools.
15 15 * Integrated code review and notifications.
16 16 * Scalability provided by multi-node setup.
17 17 * Fully programmable automation API.
18 18 * Web-based hook management.
19 19 * Native |svn| support.
20 20 * Migration from existing databases.
21 21 * |RCE| SDK.
22 22 * Built-in analytics
23 23 * Built in integrations including: Slack, Webhooks (used for Jenkins/TeamCity and other CIs), Jira, Redmine, Hipchat
24 24 * Pluggable authentication system.
25 25 * Support for AD, |LDAP|, Crowd, CAS, PAM.
26 26 * Support for external authentication via Oauth Google, Github, Bitbucket, Twitter.
27 27 * Debug modes of operation.
28 28 * Private and public gists.
29 29 * Gists with limited lifetimes and within instance only sharing.
30 30 * Fully integrated code search function.
31 31 * Always on SSL connectivity.
32 32
33 33 .. only:: html
34 34
35 35 Table of Contents
36 36 -----------------
37 37
38 38 .. toctree::
39 39 :maxdepth: 1
40 40 :caption: Admin Documentation
41 41
42 42 install/quick-start
43 43 install/install-database
44 44 install/install-steps
45 45 admin/system-overview
46 46 nix/default-env
47 47 admin/system-admin
48 48 admin/user-admin
49 admin/setting-repo-perms
49 admin/repo-admin
50 50 admin/security-tips
51 51 auth/auth
52 52 issue-trackers/issue-trackers
53 53 admin/lab-settings
54 54
55 55 .. toctree::
56 56 :maxdepth: 1
57 57 :caption: Feature Documentation
58 58
59 59 collaboration/collaboration
60 60 collaboration/review-notifications
61 61 collaboration/pull-requests
62 62 code-review/code-review
63 63 integrations/integrations
64 64
65 65 .. toctree::
66 66 :maxdepth: 1
67 67 :caption: User Documentation
68 68
69 69 usage/basic-usage
70 70 tutorials/tutorials
71 71
72 72 .. toctree::
73 73 :maxdepth: 1
74 74 :caption: Developer Documentation
75 75
76 76 api/api
77 77 tools/rhodecode-tools
78 78 extensions/extensions-hooks
79 79 contributing/contributing
80 80
81 81 .. toctree::
82 82 :maxdepth: 1
83 83 :caption: About
84 84
85 85 known-issues/known-issues
86 86 release-notes/release-notes
87 87 admin/glossary
@@ -1,2314 +1,2315 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2019 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22 import time
23 23
24 24 import rhodecode
25 25 from rhodecode.api import (
26 26 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
27 27 from rhodecode.api.utils import (
28 28 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
29 29 get_user_group_or_error, get_user_or_error, validate_repo_permissions,
30 30 get_perm_or_error, parse_args, get_origin, build_commit_data,
31 31 validate_set_owner_permissions)
32 32 from rhodecode.lib import audit_logger, rc_cache
33 33 from rhodecode.lib import repo_maintenance
34 34 from rhodecode.lib.auth import HasPermissionAnyApi, HasUserGroupPermissionAnyApi
35 35 from rhodecode.lib.celerylib.utils import get_task_id
36 36 from rhodecode.lib.utils2 import str2bool, time_to_datetime, safe_str, safe_int
37 37 from rhodecode.lib.ext_json import json
38 38 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
39 39 from rhodecode.lib.vcs import RepositoryError
40 40 from rhodecode.lib.vcs.exceptions import NodeDoesNotExistError
41 41 from rhodecode.model.changeset_status import ChangesetStatusModel
42 42 from rhodecode.model.comment import CommentsModel
43 43 from rhodecode.model.db import (
44 44 Session, ChangesetStatus, RepositoryField, Repository, RepoGroup,
45 45 ChangesetComment)
46 46 from rhodecode.model.repo import RepoModel
47 47 from rhodecode.model.scm import ScmModel, RepoList
48 48 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
49 49 from rhodecode.model import validation_schema
50 50 from rhodecode.model.validation_schema.schemas import repo_schema
51 51
52 52 log = logging.getLogger(__name__)
53 53
54 54
55 55 @jsonrpc_method()
56 56 def get_repo(request, apiuser, repoid, cache=Optional(True)):
57 57 """
58 58 Gets an existing repository by its name or repository_id.
59 59
60 60 The members section so the output returns users groups or users
61 61 associated with that repository.
62 62
63 63 This command can only be run using an |authtoken| with admin rights,
64 64 or users with at least read rights to the |repo|.
65 65
66 66 :param apiuser: This is filled automatically from the |authtoken|.
67 67 :type apiuser: AuthUser
68 68 :param repoid: The repository name or repository id.
69 69 :type repoid: str or int
70 70 :param cache: use the cached value for last changeset
71 71 :type: cache: Optional(bool)
72 72
73 73 Example output:
74 74
75 75 .. code-block:: bash
76 76
77 77 {
78 78 "error": null,
79 79 "id": <repo_id>,
80 80 "result": {
81 81 "clone_uri": null,
82 82 "created_on": "timestamp",
83 83 "description": "repo description",
84 84 "enable_downloads": false,
85 85 "enable_locking": false,
86 86 "enable_statistics": false,
87 87 "followers": [
88 88 {
89 89 "active": true,
90 90 "admin": false,
91 91 "api_key": "****************************************",
92 92 "api_keys": [
93 93 "****************************************"
94 94 ],
95 95 "email": "user@example.com",
96 96 "emails": [
97 97 "user@example.com"
98 98 ],
99 99 "extern_name": "rhodecode",
100 100 "extern_type": "rhodecode",
101 101 "firstname": "username",
102 102 "ip_addresses": [],
103 103 "language": null,
104 104 "last_login": "2015-09-16T17:16:35.854",
105 105 "lastname": "surname",
106 106 "user_id": <user_id>,
107 107 "username": "name"
108 108 }
109 109 ],
110 110 "fork_of": "parent-repo",
111 111 "landing_rev": [
112 112 "rev",
113 113 "tip"
114 114 ],
115 115 "last_changeset": {
116 116 "author": "User <user@example.com>",
117 117 "branch": "default",
118 118 "date": "timestamp",
119 119 "message": "last commit message",
120 120 "parents": [
121 121 {
122 122 "raw_id": "commit-id"
123 123 }
124 124 ],
125 125 "raw_id": "commit-id",
126 126 "revision": <revision number>,
127 127 "short_id": "short id"
128 128 },
129 129 "lock_reason": null,
130 130 "locked_by": null,
131 131 "locked_date": null,
132 132 "owner": "owner-name",
133 133 "permissions": [
134 134 {
135 135 "name": "super-admin-name",
136 136 "origin": "super-admin",
137 137 "permission": "repository.admin",
138 138 "type": "user"
139 139 },
140 140 {
141 141 "name": "owner-name",
142 142 "origin": "owner",
143 143 "permission": "repository.admin",
144 144 "type": "user"
145 145 },
146 146 {
147 147 "name": "user-group-name",
148 148 "origin": "permission",
149 149 "permission": "repository.write",
150 150 "type": "user_group"
151 151 }
152 152 ],
153 153 "private": true,
154 154 "repo_id": 676,
155 155 "repo_name": "user-group/repo-name",
156 156 "repo_type": "hg"
157 157 }
158 158 }
159 159 """
160 160
161 161 repo = get_repo_or_error(repoid)
162 162 cache = Optional.extract(cache)
163 163
164 164 include_secrets = False
165 165 if has_superadmin_permission(apiuser):
166 166 include_secrets = True
167 167 else:
168 168 # check if we have at least read permission for this repo !
169 169 _perms = (
170 170 'repository.admin', 'repository.write', 'repository.read',)
171 171 validate_repo_permissions(apiuser, repoid, repo, _perms)
172 172
173 173 permissions = []
174 174 for _user in repo.permissions():
175 175 user_data = {
176 176 'name': _user.username,
177 177 'permission': _user.permission,
178 178 'origin': get_origin(_user),
179 179 'type': "user",
180 180 }
181 181 permissions.append(user_data)
182 182
183 183 for _user_group in repo.permission_user_groups():
184 184 user_group_data = {
185 185 'name': _user_group.users_group_name,
186 186 'permission': _user_group.permission,
187 187 'origin': get_origin(_user_group),
188 188 'type': "user_group",
189 189 }
190 190 permissions.append(user_group_data)
191 191
192 192 following_users = [
193 193 user.user.get_api_data(include_secrets=include_secrets)
194 194 for user in repo.followers]
195 195
196 196 if not cache:
197 197 repo.update_commit_cache()
198 198 data = repo.get_api_data(include_secrets=include_secrets)
199 199 data['permissions'] = permissions
200 200 data['followers'] = following_users
201 201 return data
202 202
203 203
204 204 @jsonrpc_method()
205 205 def get_repos(request, apiuser, root=Optional(None), traverse=Optional(True)):
206 206 """
207 207 Lists all existing repositories.
208 208
209 209 This command can only be run using an |authtoken| with admin rights,
210 210 or users with at least read rights to |repos|.
211 211
212 212 :param apiuser: This is filled automatically from the |authtoken|.
213 213 :type apiuser: AuthUser
214 214 :param root: specify root repository group to fetch repositories.
215 215 filters the returned repositories to be members of given root group.
216 216 :type root: Optional(None)
217 217 :param traverse: traverse given root into subrepositories. With this flag
218 218 set to False, it will only return top-level repositories from `root`.
219 219 if root is empty it will return just top-level repositories.
220 220 :type traverse: Optional(True)
221 221
222 222
223 223 Example output:
224 224
225 225 .. code-block:: bash
226 226
227 227 id : <id_given_in_input>
228 228 result: [
229 229 {
230 230 "repo_id" : "<repo_id>",
231 231 "repo_name" : "<reponame>"
232 232 "repo_type" : "<repo_type>",
233 233 "clone_uri" : "<clone_uri>",
234 234 "private": : "<bool>",
235 235 "created_on" : "<datetimecreated>",
236 236 "description" : "<description>",
237 237 "landing_rev": "<landing_rev>",
238 238 "owner": "<repo_owner>",
239 239 "fork_of": "<name_of_fork_parent>",
240 240 "enable_downloads": "<bool>",
241 241 "enable_locking": "<bool>",
242 242 "enable_statistics": "<bool>",
243 243 },
244 244 ...
245 245 ]
246 246 error: null
247 247 """
248 248
249 249 include_secrets = has_superadmin_permission(apiuser)
250 250 _perms = ('repository.read', 'repository.write', 'repository.admin',)
251 251 extras = {'user': apiuser}
252 252
253 253 root = Optional.extract(root)
254 254 traverse = Optional.extract(traverse, binary=True)
255 255
256 256 if root:
257 257 # verify parent existance, if it's empty return an error
258 258 parent = RepoGroup.get_by_group_name(root)
259 259 if not parent:
260 260 raise JSONRPCError(
261 261 'Root repository group `{}` does not exist'.format(root))
262 262
263 263 if traverse:
264 264 repos = RepoModel().get_repos_for_root(root=root, traverse=traverse)
265 265 else:
266 266 repos = RepoModel().get_repos_for_root(root=parent)
267 267 else:
268 268 if traverse:
269 269 repos = RepoModel().get_all()
270 270 else:
271 271 # return just top-level
272 272 repos = RepoModel().get_repos_for_root(root=None)
273 273
274 274 repo_list = RepoList(repos, perm_set=_perms, extra_kwargs=extras)
275 275 return [repo.get_api_data(include_secrets=include_secrets)
276 276 for repo in repo_list]
277 277
278 278
279 279 @jsonrpc_method()
280 280 def get_repo_changeset(request, apiuser, repoid, revision,
281 281 details=Optional('basic')):
282 282 """
283 283 Returns information about a changeset.
284 284
285 285 Additionally parameters define the amount of details returned by
286 286 this function.
287 287
288 288 This command can only be run using an |authtoken| with admin rights,
289 289 or users with at least read rights to the |repo|.
290 290
291 291 :param apiuser: This is filled automatically from the |authtoken|.
292 292 :type apiuser: AuthUser
293 293 :param repoid: The repository name or repository id
294 294 :type repoid: str or int
295 295 :param revision: revision for which listing should be done
296 296 :type revision: str
297 297 :param details: details can be 'basic|extended|full' full gives diff
298 298 info details like the diff itself, and number of changed files etc.
299 299 :type details: Optional(str)
300 300
301 301 """
302 302 repo = get_repo_or_error(repoid)
303 303 if not has_superadmin_permission(apiuser):
304 304 _perms = (
305 305 'repository.admin', 'repository.write', 'repository.read',)
306 306 validate_repo_permissions(apiuser, repoid, repo, _perms)
307 307
308 308 changes_details = Optional.extract(details)
309 309 _changes_details_types = ['basic', 'extended', 'full']
310 310 if changes_details not in _changes_details_types:
311 311 raise JSONRPCError(
312 312 'ret_type must be one of %s' % (
313 313 ','.join(_changes_details_types)))
314 314
315 315 pre_load = ['author', 'branch', 'date', 'message', 'parents',
316 316 'status', '_commit', '_file_paths']
317 317
318 318 try:
319 319 cs = repo.get_commit(commit_id=revision, pre_load=pre_load)
320 320 except TypeError as e:
321 321 raise JSONRPCError(safe_str(e))
322 322 _cs_json = cs.__json__()
323 323 _cs_json['diff'] = build_commit_data(cs, changes_details)
324 324 if changes_details == 'full':
325 325 _cs_json['refs'] = cs._get_refs()
326 326 return _cs_json
327 327
328 328
329 329 @jsonrpc_method()
330 330 def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
331 331 details=Optional('basic')):
332 332 """
333 333 Returns a set of commits limited by the number starting
334 334 from the `start_rev` option.
335 335
336 336 Additional parameters define the amount of details returned by this
337 337 function.
338 338
339 339 This command can only be run using an |authtoken| with admin rights,
340 340 or users with at least read rights to |repos|.
341 341
342 342 :param apiuser: This is filled automatically from the |authtoken|.
343 343 :type apiuser: AuthUser
344 344 :param repoid: The repository name or repository ID.
345 345 :type repoid: str or int
346 346 :param start_rev: The starting revision from where to get changesets.
347 347 :type start_rev: str
348 348 :param limit: Limit the number of commits to this amount
349 349 :type limit: str or int
350 350 :param details: Set the level of detail returned. Valid option are:
351 351 ``basic``, ``extended`` and ``full``.
352 352 :type details: Optional(str)
353 353
354 354 .. note::
355 355
356 356 Setting the parameter `details` to the value ``full`` is extensive
357 357 and returns details like the diff itself, and the number
358 358 of changed files.
359 359
360 360 """
361 361 repo = get_repo_or_error(repoid)
362 362 if not has_superadmin_permission(apiuser):
363 363 _perms = (
364 364 'repository.admin', 'repository.write', 'repository.read',)
365 365 validate_repo_permissions(apiuser, repoid, repo, _perms)
366 366
367 367 changes_details = Optional.extract(details)
368 368 _changes_details_types = ['basic', 'extended', 'full']
369 369 if changes_details not in _changes_details_types:
370 370 raise JSONRPCError(
371 371 'ret_type must be one of %s' % (
372 372 ','.join(_changes_details_types)))
373 373
374 374 limit = int(limit)
375 375 pre_load = ['author', 'branch', 'date', 'message', 'parents',
376 376 'status', '_commit', '_file_paths']
377 377
378 378 vcs_repo = repo.scm_instance()
379 379 # SVN needs a special case to distinguish its index and commit id
380 380 if vcs_repo and vcs_repo.alias == 'svn' and (start_rev == '0'):
381 381 start_rev = vcs_repo.commit_ids[0]
382 382
383 383 try:
384 384 commits = vcs_repo.get_commits(
385 385 start_id=start_rev, pre_load=pre_load, translate_tags=False)
386 386 except TypeError as e:
387 387 raise JSONRPCError(safe_str(e))
388 388 except Exception:
389 389 log.exception('Fetching of commits failed')
390 390 raise JSONRPCError('Error occurred during commit fetching')
391 391
392 392 ret = []
393 393 for cnt, commit in enumerate(commits):
394 394 if cnt >= limit != -1:
395 395 break
396 396 _cs_json = commit.__json__()
397 397 _cs_json['diff'] = build_commit_data(commit, changes_details)
398 398 if changes_details == 'full':
399 399 _cs_json['refs'] = {
400 400 'branches': [commit.branch],
401 401 'bookmarks': getattr(commit, 'bookmarks', []),
402 402 'tags': commit.tags
403 403 }
404 404 ret.append(_cs_json)
405 405 return ret
406 406
407 407
408 408 @jsonrpc_method()
409 409 def get_repo_nodes(request, apiuser, repoid, revision, root_path,
410 410 ret_type=Optional('all'), details=Optional('basic'),
411 411 max_file_bytes=Optional(None)):
412 412 """
413 413 Returns a list of nodes and children in a flat list for a given
414 414 path at given revision.
415 415
416 416 It's possible to specify ret_type to show only `files` or `dirs`.
417 417
418 418 This command can only be run using an |authtoken| with admin rights,
419 419 or users with at least read rights to |repos|.
420 420
421 421 :param apiuser: This is filled automatically from the |authtoken|.
422 422 :type apiuser: AuthUser
423 423 :param repoid: The repository name or repository ID.
424 424 :type repoid: str or int
425 425 :param revision: The revision for which listing should be done.
426 426 :type revision: str
427 427 :param root_path: The path from which to start displaying.
428 428 :type root_path: str
429 429 :param ret_type: Set the return type. Valid options are
430 430 ``all`` (default), ``files`` and ``dirs``.
431 431 :type ret_type: Optional(str)
432 432 :param details: Returns extended information about nodes, such as
433 433 md5, binary, and or content.
434 434 The valid options are ``basic`` and ``full``.
435 435 :type details: Optional(str)
436 436 :param max_file_bytes: Only return file content under this file size bytes
437 437 :type details: Optional(int)
438 438
439 439 Example output:
440 440
441 441 .. code-block:: bash
442 442
443 443 id : <id_given_in_input>
444 444 result: [
445 445 {
446 446 "binary": false,
447 "content": "File line\nLine2\n",
447 "content": "File line",
448 448 "extension": "md",
449 449 "lines": 2,
450 450 "md5": "059fa5d29b19c0657e384749480f6422",
451 451 "mimetype": "text/x-minidsrc",
452 452 "name": "file.md",
453 453 "size": 580,
454 454 "type": "file"
455 455 },
456 456 ...
457 457 ]
458 458 error: null
459 459 """
460 460
461 461 repo = get_repo_or_error(repoid)
462 462 if not has_superadmin_permission(apiuser):
463 463 _perms = ('repository.admin', 'repository.write', 'repository.read',)
464 464 validate_repo_permissions(apiuser, repoid, repo, _perms)
465 465
466 466 ret_type = Optional.extract(ret_type)
467 467 details = Optional.extract(details)
468 468 _extended_types = ['basic', 'full']
469 469 if details not in _extended_types:
470 470 raise JSONRPCError('ret_type must be one of %s' % (','.join(_extended_types)))
471 471 extended_info = False
472 472 content = False
473 473 if details == 'basic':
474 474 extended_info = True
475 475
476 476 if details == 'full':
477 477 extended_info = content = True
478 478
479 479 _map = {}
480 480 try:
481 481 # check if repo is not empty by any chance, skip quicker if it is.
482 482 _scm = repo.scm_instance()
483 483 if _scm.is_empty():
484 484 return []
485 485
486 486 _d, _f = ScmModel().get_nodes(
487 487 repo, revision, root_path, flat=False,
488 488 extended_info=extended_info, content=content,
489 489 max_file_bytes=max_file_bytes)
490 490 _map = {
491 491 'all': _d + _f,
492 492 'files': _f,
493 493 'dirs': _d,
494 494 }
495 495 return _map[ret_type]
496 496 except KeyError:
497 497 raise JSONRPCError(
498 498 'ret_type must be one of %s' % (','.join(sorted(_map.keys()))))
499 499 except Exception:
500 500 log.exception("Exception occurred while trying to get repo nodes")
501 501 raise JSONRPCError(
502 502 'failed to get repo: `%s` nodes' % repo.repo_name
503 503 )
504 504
505 505
506 506 @jsonrpc_method()
507 507 def get_repo_file(request, apiuser, repoid, commit_id, file_path,
508 508 max_file_bytes=Optional(None), details=Optional('basic'),
509 509 cache=Optional(True)):
510 510 """
511 511 Returns a single file from repository at given revision.
512 512
513 513 This command can only be run using an |authtoken| with admin rights,
514 514 or users with at least read rights to |repos|.
515 515
516 516 :param apiuser: This is filled automatically from the |authtoken|.
517 517 :type apiuser: AuthUser
518 518 :param repoid: The repository name or repository ID.
519 519 :type repoid: str or int
520 520 :param commit_id: The revision for which listing should be done.
521 521 :type commit_id: str
522 522 :param file_path: The path from which to start displaying.
523 523 :type file_path: str
524 524 :param details: Returns different set of information about nodes.
525 525 The valid options are ``minimal`` ``basic`` and ``full``.
526 526 :type details: Optional(str)
527 527 :param max_file_bytes: Only return file content under this file size bytes
528 528 :type max_file_bytes: Optional(int)
529 529 :param cache: Use internal caches for fetching files. If disabled fetching
530 530 files is slower but more memory efficient
531 531 :type cache: Optional(bool)
532
532 533 Example output:
533 534
534 535 .. code-block:: bash
535 536
536 537 id : <id_given_in_input>
537 538 result: {
538 539 "binary": false,
539 540 "extension": "py",
540 541 "lines": 35,
541 542 "content": "....",
542 543 "md5": "76318336366b0f17ee249e11b0c99c41",
543 544 "mimetype": "text/x-python",
544 545 "name": "python.py",
545 546 "size": 817,
546 547 "type": "file",
547 548 }
548 549 error: null
549 550 """
550 551
551 552 repo = get_repo_or_error(repoid)
552 553 if not has_superadmin_permission(apiuser):
553 554 _perms = ('repository.admin', 'repository.write', 'repository.read',)
554 555 validate_repo_permissions(apiuser, repoid, repo, _perms)
555 556
556 557 cache = Optional.extract(cache, binary=True)
557 558 details = Optional.extract(details)
558 559 _extended_types = ['minimal', 'minimal+search', 'basic', 'full']
559 560 if details not in _extended_types:
560 561 raise JSONRPCError(
561 562 'ret_type must be one of %s, got %s' % (','.join(_extended_types)), details)
562 563 extended_info = False
563 564 content = False
564 565
565 566 if details == 'minimal':
566 567 extended_info = False
567 568
568 569 elif details == 'basic':
569 570 extended_info = True
570 571
571 572 elif details == 'full':
572 573 extended_info = content = True
573 574
574 575 try:
575 576 # check if repo is not empty by any chance, skip quicker if it is.
576 577 _scm = repo.scm_instance()
577 578 if _scm.is_empty():
578 579 return None
579 580
580 581 node = ScmModel().get_node(
581 582 repo, commit_id, file_path, extended_info=extended_info,
582 583 content=content, max_file_bytes=max_file_bytes, cache=cache)
583 584 except NodeDoesNotExistError:
584 585 raise JSONRPCError('There is no file in repo: `{}` at path `{}` for commit: `{}`'.format(
585 586 repo.repo_name, file_path, commit_id))
586 587 except Exception:
587 588 log.exception("Exception occurred while trying to get repo %s file",
588 589 repo.repo_name)
589 590 raise JSONRPCError('failed to get repo: `{}` file at path {}'.format(
590 591 repo.repo_name, file_path))
591 592
592 593 return node
593 594
594 595
595 596 @jsonrpc_method()
596 597 def get_repo_fts_tree(request, apiuser, repoid, commit_id, root_path):
597 598 """
598 599 Returns a list of tree nodes for path at given revision. This api is built
599 600 strictly for usage in full text search building, and shouldn't be consumed
600 601
601 602 This command can only be run using an |authtoken| with admin rights,
602 603 or users with at least read rights to |repos|.
603 604
604 605 """
605 606
606 607 repo = get_repo_or_error(repoid)
607 608 if not has_superadmin_permission(apiuser):
608 609 _perms = ('repository.admin', 'repository.write', 'repository.read',)
609 610 validate_repo_permissions(apiuser, repoid, repo, _perms)
610 611
611 612 repo_id = repo.repo_id
612 613 cache_seconds = safe_int(rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
613 614 cache_on = cache_seconds > 0
614 615
615 616 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
616 617 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
617 618
618 619 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
619 620 condition=cache_on)
620 621 def compute_fts_tree(repo_id, commit_id, root_path, cache_ver):
621 622 return ScmModel().get_fts_data(repo_id, commit_id, root_path)
622 623
623 624 try:
624 625 # check if repo is not empty by any chance, skip quicker if it is.
625 626 _scm = repo.scm_instance()
626 627 if _scm.is_empty():
627 628 return []
628 629 except RepositoryError:
629 630 log.exception("Exception occurred while trying to get repo nodes")
630 631 raise JSONRPCError('failed to get repo: `%s` nodes' % repo.repo_name)
631 632
632 633 try:
633 634 # we need to resolve commit_id to a FULL sha for cache to work correctly.
634 635 # sending 'master' is a pointer that needs to be translated to current commit.
635 636 commit_id = _scm.get_commit(commit_id=commit_id).raw_id
636 637 log.debug(
637 638 'Computing FTS REPO TREE for repo_id %s commit_id `%s` '
638 639 'with caching: %s[TTL: %ss]' % (
639 640 repo_id, commit_id, cache_on, cache_seconds or 0))
640 641
641 642 tree_files = compute_fts_tree(repo_id, commit_id, root_path, 'v1')
642 643 return tree_files
643 644
644 645 except Exception:
645 646 log.exception("Exception occurred while trying to get repo nodes")
646 647 raise JSONRPCError('failed to get repo: `%s` nodes' % repo.repo_name)
647 648
648 649
649 650 @jsonrpc_method()
650 651 def get_repo_refs(request, apiuser, repoid):
651 652 """
652 653 Returns a dictionary of current references. It returns
653 654 bookmarks, branches, closed_branches, and tags for given repository
654 655
655 656 It's possible to specify ret_type to show only `files` or `dirs`.
656 657
657 658 This command can only be run using an |authtoken| with admin rights,
658 659 or users with at least read rights to |repos|.
659 660
660 661 :param apiuser: This is filled automatically from the |authtoken|.
661 662 :type apiuser: AuthUser
662 663 :param repoid: The repository name or repository ID.
663 664 :type repoid: str or int
664 665
665 666 Example output:
666 667
667 668 .. code-block:: bash
668 669
669 670 id : <id_given_in_input>
670 671 "result": {
671 672 "bookmarks": {
672 673 "dev": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
673 674 "master": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
674 675 },
675 676 "branches": {
676 677 "default": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
677 678 "stable": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
678 679 },
679 680 "branches_closed": {},
680 681 "tags": {
681 682 "tip": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
682 683 "v4.4.0": "1232313f9e6adac5ce5399c2a891dc1e72b79022",
683 684 "v4.4.1": "cbb9f1d329ae5768379cdec55a62ebdd546c4e27",
684 685 "v4.4.2": "24ffe44a27fcd1c5b6936144e176b9f6dd2f3a17",
685 686 }
686 687 }
687 688 error: null
688 689 """
689 690
690 691 repo = get_repo_or_error(repoid)
691 692 if not has_superadmin_permission(apiuser):
692 693 _perms = ('repository.admin', 'repository.write', 'repository.read',)
693 694 validate_repo_permissions(apiuser, repoid, repo, _perms)
694 695
695 696 try:
696 697 # check if repo is not empty by any chance, skip quicker if it is.
697 698 vcs_instance = repo.scm_instance()
698 699 refs = vcs_instance.refs()
699 700 return refs
700 701 except Exception:
701 702 log.exception("Exception occurred while trying to get repo refs")
702 703 raise JSONRPCError(
703 704 'failed to get repo: `%s` references' % repo.repo_name
704 705 )
705 706
706 707
707 708 @jsonrpc_method()
708 709 def create_repo(
709 710 request, apiuser, repo_name, repo_type,
710 711 owner=Optional(OAttr('apiuser')),
711 712 description=Optional(''),
712 713 private=Optional(False),
713 714 clone_uri=Optional(None),
714 715 push_uri=Optional(None),
715 716 landing_rev=Optional('rev:tip'),
716 717 enable_statistics=Optional(False),
717 718 enable_locking=Optional(False),
718 719 enable_downloads=Optional(False),
719 720 copy_permissions=Optional(False)):
720 721 """
721 722 Creates a repository.
722 723
723 724 * If the repository name contains "/", repository will be created inside
724 725 a repository group or nested repository groups
725 726
726 727 For example "foo/bar/repo1" will create |repo| called "repo1" inside
727 728 group "foo/bar". You have to have permissions to access and write to
728 729 the last repository group ("bar" in this example)
729 730
730 731 This command can only be run using an |authtoken| with at least
731 732 permissions to create repositories, or write permissions to
732 733 parent repository groups.
733 734
734 735 :param apiuser: This is filled automatically from the |authtoken|.
735 736 :type apiuser: AuthUser
736 737 :param repo_name: Set the repository name.
737 738 :type repo_name: str
738 739 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
739 740 :type repo_type: str
740 741 :param owner: user_id or username
741 742 :type owner: Optional(str)
742 743 :param description: Set the repository description.
743 744 :type description: Optional(str)
744 745 :param private: set repository as private
745 746 :type private: bool
746 747 :param clone_uri: set clone_uri
747 748 :type clone_uri: str
748 749 :param push_uri: set push_uri
749 750 :type push_uri: str
750 751 :param landing_rev: <rev_type>:<rev>
751 752 :type landing_rev: str
752 753 :param enable_locking:
753 754 :type enable_locking: bool
754 755 :param enable_downloads:
755 756 :type enable_downloads: bool
756 757 :param enable_statistics:
757 758 :type enable_statistics: bool
758 759 :param copy_permissions: Copy permission from group in which the
759 760 repository is being created.
760 761 :type copy_permissions: bool
761 762
762 763
763 764 Example output:
764 765
765 766 .. code-block:: bash
766 767
767 768 id : <id_given_in_input>
768 769 result: {
769 770 "msg": "Created new repository `<reponame>`",
770 771 "success": true,
771 772 "task": "<celery task id or None if done sync>"
772 773 }
773 774 error: null
774 775
775 776
776 777 Example error output:
777 778
778 779 .. code-block:: bash
779 780
780 781 id : <id_given_in_input>
781 782 result : null
782 783 error : {
783 784 'failed to create repository `<repo_name>`'
784 785 }
785 786
786 787 """
787 788
788 789 owner = validate_set_owner_permissions(apiuser, owner)
789 790
790 791 description = Optional.extract(description)
791 792 copy_permissions = Optional.extract(copy_permissions)
792 793 clone_uri = Optional.extract(clone_uri)
793 794 push_uri = Optional.extract(push_uri)
794 795 landing_commit_ref = Optional.extract(landing_rev)
795 796
796 797 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
797 798 if isinstance(private, Optional):
798 799 private = defs.get('repo_private') or Optional.extract(private)
799 800 if isinstance(repo_type, Optional):
800 801 repo_type = defs.get('repo_type')
801 802 if isinstance(enable_statistics, Optional):
802 803 enable_statistics = defs.get('repo_enable_statistics')
803 804 if isinstance(enable_locking, Optional):
804 805 enable_locking = defs.get('repo_enable_locking')
805 806 if isinstance(enable_downloads, Optional):
806 807 enable_downloads = defs.get('repo_enable_downloads')
807 808
808 809 schema = repo_schema.RepoSchema().bind(
809 810 repo_type_options=rhodecode.BACKENDS.keys(),
810 811 repo_type=repo_type,
811 812 # user caller
812 813 user=apiuser)
813 814
814 815 try:
815 816 schema_data = schema.deserialize(dict(
816 817 repo_name=repo_name,
817 818 repo_type=repo_type,
818 819 repo_owner=owner.username,
819 820 repo_description=description,
820 821 repo_landing_commit_ref=landing_commit_ref,
821 822 repo_clone_uri=clone_uri,
822 823 repo_push_uri=push_uri,
823 824 repo_private=private,
824 825 repo_copy_permissions=copy_permissions,
825 826 repo_enable_statistics=enable_statistics,
826 827 repo_enable_downloads=enable_downloads,
827 828 repo_enable_locking=enable_locking))
828 829 except validation_schema.Invalid as err:
829 830 raise JSONRPCValidationError(colander_exc=err)
830 831
831 832 try:
832 833 data = {
833 834 'owner': owner,
834 835 'repo_name': schema_data['repo_group']['repo_name_without_group'],
835 836 'repo_name_full': schema_data['repo_name'],
836 837 'repo_group': schema_data['repo_group']['repo_group_id'],
837 838 'repo_type': schema_data['repo_type'],
838 839 'repo_description': schema_data['repo_description'],
839 840 'repo_private': schema_data['repo_private'],
840 841 'clone_uri': schema_data['repo_clone_uri'],
841 842 'push_uri': schema_data['repo_push_uri'],
842 843 'repo_landing_rev': schema_data['repo_landing_commit_ref'],
843 844 'enable_statistics': schema_data['repo_enable_statistics'],
844 845 'enable_locking': schema_data['repo_enable_locking'],
845 846 'enable_downloads': schema_data['repo_enable_downloads'],
846 847 'repo_copy_permissions': schema_data['repo_copy_permissions'],
847 848 }
848 849
849 850 task = RepoModel().create(form_data=data, cur_user=owner.user_id)
850 851 task_id = get_task_id(task)
851 852 # no commit, it's done in RepoModel, or async via celery
852 853 return {
853 854 'msg': "Created new repository `%s`" % (schema_data['repo_name'],),
854 855 'success': True, # cannot return the repo data here since fork
855 856 # can be done async
856 857 'task': task_id
857 858 }
858 859 except Exception:
859 860 log.exception(
860 861 u"Exception while trying to create the repository %s",
861 862 schema_data['repo_name'])
862 863 raise JSONRPCError(
863 864 'failed to create repository `%s`' % (schema_data['repo_name'],))
864 865
865 866
866 867 @jsonrpc_method()
867 868 def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''),
868 869 description=Optional('')):
869 870 """
870 871 Adds an extra field to a repository.
871 872
872 873 This command can only be run using an |authtoken| with at least
873 874 write permissions to the |repo|.
874 875
875 876 :param apiuser: This is filled automatically from the |authtoken|.
876 877 :type apiuser: AuthUser
877 878 :param repoid: Set the repository name or repository id.
878 879 :type repoid: str or int
879 880 :param key: Create a unique field key for this repository.
880 881 :type key: str
881 882 :param label:
882 883 :type label: Optional(str)
883 884 :param description:
884 885 :type description: Optional(str)
885 886 """
886 887 repo = get_repo_or_error(repoid)
887 888 if not has_superadmin_permission(apiuser):
888 889 _perms = ('repository.admin',)
889 890 validate_repo_permissions(apiuser, repoid, repo, _perms)
890 891
891 892 label = Optional.extract(label) or key
892 893 description = Optional.extract(description)
893 894
894 895 field = RepositoryField.get_by_key_name(key, repo)
895 896 if field:
896 897 raise JSONRPCError('Field with key '
897 898 '`%s` exists for repo `%s`' % (key, repoid))
898 899
899 900 try:
900 901 RepoModel().add_repo_field(repo, key, field_label=label,
901 902 field_desc=description)
902 903 Session().commit()
903 904 return {
904 905 'msg': "Added new repository field `%s`" % (key,),
905 906 'success': True,
906 907 }
907 908 except Exception:
908 909 log.exception("Exception occurred while trying to add field to repo")
909 910 raise JSONRPCError(
910 911 'failed to create new field for repository `%s`' % (repoid,))
911 912
912 913
913 914 @jsonrpc_method()
914 915 def remove_field_from_repo(request, apiuser, repoid, key):
915 916 """
916 917 Removes an extra field from a repository.
917 918
918 919 This command can only be run using an |authtoken| with at least
919 920 write permissions to the |repo|.
920 921
921 922 :param apiuser: This is filled automatically from the |authtoken|.
922 923 :type apiuser: AuthUser
923 924 :param repoid: Set the repository name or repository ID.
924 925 :type repoid: str or int
925 926 :param key: Set the unique field key for this repository.
926 927 :type key: str
927 928 """
928 929
929 930 repo = get_repo_or_error(repoid)
930 931 if not has_superadmin_permission(apiuser):
931 932 _perms = ('repository.admin',)
932 933 validate_repo_permissions(apiuser, repoid, repo, _perms)
933 934
934 935 field = RepositoryField.get_by_key_name(key, repo)
935 936 if not field:
936 937 raise JSONRPCError('Field with key `%s` does not '
937 938 'exists for repo `%s`' % (key, repoid))
938 939
939 940 try:
940 941 RepoModel().delete_repo_field(repo, field_key=key)
941 942 Session().commit()
942 943 return {
943 944 'msg': "Deleted repository field `%s`" % (key,),
944 945 'success': True,
945 946 }
946 947 except Exception:
947 948 log.exception(
948 949 "Exception occurred while trying to delete field from repo")
949 950 raise JSONRPCError(
950 951 'failed to delete field for repository `%s`' % (repoid,))
951 952
952 953
953 954 @jsonrpc_method()
954 955 def update_repo(
955 956 request, apiuser, repoid, repo_name=Optional(None),
956 957 owner=Optional(OAttr('apiuser')), description=Optional(''),
957 958 private=Optional(False),
958 959 clone_uri=Optional(None), push_uri=Optional(None),
959 960 landing_rev=Optional('rev:tip'), fork_of=Optional(None),
960 961 enable_statistics=Optional(False),
961 962 enable_locking=Optional(False),
962 963 enable_downloads=Optional(False), fields=Optional('')):
963 964 """
964 965 Updates a repository with the given information.
965 966
966 967 This command can only be run using an |authtoken| with at least
967 968 admin permissions to the |repo|.
968 969
969 970 * If the repository name contains "/", repository will be updated
970 971 accordingly with a repository group or nested repository groups
971 972
972 973 For example repoid=repo-test name="foo/bar/repo-test" will update |repo|
973 974 called "repo-test" and place it inside group "foo/bar".
974 975 You have to have permissions to access and write to the last repository
975 976 group ("bar" in this example)
976 977
977 978 :param apiuser: This is filled automatically from the |authtoken|.
978 979 :type apiuser: AuthUser
979 980 :param repoid: repository name or repository ID.
980 981 :type repoid: str or int
981 982 :param repo_name: Update the |repo| name, including the
982 983 repository group it's in.
983 984 :type repo_name: str
984 985 :param owner: Set the |repo| owner.
985 986 :type owner: str
986 987 :param fork_of: Set the |repo| as fork of another |repo|.
987 988 :type fork_of: str
988 989 :param description: Update the |repo| description.
989 990 :type description: str
990 991 :param private: Set the |repo| as private. (True | False)
991 992 :type private: bool
992 993 :param clone_uri: Update the |repo| clone URI.
993 994 :type clone_uri: str
994 995 :param landing_rev: Set the |repo| landing revision. Default is ``rev:tip``.
995 996 :type landing_rev: str
996 997 :param enable_statistics: Enable statistics on the |repo|, (True | False).
997 998 :type enable_statistics: bool
998 999 :param enable_locking: Enable |repo| locking.
999 1000 :type enable_locking: bool
1000 1001 :param enable_downloads: Enable downloads from the |repo|, (True | False).
1001 1002 :type enable_downloads: bool
1002 1003 :param fields: Add extra fields to the |repo|. Use the following
1003 1004 example format: ``field_key=field_val,field_key2=fieldval2``.
1004 1005 Escape ', ' with \,
1005 1006 :type fields: str
1006 1007 """
1007 1008
1008 1009 repo = get_repo_or_error(repoid)
1009 1010
1010 1011 include_secrets = False
1011 1012 if not has_superadmin_permission(apiuser):
1012 1013 validate_repo_permissions(apiuser, repoid, repo, ('repository.admin',))
1013 1014 else:
1014 1015 include_secrets = True
1015 1016
1016 1017 updates = dict(
1017 1018 repo_name=repo_name
1018 1019 if not isinstance(repo_name, Optional) else repo.repo_name,
1019 1020
1020 1021 fork_id=fork_of
1021 1022 if not isinstance(fork_of, Optional) else repo.fork.repo_name if repo.fork else None,
1022 1023
1023 1024 user=owner
1024 1025 if not isinstance(owner, Optional) else repo.user.username,
1025 1026
1026 1027 repo_description=description
1027 1028 if not isinstance(description, Optional) else repo.description,
1028 1029
1029 1030 repo_private=private
1030 1031 if not isinstance(private, Optional) else repo.private,
1031 1032
1032 1033 clone_uri=clone_uri
1033 1034 if not isinstance(clone_uri, Optional) else repo.clone_uri,
1034 1035
1035 1036 push_uri=push_uri
1036 1037 if not isinstance(push_uri, Optional) else repo.push_uri,
1037 1038
1038 1039 repo_landing_rev=landing_rev
1039 1040 if not isinstance(landing_rev, Optional) else repo._landing_revision,
1040 1041
1041 1042 repo_enable_statistics=enable_statistics
1042 1043 if not isinstance(enable_statistics, Optional) else repo.enable_statistics,
1043 1044
1044 1045 repo_enable_locking=enable_locking
1045 1046 if not isinstance(enable_locking, Optional) else repo.enable_locking,
1046 1047
1047 1048 repo_enable_downloads=enable_downloads
1048 1049 if not isinstance(enable_downloads, Optional) else repo.enable_downloads)
1049 1050
1050 1051 ref_choices, _labels = ScmModel().get_repo_landing_revs(
1051 1052 request.translate, repo=repo)
1052 1053
1053 1054 old_values = repo.get_api_data()
1054 1055 repo_type = repo.repo_type
1055 1056 schema = repo_schema.RepoSchema().bind(
1056 1057 repo_type_options=rhodecode.BACKENDS.keys(),
1057 1058 repo_ref_options=ref_choices,
1058 1059 repo_type=repo_type,
1059 1060 # user caller
1060 1061 user=apiuser,
1061 1062 old_values=old_values)
1062 1063 try:
1063 1064 schema_data = schema.deserialize(dict(
1064 1065 # we save old value, users cannot change type
1065 1066 repo_type=repo_type,
1066 1067
1067 1068 repo_name=updates['repo_name'],
1068 1069 repo_owner=updates['user'],
1069 1070 repo_description=updates['repo_description'],
1070 1071 repo_clone_uri=updates['clone_uri'],
1071 1072 repo_push_uri=updates['push_uri'],
1072 1073 repo_fork_of=updates['fork_id'],
1073 1074 repo_private=updates['repo_private'],
1074 1075 repo_landing_commit_ref=updates['repo_landing_rev'],
1075 1076 repo_enable_statistics=updates['repo_enable_statistics'],
1076 1077 repo_enable_downloads=updates['repo_enable_downloads'],
1077 1078 repo_enable_locking=updates['repo_enable_locking']))
1078 1079 except validation_schema.Invalid as err:
1079 1080 raise JSONRPCValidationError(colander_exc=err)
1080 1081
1081 1082 # save validated data back into the updates dict
1082 1083 validated_updates = dict(
1083 1084 repo_name=schema_data['repo_group']['repo_name_without_group'],
1084 1085 repo_group=schema_data['repo_group']['repo_group_id'],
1085 1086
1086 1087 user=schema_data['repo_owner'],
1087 1088 repo_description=schema_data['repo_description'],
1088 1089 repo_private=schema_data['repo_private'],
1089 1090 clone_uri=schema_data['repo_clone_uri'],
1090 1091 push_uri=schema_data['repo_push_uri'],
1091 1092 repo_landing_rev=schema_data['repo_landing_commit_ref'],
1092 1093 repo_enable_statistics=schema_data['repo_enable_statistics'],
1093 1094 repo_enable_locking=schema_data['repo_enable_locking'],
1094 1095 repo_enable_downloads=schema_data['repo_enable_downloads'],
1095 1096 )
1096 1097
1097 1098 if schema_data['repo_fork_of']:
1098 1099 fork_repo = get_repo_or_error(schema_data['repo_fork_of'])
1099 1100 validated_updates['fork_id'] = fork_repo.repo_id
1100 1101
1101 1102 # extra fields
1102 1103 fields = parse_args(Optional.extract(fields), key_prefix='ex_')
1103 1104 if fields:
1104 1105 validated_updates.update(fields)
1105 1106
1106 1107 try:
1107 1108 RepoModel().update(repo, **validated_updates)
1108 1109 audit_logger.store_api(
1109 1110 'repo.edit', action_data={'old_data': old_values},
1110 1111 user=apiuser, repo=repo)
1111 1112 Session().commit()
1112 1113 return {
1113 1114 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
1114 1115 'repository': repo.get_api_data(include_secrets=include_secrets)
1115 1116 }
1116 1117 except Exception:
1117 1118 log.exception(
1118 1119 u"Exception while trying to update the repository %s",
1119 1120 repoid)
1120 1121 raise JSONRPCError('failed to update repo `%s`' % repoid)
1121 1122
1122 1123
1123 1124 @jsonrpc_method()
1124 1125 def fork_repo(request, apiuser, repoid, fork_name,
1125 1126 owner=Optional(OAttr('apiuser')),
1126 1127 description=Optional(''),
1127 1128 private=Optional(False),
1128 1129 clone_uri=Optional(None),
1129 1130 landing_rev=Optional('rev:tip'),
1130 1131 copy_permissions=Optional(False)):
1131 1132 """
1132 1133 Creates a fork of the specified |repo|.
1133 1134
1134 1135 * If the fork_name contains "/", fork will be created inside
1135 1136 a repository group or nested repository groups
1136 1137
1137 1138 For example "foo/bar/fork-repo" will create fork called "fork-repo"
1138 1139 inside group "foo/bar". You have to have permissions to access and
1139 1140 write to the last repository group ("bar" in this example)
1140 1141
1141 1142 This command can only be run using an |authtoken| with minimum
1142 1143 read permissions of the forked repo, create fork permissions for an user.
1143 1144
1144 1145 :param apiuser: This is filled automatically from the |authtoken|.
1145 1146 :type apiuser: AuthUser
1146 1147 :param repoid: Set repository name or repository ID.
1147 1148 :type repoid: str or int
1148 1149 :param fork_name: Set the fork name, including it's repository group membership.
1149 1150 :type fork_name: str
1150 1151 :param owner: Set the fork owner.
1151 1152 :type owner: str
1152 1153 :param description: Set the fork description.
1153 1154 :type description: str
1154 1155 :param copy_permissions: Copy permissions from parent |repo|. The
1155 1156 default is False.
1156 1157 :type copy_permissions: bool
1157 1158 :param private: Make the fork private. The default is False.
1158 1159 :type private: bool
1159 1160 :param landing_rev: Set the landing revision. The default is tip.
1160 1161
1161 1162 Example output:
1162 1163
1163 1164 .. code-block:: bash
1164 1165
1165 1166 id : <id_for_response>
1166 1167 api_key : "<api_key>"
1167 1168 args: {
1168 1169 "repoid" : "<reponame or repo_id>",
1169 1170 "fork_name": "<forkname>",
1170 1171 "owner": "<username or user_id = Optional(=apiuser)>",
1171 1172 "description": "<description>",
1172 1173 "copy_permissions": "<bool>",
1173 1174 "private": "<bool>",
1174 1175 "landing_rev": "<landing_rev>"
1175 1176 }
1176 1177
1177 1178 Example error output:
1178 1179
1179 1180 .. code-block:: bash
1180 1181
1181 1182 id : <id_given_in_input>
1182 1183 result: {
1183 1184 "msg": "Created fork of `<reponame>` as `<forkname>`",
1184 1185 "success": true,
1185 1186 "task": "<celery task id or None if done sync>"
1186 1187 }
1187 1188 error: null
1188 1189
1189 1190 """
1190 1191
1191 1192 repo = get_repo_or_error(repoid)
1192 1193 repo_name = repo.repo_name
1193 1194
1194 1195 if not has_superadmin_permission(apiuser):
1195 1196 # check if we have at least read permission for
1196 1197 # this repo that we fork !
1197 1198 _perms = (
1198 1199 'repository.admin', 'repository.write', 'repository.read')
1199 1200 validate_repo_permissions(apiuser, repoid, repo, _perms)
1200 1201
1201 1202 # check if the regular user has at least fork permissions as well
1202 1203 if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser):
1203 1204 raise JSONRPCForbidden()
1204 1205
1205 1206 # check if user can set owner parameter
1206 1207 owner = validate_set_owner_permissions(apiuser, owner)
1207 1208
1208 1209 description = Optional.extract(description)
1209 1210 copy_permissions = Optional.extract(copy_permissions)
1210 1211 clone_uri = Optional.extract(clone_uri)
1211 1212 landing_commit_ref = Optional.extract(landing_rev)
1212 1213 private = Optional.extract(private)
1213 1214
1214 1215 schema = repo_schema.RepoSchema().bind(
1215 1216 repo_type_options=rhodecode.BACKENDS.keys(),
1216 1217 repo_type=repo.repo_type,
1217 1218 # user caller
1218 1219 user=apiuser)
1219 1220
1220 1221 try:
1221 1222 schema_data = schema.deserialize(dict(
1222 1223 repo_name=fork_name,
1223 1224 repo_type=repo.repo_type,
1224 1225 repo_owner=owner.username,
1225 1226 repo_description=description,
1226 1227 repo_landing_commit_ref=landing_commit_ref,
1227 1228 repo_clone_uri=clone_uri,
1228 1229 repo_private=private,
1229 1230 repo_copy_permissions=copy_permissions))
1230 1231 except validation_schema.Invalid as err:
1231 1232 raise JSONRPCValidationError(colander_exc=err)
1232 1233
1233 1234 try:
1234 1235 data = {
1235 1236 'fork_parent_id': repo.repo_id,
1236 1237
1237 1238 'repo_name': schema_data['repo_group']['repo_name_without_group'],
1238 1239 'repo_name_full': schema_data['repo_name'],
1239 1240 'repo_group': schema_data['repo_group']['repo_group_id'],
1240 1241 'repo_type': schema_data['repo_type'],
1241 1242 'description': schema_data['repo_description'],
1242 1243 'private': schema_data['repo_private'],
1243 1244 'copy_permissions': schema_data['repo_copy_permissions'],
1244 1245 'landing_rev': schema_data['repo_landing_commit_ref'],
1245 1246 }
1246 1247
1247 1248 task = RepoModel().create_fork(data, cur_user=owner.user_id)
1248 1249 # no commit, it's done in RepoModel, or async via celery
1249 1250 task_id = get_task_id(task)
1250 1251
1251 1252 return {
1252 1253 'msg': 'Created fork of `%s` as `%s`' % (
1253 1254 repo.repo_name, schema_data['repo_name']),
1254 1255 'success': True, # cannot return the repo data here since fork
1255 1256 # can be done async
1256 1257 'task': task_id
1257 1258 }
1258 1259 except Exception:
1259 1260 log.exception(
1260 1261 u"Exception while trying to create fork %s",
1261 1262 schema_data['repo_name'])
1262 1263 raise JSONRPCError(
1263 1264 'failed to fork repository `%s` as `%s`' % (
1264 1265 repo_name, schema_data['repo_name']))
1265 1266
1266 1267
1267 1268 @jsonrpc_method()
1268 1269 def delete_repo(request, apiuser, repoid, forks=Optional('')):
1269 1270 """
1270 1271 Deletes a repository.
1271 1272
1272 1273 * When the `forks` parameter is set it's possible to detach or delete
1273 1274 forks of deleted repository.
1274 1275
1275 1276 This command can only be run using an |authtoken| with admin
1276 1277 permissions on the |repo|.
1277 1278
1278 1279 :param apiuser: This is filled automatically from the |authtoken|.
1279 1280 :type apiuser: AuthUser
1280 1281 :param repoid: Set the repository name or repository ID.
1281 1282 :type repoid: str or int
1282 1283 :param forks: Set to `detach` or `delete` forks from the |repo|.
1283 1284 :type forks: Optional(str)
1284 1285
1285 1286 Example error output:
1286 1287
1287 1288 .. code-block:: bash
1288 1289
1289 1290 id : <id_given_in_input>
1290 1291 result: {
1291 1292 "msg": "Deleted repository `<reponame>`",
1292 1293 "success": true
1293 1294 }
1294 1295 error: null
1295 1296 """
1296 1297
1297 1298 repo = get_repo_or_error(repoid)
1298 1299 repo_name = repo.repo_name
1299 1300 if not has_superadmin_permission(apiuser):
1300 1301 _perms = ('repository.admin',)
1301 1302 validate_repo_permissions(apiuser, repoid, repo, _perms)
1302 1303
1303 1304 try:
1304 1305 handle_forks = Optional.extract(forks)
1305 1306 _forks_msg = ''
1306 1307 _forks = [f for f in repo.forks]
1307 1308 if handle_forks == 'detach':
1308 1309 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1309 1310 elif handle_forks == 'delete':
1310 1311 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1311 1312 elif _forks:
1312 1313 raise JSONRPCError(
1313 1314 'Cannot delete `%s` it still contains attached forks' %
1314 1315 (repo.repo_name,)
1315 1316 )
1316 1317 old_data = repo.get_api_data()
1317 1318 RepoModel().delete(repo, forks=forks)
1318 1319
1319 1320 repo = audit_logger.RepoWrap(repo_id=None,
1320 1321 repo_name=repo.repo_name)
1321 1322
1322 1323 audit_logger.store_api(
1323 1324 'repo.delete', action_data={'old_data': old_data},
1324 1325 user=apiuser, repo=repo)
1325 1326
1326 1327 ScmModel().mark_for_invalidation(repo_name, delete=True)
1327 1328 Session().commit()
1328 1329 return {
1329 1330 'msg': 'Deleted repository `%s`%s' % (repo_name, _forks_msg),
1330 1331 'success': True
1331 1332 }
1332 1333 except Exception:
1333 1334 log.exception("Exception occurred while trying to delete repo")
1334 1335 raise JSONRPCError(
1335 1336 'failed to delete repository `%s`' % (repo_name,)
1336 1337 )
1337 1338
1338 1339
1339 1340 #TODO: marcink, change name ?
1340 1341 @jsonrpc_method()
1341 1342 def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)):
1342 1343 """
1343 1344 Invalidates the cache for the specified repository.
1344 1345
1345 1346 This command can only be run using an |authtoken| with admin rights to
1346 1347 the specified repository.
1347 1348
1348 1349 This command takes the following options:
1349 1350
1350 1351 :param apiuser: This is filled automatically from |authtoken|.
1351 1352 :type apiuser: AuthUser
1352 1353 :param repoid: Sets the repository name or repository ID.
1353 1354 :type repoid: str or int
1354 1355 :param delete_keys: This deletes the invalidated keys instead of
1355 1356 just flagging them.
1356 1357 :type delete_keys: Optional(``True`` | ``False``)
1357 1358
1358 1359 Example output:
1359 1360
1360 1361 .. code-block:: bash
1361 1362
1362 1363 id : <id_given_in_input>
1363 1364 result : {
1364 1365 'msg': Cache for repository `<repository name>` was invalidated,
1365 1366 'repository': <repository name>
1366 1367 }
1367 1368 error : null
1368 1369
1369 1370 Example error output:
1370 1371
1371 1372 .. code-block:: bash
1372 1373
1373 1374 id : <id_given_in_input>
1374 1375 result : null
1375 1376 error : {
1376 1377 'Error occurred during cache invalidation action'
1377 1378 }
1378 1379
1379 1380 """
1380 1381
1381 1382 repo = get_repo_or_error(repoid)
1382 1383 if not has_superadmin_permission(apiuser):
1383 1384 _perms = ('repository.admin', 'repository.write',)
1384 1385 validate_repo_permissions(apiuser, repoid, repo, _perms)
1385 1386
1386 1387 delete = Optional.extract(delete_keys)
1387 1388 try:
1388 1389 ScmModel().mark_for_invalidation(repo.repo_name, delete=delete)
1389 1390 return {
1390 1391 'msg': 'Cache for repository `%s` was invalidated' % (repoid,),
1391 1392 'repository': repo.repo_name
1392 1393 }
1393 1394 except Exception:
1394 1395 log.exception(
1395 1396 "Exception occurred while trying to invalidate repo cache")
1396 1397 raise JSONRPCError(
1397 1398 'Error occurred during cache invalidation action'
1398 1399 )
1399 1400
1400 1401
1401 1402 #TODO: marcink, change name ?
1402 1403 @jsonrpc_method()
1403 1404 def lock(request, apiuser, repoid, locked=Optional(None),
1404 1405 userid=Optional(OAttr('apiuser'))):
1405 1406 """
1406 1407 Sets the lock state of the specified |repo| by the given user.
1407 1408 From more information, see :ref:`repo-locking`.
1408 1409
1409 1410 * If the ``userid`` option is not set, the repository is locked to the
1410 1411 user who called the method.
1411 1412 * If the ``locked`` parameter is not set, the current lock state of the
1412 1413 repository is displayed.
1413 1414
1414 1415 This command can only be run using an |authtoken| with admin rights to
1415 1416 the specified repository.
1416 1417
1417 1418 This command takes the following options:
1418 1419
1419 1420 :param apiuser: This is filled automatically from the |authtoken|.
1420 1421 :type apiuser: AuthUser
1421 1422 :param repoid: Sets the repository name or repository ID.
1422 1423 :type repoid: str or int
1423 1424 :param locked: Sets the lock state.
1424 1425 :type locked: Optional(``True`` | ``False``)
1425 1426 :param userid: Set the repository lock to this user.
1426 1427 :type userid: Optional(str or int)
1427 1428
1428 1429 Example error output:
1429 1430
1430 1431 .. code-block:: bash
1431 1432
1432 1433 id : <id_given_in_input>
1433 1434 result : {
1434 1435 'repo': '<reponame>',
1435 1436 'locked': <bool: lock state>,
1436 1437 'locked_since': <int: lock timestamp>,
1437 1438 'locked_by': <username of person who made the lock>,
1438 1439 'lock_reason': <str: reason for locking>,
1439 1440 'lock_state_changed': <bool: True if lock state has been changed in this request>,
1440 1441 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
1441 1442 or
1442 1443 'msg': 'Repo `<repository name>` not locked.'
1443 1444 or
1444 1445 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
1445 1446 }
1446 1447 error : null
1447 1448
1448 1449 Example error output:
1449 1450
1450 1451 .. code-block:: bash
1451 1452
1452 1453 id : <id_given_in_input>
1453 1454 result : null
1454 1455 error : {
1455 1456 'Error occurred locking repository `<reponame>`'
1456 1457 }
1457 1458 """
1458 1459
1459 1460 repo = get_repo_or_error(repoid)
1460 1461 if not has_superadmin_permission(apiuser):
1461 1462 # check if we have at least write permission for this repo !
1462 1463 _perms = ('repository.admin', 'repository.write',)
1463 1464 validate_repo_permissions(apiuser, repoid, repo, _perms)
1464 1465
1465 1466 # make sure normal user does not pass someone else userid,
1466 1467 # he is not allowed to do that
1467 1468 if not isinstance(userid, Optional) and userid != apiuser.user_id:
1468 1469 raise JSONRPCError('userid is not the same as your user')
1469 1470
1470 1471 if isinstance(userid, Optional):
1471 1472 userid = apiuser.user_id
1472 1473
1473 1474 user = get_user_or_error(userid)
1474 1475
1475 1476 if isinstance(locked, Optional):
1476 1477 lockobj = repo.locked
1477 1478
1478 1479 if lockobj[0] is None:
1479 1480 _d = {
1480 1481 'repo': repo.repo_name,
1481 1482 'locked': False,
1482 1483 'locked_since': None,
1483 1484 'locked_by': None,
1484 1485 'lock_reason': None,
1485 1486 'lock_state_changed': False,
1486 1487 'msg': 'Repo `%s` not locked.' % repo.repo_name
1487 1488 }
1488 1489 return _d
1489 1490 else:
1490 1491 _user_id, _time, _reason = lockobj
1491 1492 lock_user = get_user_or_error(userid)
1492 1493 _d = {
1493 1494 'repo': repo.repo_name,
1494 1495 'locked': True,
1495 1496 'locked_since': _time,
1496 1497 'locked_by': lock_user.username,
1497 1498 'lock_reason': _reason,
1498 1499 'lock_state_changed': False,
1499 1500 'msg': ('Repo `%s` locked by `%s` on `%s`.'
1500 1501 % (repo.repo_name, lock_user.username,
1501 1502 json.dumps(time_to_datetime(_time))))
1502 1503 }
1503 1504 return _d
1504 1505
1505 1506 # force locked state through a flag
1506 1507 else:
1507 1508 locked = str2bool(locked)
1508 1509 lock_reason = Repository.LOCK_API
1509 1510 try:
1510 1511 if locked:
1511 1512 lock_time = time.time()
1512 1513 Repository.lock(repo, user.user_id, lock_time, lock_reason)
1513 1514 else:
1514 1515 lock_time = None
1515 1516 Repository.unlock(repo)
1516 1517 _d = {
1517 1518 'repo': repo.repo_name,
1518 1519 'locked': locked,
1519 1520 'locked_since': lock_time,
1520 1521 'locked_by': user.username,
1521 1522 'lock_reason': lock_reason,
1522 1523 'lock_state_changed': True,
1523 1524 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
1524 1525 % (user.username, repo.repo_name, locked))
1525 1526 }
1526 1527 return _d
1527 1528 except Exception:
1528 1529 log.exception(
1529 1530 "Exception occurred while trying to lock repository")
1530 1531 raise JSONRPCError(
1531 1532 'Error occurred locking repository `%s`' % repo.repo_name
1532 1533 )
1533 1534
1534 1535
1535 1536 @jsonrpc_method()
1536 1537 def comment_commit(
1537 1538 request, apiuser, repoid, commit_id, message, status=Optional(None),
1538 1539 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
1539 1540 resolves_comment_id=Optional(None),
1540 1541 userid=Optional(OAttr('apiuser'))):
1541 1542 """
1542 1543 Set a commit comment, and optionally change the status of the commit.
1543 1544
1544 1545 :param apiuser: This is filled automatically from the |authtoken|.
1545 1546 :type apiuser: AuthUser
1546 1547 :param repoid: Set the repository name or repository ID.
1547 1548 :type repoid: str or int
1548 1549 :param commit_id: Specify the commit_id for which to set a comment.
1549 1550 :type commit_id: str
1550 1551 :param message: The comment text.
1551 1552 :type message: str
1552 1553 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
1553 1554 'approved', 'rejected', 'under_review'
1554 1555 :type status: str
1555 1556 :param comment_type: Comment type, one of: 'note', 'todo'
1556 1557 :type comment_type: Optional(str), default: 'note'
1557 1558 :param userid: Set the user name of the comment creator.
1558 1559 :type userid: Optional(str or int)
1559 1560
1560 1561 Example error output:
1561 1562
1562 1563 .. code-block:: bash
1563 1564
1564 1565 {
1565 1566 "id" : <id_given_in_input>,
1566 1567 "result" : {
1567 1568 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
1568 1569 "status_change": null or <status>,
1569 1570 "success": true
1570 1571 },
1571 1572 "error" : null
1572 1573 }
1573 1574
1574 1575 """
1575 1576 repo = get_repo_or_error(repoid)
1576 1577 if not has_superadmin_permission(apiuser):
1577 1578 _perms = ('repository.read', 'repository.write', 'repository.admin')
1578 1579 validate_repo_permissions(apiuser, repoid, repo, _perms)
1579 1580
1580 1581 try:
1581 1582 commit_id = repo.scm_instance().get_commit(commit_id=commit_id).raw_id
1582 1583 except Exception as e:
1583 1584 log.exception('Failed to fetch commit')
1584 1585 raise JSONRPCError(safe_str(e))
1585 1586
1586 1587 if isinstance(userid, Optional):
1587 1588 userid = apiuser.user_id
1588 1589
1589 1590 user = get_user_or_error(userid)
1590 1591 status = Optional.extract(status)
1591 1592 comment_type = Optional.extract(comment_type)
1592 1593 resolves_comment_id = Optional.extract(resolves_comment_id)
1593 1594
1594 1595 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1595 1596 if status and status not in allowed_statuses:
1596 1597 raise JSONRPCError('Bad status, must be on '
1597 1598 'of %s got %s' % (allowed_statuses, status,))
1598 1599
1599 1600 if resolves_comment_id:
1600 1601 comment = ChangesetComment.get(resolves_comment_id)
1601 1602 if not comment:
1602 1603 raise JSONRPCError(
1603 1604 'Invalid resolves_comment_id `%s` for this commit.'
1604 1605 % resolves_comment_id)
1605 1606 if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO:
1606 1607 raise JSONRPCError(
1607 1608 'Comment `%s` is wrong type for setting status to resolved.'
1608 1609 % resolves_comment_id)
1609 1610
1610 1611 try:
1611 1612 rc_config = SettingsModel().get_all_settings()
1612 1613 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1613 1614 status_change_label = ChangesetStatus.get_status_lbl(status)
1614 1615 comment = CommentsModel().create(
1615 1616 message, repo, user, commit_id=commit_id,
1616 1617 status_change=status_change_label,
1617 1618 status_change_type=status,
1618 1619 renderer=renderer,
1619 1620 comment_type=comment_type,
1620 1621 resolves_comment_id=resolves_comment_id,
1621 1622 auth_user=apiuser
1622 1623 )
1623 1624 if status:
1624 1625 # also do a status change
1625 1626 try:
1626 1627 ChangesetStatusModel().set_status(
1627 1628 repo, status, user, comment, revision=commit_id,
1628 1629 dont_allow_on_closed_pull_request=True
1629 1630 )
1630 1631 except StatusChangeOnClosedPullRequestError:
1631 1632 log.exception(
1632 1633 "Exception occurred while trying to change repo commit status")
1633 1634 msg = ('Changing status on a changeset associated with '
1634 1635 'a closed pull request is not allowed')
1635 1636 raise JSONRPCError(msg)
1636 1637
1637 1638 Session().commit()
1638 1639 return {
1639 1640 'msg': (
1640 1641 'Commented on commit `%s` for repository `%s`' % (
1641 1642 comment.revision, repo.repo_name)),
1642 1643 'status_change': status,
1643 1644 'success': True,
1644 1645 }
1645 1646 except JSONRPCError:
1646 1647 # catch any inside errors, and re-raise them to prevent from
1647 1648 # below global catch to silence them
1648 1649 raise
1649 1650 except Exception:
1650 1651 log.exception("Exception occurred while trying to comment on commit")
1651 1652 raise JSONRPCError(
1652 1653 'failed to set comment on repository `%s`' % (repo.repo_name,)
1653 1654 )
1654 1655
1655 1656
1656 1657 @jsonrpc_method()
1657 1658 def get_repo_comments(request, apiuser, repoid,
1658 1659 commit_id=Optional(None), comment_type=Optional(None),
1659 1660 userid=Optional(None)):
1660 1661 """
1661 1662 Get all comments for a repository
1662 1663
1663 1664 :param apiuser: This is filled automatically from the |authtoken|.
1664 1665 :type apiuser: AuthUser
1665 1666 :param repoid: Set the repository name or repository ID.
1666 1667 :type repoid: str or int
1667 1668 :param commit_id: Optionally filter the comments by the commit_id
1668 1669 :type commit_id: Optional(str), default: None
1669 1670 :param comment_type: Optionally filter the comments by the comment_type
1670 1671 one of: 'note', 'todo'
1671 1672 :type comment_type: Optional(str), default: None
1672 1673 :param userid: Optionally filter the comments by the author of comment
1673 1674 :type userid: Optional(str or int), Default: None
1674 1675
1675 1676 Example error output:
1676 1677
1677 1678 .. code-block:: bash
1678 1679
1679 1680 {
1680 1681 "id" : <id_given_in_input>,
1681 1682 "result" : [
1682 1683 {
1683 1684 "comment_author": <USER_DETAILS>,
1684 1685 "comment_created_on": "2017-02-01T14:38:16.309",
1685 1686 "comment_f_path": "file.txt",
1686 1687 "comment_id": 282,
1687 1688 "comment_lineno": "n1",
1688 1689 "comment_resolved_by": null,
1689 1690 "comment_status": [],
1690 1691 "comment_text": "This file needs a header",
1691 1692 "comment_type": "todo"
1692 1693 }
1693 1694 ],
1694 1695 "error" : null
1695 1696 }
1696 1697
1697 1698 """
1698 1699 repo = get_repo_or_error(repoid)
1699 1700 if not has_superadmin_permission(apiuser):
1700 1701 _perms = ('repository.read', 'repository.write', 'repository.admin')
1701 1702 validate_repo_permissions(apiuser, repoid, repo, _perms)
1702 1703
1703 1704 commit_id = Optional.extract(commit_id)
1704 1705
1705 1706 userid = Optional.extract(userid)
1706 1707 if userid:
1707 1708 user = get_user_or_error(userid)
1708 1709 else:
1709 1710 user = None
1710 1711
1711 1712 comment_type = Optional.extract(comment_type)
1712 1713 if comment_type and comment_type not in ChangesetComment.COMMENT_TYPES:
1713 1714 raise JSONRPCError(
1714 1715 'comment_type must be one of `{}` got {}'.format(
1715 1716 ChangesetComment.COMMENT_TYPES, comment_type)
1716 1717 )
1717 1718
1718 1719 comments = CommentsModel().get_repository_comments(
1719 1720 repo=repo, comment_type=comment_type, user=user, commit_id=commit_id)
1720 1721 return comments
1721 1722
1722 1723
1723 1724 @jsonrpc_method()
1724 1725 def grant_user_permission(request, apiuser, repoid, userid, perm):
1725 1726 """
1726 1727 Grant permissions for the specified user on the given repository,
1727 1728 or update existing permissions if found.
1728 1729
1729 1730 This command can only be run using an |authtoken| with admin
1730 1731 permissions on the |repo|.
1731 1732
1732 1733 :param apiuser: This is filled automatically from the |authtoken|.
1733 1734 :type apiuser: AuthUser
1734 1735 :param repoid: Set the repository name or repository ID.
1735 1736 :type repoid: str or int
1736 1737 :param userid: Set the user name.
1737 1738 :type userid: str
1738 1739 :param perm: Set the user permissions, using the following format
1739 1740 ``(repository.(none|read|write|admin))``
1740 1741 :type perm: str
1741 1742
1742 1743 Example output:
1743 1744
1744 1745 .. code-block:: bash
1745 1746
1746 1747 id : <id_given_in_input>
1747 1748 result: {
1748 1749 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1749 1750 "success": true
1750 1751 }
1751 1752 error: null
1752 1753 """
1753 1754
1754 1755 repo = get_repo_or_error(repoid)
1755 1756 user = get_user_or_error(userid)
1756 1757 perm = get_perm_or_error(perm)
1757 1758 if not has_superadmin_permission(apiuser):
1758 1759 _perms = ('repository.admin',)
1759 1760 validate_repo_permissions(apiuser, repoid, repo, _perms)
1760 1761
1761 1762 perm_additions = [[user.user_id, perm.permission_name, "user"]]
1762 1763 try:
1763 1764 changes = RepoModel().update_permissions(
1764 1765 repo=repo, perm_additions=perm_additions, cur_user=apiuser)
1765 1766
1766 1767 action_data = {
1767 1768 'added': changes['added'],
1768 1769 'updated': changes['updated'],
1769 1770 'deleted': changes['deleted'],
1770 1771 }
1771 1772 audit_logger.store_api(
1772 1773 'repo.edit.permissions', action_data=action_data, user=apiuser, repo=repo)
1773 1774
1774 1775 Session().commit()
1775 1776 return {
1776 1777 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1777 1778 perm.permission_name, user.username, repo.repo_name
1778 1779 ),
1779 1780 'success': True
1780 1781 }
1781 1782 except Exception:
1782 1783 log.exception("Exception occurred while trying edit permissions for repo")
1783 1784 raise JSONRPCError(
1784 1785 'failed to edit permission for user: `%s` in repo: `%s`' % (
1785 1786 userid, repoid
1786 1787 )
1787 1788 )
1788 1789
1789 1790
1790 1791 @jsonrpc_method()
1791 1792 def revoke_user_permission(request, apiuser, repoid, userid):
1792 1793 """
1793 1794 Revoke permission for a user on the specified repository.
1794 1795
1795 1796 This command can only be run using an |authtoken| with admin
1796 1797 permissions on the |repo|.
1797 1798
1798 1799 :param apiuser: This is filled automatically from the |authtoken|.
1799 1800 :type apiuser: AuthUser
1800 1801 :param repoid: Set the repository name or repository ID.
1801 1802 :type repoid: str or int
1802 1803 :param userid: Set the user name of revoked user.
1803 1804 :type userid: str or int
1804 1805
1805 1806 Example error output:
1806 1807
1807 1808 .. code-block:: bash
1808 1809
1809 1810 id : <id_given_in_input>
1810 1811 result: {
1811 1812 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1812 1813 "success": true
1813 1814 }
1814 1815 error: null
1815 1816 """
1816 1817
1817 1818 repo = get_repo_or_error(repoid)
1818 1819 user = get_user_or_error(userid)
1819 1820 if not has_superadmin_permission(apiuser):
1820 1821 _perms = ('repository.admin',)
1821 1822 validate_repo_permissions(apiuser, repoid, repo, _perms)
1822 1823
1823 1824 perm_deletions = [[user.user_id, None, "user"]]
1824 1825 try:
1825 1826 changes = RepoModel().update_permissions(
1826 1827 repo=repo, perm_deletions=perm_deletions, cur_user=user)
1827 1828
1828 1829 action_data = {
1829 1830 'added': changes['added'],
1830 1831 'updated': changes['updated'],
1831 1832 'deleted': changes['deleted'],
1832 1833 }
1833 1834 audit_logger.store_api(
1834 1835 'repo.edit.permissions', action_data=action_data, user=apiuser, repo=repo)
1835 1836
1836 1837 Session().commit()
1837 1838 return {
1838 1839 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1839 1840 user.username, repo.repo_name
1840 1841 ),
1841 1842 'success': True
1842 1843 }
1843 1844 except Exception:
1844 1845 log.exception("Exception occurred while trying revoke permissions to repo")
1845 1846 raise JSONRPCError(
1846 1847 'failed to edit permission for user: `%s` in repo: `%s`' % (
1847 1848 userid, repoid
1848 1849 )
1849 1850 )
1850 1851
1851 1852
1852 1853 @jsonrpc_method()
1853 1854 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm):
1854 1855 """
1855 1856 Grant permission for a user group on the specified repository,
1856 1857 or update existing permissions.
1857 1858
1858 1859 This command can only be run using an |authtoken| with admin
1859 1860 permissions on the |repo|.
1860 1861
1861 1862 :param apiuser: This is filled automatically from the |authtoken|.
1862 1863 :type apiuser: AuthUser
1863 1864 :param repoid: Set the repository name or repository ID.
1864 1865 :type repoid: str or int
1865 1866 :param usergroupid: Specify the ID of the user group.
1866 1867 :type usergroupid: str or int
1867 1868 :param perm: Set the user group permissions using the following
1868 1869 format: (repository.(none|read|write|admin))
1869 1870 :type perm: str
1870 1871
1871 1872 Example output:
1872 1873
1873 1874 .. code-block:: bash
1874 1875
1875 1876 id : <id_given_in_input>
1876 1877 result : {
1877 1878 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1878 1879 "success": true
1879 1880
1880 1881 }
1881 1882 error : null
1882 1883
1883 1884 Example error output:
1884 1885
1885 1886 .. code-block:: bash
1886 1887
1887 1888 id : <id_given_in_input>
1888 1889 result : null
1889 1890 error : {
1890 1891 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1891 1892 }
1892 1893
1893 1894 """
1894 1895
1895 1896 repo = get_repo_or_error(repoid)
1896 1897 perm = get_perm_or_error(perm)
1897 1898 if not has_superadmin_permission(apiuser):
1898 1899 _perms = ('repository.admin',)
1899 1900 validate_repo_permissions(apiuser, repoid, repo, _perms)
1900 1901
1901 1902 user_group = get_user_group_or_error(usergroupid)
1902 1903 if not has_superadmin_permission(apiuser):
1903 1904 # check if we have at least read permission for this user group !
1904 1905 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1905 1906 if not HasUserGroupPermissionAnyApi(*_perms)(
1906 1907 user=apiuser, user_group_name=user_group.users_group_name):
1907 1908 raise JSONRPCError(
1908 1909 'user group `%s` does not exist' % (usergroupid,))
1909 1910
1910 1911 perm_additions = [[user_group.users_group_id, perm.permission_name, "user_group"]]
1911 1912 try:
1912 1913 changes = RepoModel().update_permissions(
1913 1914 repo=repo, perm_additions=perm_additions, cur_user=apiuser)
1914 1915 action_data = {
1915 1916 'added': changes['added'],
1916 1917 'updated': changes['updated'],
1917 1918 'deleted': changes['deleted'],
1918 1919 }
1919 1920 audit_logger.store_api(
1920 1921 'repo.edit.permissions', action_data=action_data, user=apiuser, repo=repo)
1921 1922
1922 1923 Session().commit()
1923 1924 return {
1924 1925 'msg': 'Granted perm: `%s` for user group: `%s` in '
1925 1926 'repo: `%s`' % (
1926 1927 perm.permission_name, user_group.users_group_name,
1927 1928 repo.repo_name
1928 1929 ),
1929 1930 'success': True
1930 1931 }
1931 1932 except Exception:
1932 1933 log.exception(
1933 1934 "Exception occurred while trying change permission on repo")
1934 1935 raise JSONRPCError(
1935 1936 'failed to edit permission for user group: `%s` in '
1936 1937 'repo: `%s`' % (
1937 1938 usergroupid, repo.repo_name
1938 1939 )
1939 1940 )
1940 1941
1941 1942
1942 1943 @jsonrpc_method()
1943 1944 def revoke_user_group_permission(request, apiuser, repoid, usergroupid):
1944 1945 """
1945 1946 Revoke the permissions of a user group on a given repository.
1946 1947
1947 1948 This command can only be run using an |authtoken| with admin
1948 1949 permissions on the |repo|.
1949 1950
1950 1951 :param apiuser: This is filled automatically from the |authtoken|.
1951 1952 :type apiuser: AuthUser
1952 1953 :param repoid: Set the repository name or repository ID.
1953 1954 :type repoid: str or int
1954 1955 :param usergroupid: Specify the user group ID.
1955 1956 :type usergroupid: str or int
1956 1957
1957 1958 Example output:
1958 1959
1959 1960 .. code-block:: bash
1960 1961
1961 1962 id : <id_given_in_input>
1962 1963 result: {
1963 1964 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1964 1965 "success": true
1965 1966 }
1966 1967 error: null
1967 1968 """
1968 1969
1969 1970 repo = get_repo_or_error(repoid)
1970 1971 if not has_superadmin_permission(apiuser):
1971 1972 _perms = ('repository.admin',)
1972 1973 validate_repo_permissions(apiuser, repoid, repo, _perms)
1973 1974
1974 1975 user_group = get_user_group_or_error(usergroupid)
1975 1976 if not has_superadmin_permission(apiuser):
1976 1977 # check if we have at least read permission for this user group !
1977 1978 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1978 1979 if not HasUserGroupPermissionAnyApi(*_perms)(
1979 1980 user=apiuser, user_group_name=user_group.users_group_name):
1980 1981 raise JSONRPCError(
1981 1982 'user group `%s` does not exist' % (usergroupid,))
1982 1983
1983 1984 perm_deletions = [[user_group.users_group_id, None, "user_group"]]
1984 1985 try:
1985 1986 changes = RepoModel().update_permissions(
1986 1987 repo=repo, perm_deletions=perm_deletions, cur_user=apiuser)
1987 1988 action_data = {
1988 1989 'added': changes['added'],
1989 1990 'updated': changes['updated'],
1990 1991 'deleted': changes['deleted'],
1991 1992 }
1992 1993 audit_logger.store_api(
1993 1994 'repo.edit.permissions', action_data=action_data, user=apiuser, repo=repo)
1994 1995
1995 1996 Session().commit()
1996 1997 return {
1997 1998 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1998 1999 user_group.users_group_name, repo.repo_name
1999 2000 ),
2000 2001 'success': True
2001 2002 }
2002 2003 except Exception:
2003 2004 log.exception("Exception occurred while trying revoke "
2004 2005 "user group permission on repo")
2005 2006 raise JSONRPCError(
2006 2007 'failed to edit permission for user group: `%s` in '
2007 2008 'repo: `%s`' % (
2008 2009 user_group.users_group_name, repo.repo_name
2009 2010 )
2010 2011 )
2011 2012
2012 2013
2013 2014 @jsonrpc_method()
2014 2015 def pull(request, apiuser, repoid, remote_uri=Optional(None)):
2015 2016 """
2016 2017 Triggers a pull on the given repository from a remote location. You
2017 2018 can use this to keep remote repositories up-to-date.
2018 2019
2019 2020 This command can only be run using an |authtoken| with admin
2020 2021 rights to the specified repository. For more information,
2021 2022 see :ref:`config-token-ref`.
2022 2023
2023 2024 This command takes the following options:
2024 2025
2025 2026 :param apiuser: This is filled automatically from the |authtoken|.
2026 2027 :type apiuser: AuthUser
2027 2028 :param repoid: The repository name or repository ID.
2028 2029 :type repoid: str or int
2029 2030 :param remote_uri: Optional remote URI to pass in for pull
2030 2031 :type remote_uri: str
2031 2032
2032 2033 Example output:
2033 2034
2034 2035 .. code-block:: bash
2035 2036
2036 2037 id : <id_given_in_input>
2037 2038 result : {
2038 2039 "msg": "Pulled from url `<remote_url>` on repo `<repository name>`"
2039 2040 "repository": "<repository name>"
2040 2041 }
2041 2042 error : null
2042 2043
2043 2044 Example error output:
2044 2045
2045 2046 .. code-block:: bash
2046 2047
2047 2048 id : <id_given_in_input>
2048 2049 result : null
2049 2050 error : {
2050 2051 "Unable to push changes from `<remote_url>`"
2051 2052 }
2052 2053
2053 2054 """
2054 2055
2055 2056 repo = get_repo_or_error(repoid)
2056 2057 remote_uri = Optional.extract(remote_uri)
2057 2058 remote_uri_display = remote_uri or repo.clone_uri_hidden
2058 2059 if not has_superadmin_permission(apiuser):
2059 2060 _perms = ('repository.admin',)
2060 2061 validate_repo_permissions(apiuser, repoid, repo, _perms)
2061 2062
2062 2063 try:
2063 2064 ScmModel().pull_changes(
2064 2065 repo.repo_name, apiuser.username, remote_uri=remote_uri)
2065 2066 return {
2066 2067 'msg': 'Pulled from url `%s` on repo `%s`' % (
2067 2068 remote_uri_display, repo.repo_name),
2068 2069 'repository': repo.repo_name
2069 2070 }
2070 2071 except Exception:
2071 2072 log.exception("Exception occurred while trying to "
2072 2073 "pull changes from remote location")
2073 2074 raise JSONRPCError(
2074 2075 'Unable to pull changes from `%s`' % remote_uri_display
2075 2076 )
2076 2077
2077 2078
2078 2079 @jsonrpc_method()
2079 2080 def strip(request, apiuser, repoid, revision, branch):
2080 2081 """
2081 2082 Strips the given revision from the specified repository.
2082 2083
2083 2084 * This will remove the revision and all of its decendants.
2084 2085
2085 2086 This command can only be run using an |authtoken| with admin rights to
2086 2087 the specified repository.
2087 2088
2088 2089 This command takes the following options:
2089 2090
2090 2091 :param apiuser: This is filled automatically from the |authtoken|.
2091 2092 :type apiuser: AuthUser
2092 2093 :param repoid: The repository name or repository ID.
2093 2094 :type repoid: str or int
2094 2095 :param revision: The revision you wish to strip.
2095 2096 :type revision: str
2096 2097 :param branch: The branch from which to strip the revision.
2097 2098 :type branch: str
2098 2099
2099 2100 Example output:
2100 2101
2101 2102 .. code-block:: bash
2102 2103
2103 2104 id : <id_given_in_input>
2104 2105 result : {
2105 2106 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
2106 2107 "repository": "<repository name>"
2107 2108 }
2108 2109 error : null
2109 2110
2110 2111 Example error output:
2111 2112
2112 2113 .. code-block:: bash
2113 2114
2114 2115 id : <id_given_in_input>
2115 2116 result : null
2116 2117 error : {
2117 2118 "Unable to strip commit <commit_hash> from repo `<repository name>`"
2118 2119 }
2119 2120
2120 2121 """
2121 2122
2122 2123 repo = get_repo_or_error(repoid)
2123 2124 if not has_superadmin_permission(apiuser):
2124 2125 _perms = ('repository.admin',)
2125 2126 validate_repo_permissions(apiuser, repoid, repo, _perms)
2126 2127
2127 2128 try:
2128 2129 ScmModel().strip(repo, revision, branch)
2129 2130 audit_logger.store_api(
2130 2131 'repo.commit.strip', action_data={'commit_id': revision},
2131 2132 repo=repo,
2132 2133 user=apiuser, commit=True)
2133 2134
2134 2135 return {
2135 2136 'msg': 'Stripped commit %s from repo `%s`' % (
2136 2137 revision, repo.repo_name),
2137 2138 'repository': repo.repo_name
2138 2139 }
2139 2140 except Exception:
2140 2141 log.exception("Exception while trying to strip")
2141 2142 raise JSONRPCError(
2142 2143 'Unable to strip commit %s from repo `%s`' % (
2143 2144 revision, repo.repo_name)
2144 2145 )
2145 2146
2146 2147
2147 2148 @jsonrpc_method()
2148 2149 def get_repo_settings(request, apiuser, repoid, key=Optional(None)):
2149 2150 """
2150 2151 Returns all settings for a repository. If key is given it only returns the
2151 2152 setting identified by the key or null.
2152 2153
2153 2154 :param apiuser: This is filled automatically from the |authtoken|.
2154 2155 :type apiuser: AuthUser
2155 2156 :param repoid: The repository name or repository id.
2156 2157 :type repoid: str or int
2157 2158 :param key: Key of the setting to return.
2158 2159 :type: key: Optional(str)
2159 2160
2160 2161 Example output:
2161 2162
2162 2163 .. code-block:: bash
2163 2164
2164 2165 {
2165 2166 "error": null,
2166 2167 "id": 237,
2167 2168 "result": {
2168 2169 "extensions_largefiles": true,
2169 2170 "extensions_evolve": true,
2170 2171 "hooks_changegroup_push_logger": true,
2171 2172 "hooks_changegroup_repo_size": false,
2172 2173 "hooks_outgoing_pull_logger": true,
2173 2174 "phases_publish": "True",
2174 2175 "rhodecode_hg_use_rebase_for_merging": true,
2175 2176 "rhodecode_pr_merge_enabled": true,
2176 2177 "rhodecode_use_outdated_comments": true
2177 2178 }
2178 2179 }
2179 2180 """
2180 2181
2181 2182 # Restrict access to this api method to admins only.
2182 2183 if not has_superadmin_permission(apiuser):
2183 2184 raise JSONRPCForbidden()
2184 2185
2185 2186 try:
2186 2187 repo = get_repo_or_error(repoid)
2187 2188 settings_model = VcsSettingsModel(repo=repo)
2188 2189 settings = settings_model.get_global_settings()
2189 2190 settings.update(settings_model.get_repo_settings())
2190 2191
2191 2192 # If only a single setting is requested fetch it from all settings.
2192 2193 key = Optional.extract(key)
2193 2194 if key is not None:
2194 2195 settings = settings.get(key, None)
2195 2196 except Exception:
2196 2197 msg = 'Failed to fetch settings for repository `{}`'.format(repoid)
2197 2198 log.exception(msg)
2198 2199 raise JSONRPCError(msg)
2199 2200
2200 2201 return settings
2201 2202
2202 2203
2203 2204 @jsonrpc_method()
2204 2205 def set_repo_settings(request, apiuser, repoid, settings):
2205 2206 """
2206 2207 Update repository settings. Returns true on success.
2207 2208
2208 2209 :param apiuser: This is filled automatically from the |authtoken|.
2209 2210 :type apiuser: AuthUser
2210 2211 :param repoid: The repository name or repository id.
2211 2212 :type repoid: str or int
2212 2213 :param settings: The new settings for the repository.
2213 2214 :type: settings: dict
2214 2215
2215 2216 Example output:
2216 2217
2217 2218 .. code-block:: bash
2218 2219
2219 2220 {
2220 2221 "error": null,
2221 2222 "id": 237,
2222 2223 "result": true
2223 2224 }
2224 2225 """
2225 2226 # Restrict access to this api method to admins only.
2226 2227 if not has_superadmin_permission(apiuser):
2227 2228 raise JSONRPCForbidden()
2228 2229
2229 2230 if type(settings) is not dict:
2230 2231 raise JSONRPCError('Settings have to be a JSON Object.')
2231 2232
2232 2233 try:
2233 2234 settings_model = VcsSettingsModel(repo=repoid)
2234 2235
2235 2236 # Merge global, repo and incoming settings.
2236 2237 new_settings = settings_model.get_global_settings()
2237 2238 new_settings.update(settings_model.get_repo_settings())
2238 2239 new_settings.update(settings)
2239 2240
2240 2241 # Update the settings.
2241 2242 inherit_global_settings = new_settings.get(
2242 2243 'inherit_global_settings', False)
2243 2244 settings_model.create_or_update_repo_settings(
2244 2245 new_settings, inherit_global_settings=inherit_global_settings)
2245 2246 Session().commit()
2246 2247 except Exception:
2247 2248 msg = 'Failed to update settings for repository `{}`'.format(repoid)
2248 2249 log.exception(msg)
2249 2250 raise JSONRPCError(msg)
2250 2251
2251 2252 # Indicate success.
2252 2253 return True
2253 2254
2254 2255
2255 2256 @jsonrpc_method()
2256 2257 def maintenance(request, apiuser, repoid):
2257 2258 """
2258 2259 Triggers a maintenance on the given repository.
2259 2260
2260 2261 This command can only be run using an |authtoken| with admin
2261 2262 rights to the specified repository. For more information,
2262 2263 see :ref:`config-token-ref`.
2263 2264
2264 2265 This command takes the following options:
2265 2266
2266 2267 :param apiuser: This is filled automatically from the |authtoken|.
2267 2268 :type apiuser: AuthUser
2268 2269 :param repoid: The repository name or repository ID.
2269 2270 :type repoid: str or int
2270 2271
2271 2272 Example output:
2272 2273
2273 2274 .. code-block:: bash
2274 2275
2275 2276 id : <id_given_in_input>
2276 2277 result : {
2277 2278 "msg": "executed maintenance command",
2278 2279 "executed_actions": [
2279 2280 <action_message>, <action_message2>...
2280 2281 ],
2281 2282 "repository": "<repository name>"
2282 2283 }
2283 2284 error : null
2284 2285
2285 2286 Example error output:
2286 2287
2287 2288 .. code-block:: bash
2288 2289
2289 2290 id : <id_given_in_input>
2290 2291 result : null
2291 2292 error : {
2292 2293 "Unable to execute maintenance on `<reponame>`"
2293 2294 }
2294 2295
2295 2296 """
2296 2297
2297 2298 repo = get_repo_or_error(repoid)
2298 2299 if not has_superadmin_permission(apiuser):
2299 2300 _perms = ('repository.admin',)
2300 2301 validate_repo_permissions(apiuser, repoid, repo, _perms)
2301 2302
2302 2303 try:
2303 2304 maintenance = repo_maintenance.RepoMaintenance()
2304 2305 executed_actions = maintenance.execute(repo)
2305 2306
2306 2307 return {
2307 2308 'msg': 'executed maintenance command',
2308 2309 'executed_actions': executed_actions,
2309 2310 'repository': repo.repo_name
2310 2311 }
2311 2312 except Exception:
2312 2313 log.exception("Exception occurred while trying to run maintenance")
2313 2314 raise JSONRPCError(
2314 2315 'Unable to execute maintenance on `%s`' % repo.repo_name)
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now