diff --git a/docs/ai/ai-code-review.rst b/docs/ai/ai-code-review.rst
new file mode 100644
index 00000000..0100a056
--- /dev/null
+++ b/docs/ai/ai-code-review.rst
@@ -0,0 +1,29 @@
+.. _ai-code-review:
+
+AI Code review
+=================
+
+To start AI code review, first complete the setup in :ref:`ai-config`.
+
+You can configure AI code review in several places:
+
+1. Global (admin)
+ Navigate to :menuselection:`Admin --> Authentication --> Settings --> AI Features` and enable `Turn on AI code review by default for new PRs`.
+ This sets the default for all newly created pull requests. Repository admins and PR authors can override this setting at the repository and pull request level.
+
+2. Repository-level setting (repository admin)
+ Navigate to :menuselection:`Repository Settings --> VCS --> Pull Request Settings` and toggle `Enable AI review for pull requests`.
+
+3. During pull request creation (any user)
+ When creating a pull request, enable the `Run AI code review` checkbox to run the review for that PR.
+
+4. In an existing pull request (any user)
+ In an existing pull request, use the button in the right-side menu to start an AI code review.
+
+
+.. note::
+
+ At the moment, AI code review can only be run once per pull request.
+ After the review finishes, you won’t be able to restart it. In addition,
+ you can view the AI code review status in the audit logs.
+
diff --git a/docs/ai/ai-configuration.rst b/docs/ai/ai-configuration.rst
new file mode 100644
index 00000000..efa6e9e7
--- /dev/null
+++ b/docs/ai/ai-configuration.rst
@@ -0,0 +1,16 @@
+.. _ai-config:
+
+AI Configuration
+=================
+
+To start using AI features in the |RCE|, run through the below steps:
+
+1. Navigate to :menuselection:`Admin --> Authentication --> Settings --> AI Features` - and check `Enable AI features` checkbox.
+
+2. Insert your API key into the `Api key` input.
+
+3. Select `AI Model` from the dropdown. Currently |RCE| supports 3 providers: GPT, Gemini, Claude.
+
+4. Hit `Update model versions` button. This will download model versions for selected model.
+
+5. Hit `Save` button.
diff --git a/docs/index.rst b/docs/index.rst
index da3a5b33..2863efb6 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -47,6 +47,13 @@ and commit files and |repos| while managing their security permissions.
RhodeCode RCstack Installer
+.. toctree::
+ :maxdepth: 1
+ :caption: AI Documentation
+
+ ai/ai-configuration
+ ai/ai-code-review
+
.. toctree::
:maxdepth: 1
:caption: Admin Documentation
diff --git a/rhodecode/apps/admin/views/ai.py b/rhodecode/apps/admin/views/ai.py
index 59cc1832..9a31b055 100644
--- a/rhodecode/apps/admin/views/ai.py
+++ b/rhodecode/apps/admin/views/ai.py
@@ -36,6 +36,7 @@ class AdminAiView(BaseAppView):
c.selected_ai_model_version = app_settings.get("rhodecode_ai_model_version")
c.api_key = app_settings.get("rhodecode_ai_api_key")
c.ai_features_enabled = app_settings.get("rhodecode_ai_features_enabled", False)
+ c.ai_default_code_review = app_settings.get("rhodecode_ai_default_code_review", False)
c.ai_instructions = app_settings.get("rhodecode_ai_code_review_instructions")
if not c.ai_instructions:
@@ -112,6 +113,7 @@ class AdminAiView(BaseAppView):
try:
settings = [
("ai_features_enabled", "rhodecode_ai_features_enabled", "bool"),
+ ("ai_default_code_review", "rhodecode_ai_default_code_review", "bool"),
("ai_model", "rhodecode_ai_model", "unicode"),
("ai_model_version", "rhodecode_ai_model_version", "unicode"),
("ai_api_key", "rhodecode_ai_api_key", "unicode"),
diff --git a/rhodecode/apps/repository/views/repo_pull_requests.py b/rhodecode/apps/repository/views/repo_pull_requests.py
index 8c71c007..1d966843 100644
--- a/rhodecode/apps/repository/views/repo_pull_requests.py
+++ b/rhodecode/apps/repository/views/repo_pull_requests.py
@@ -913,6 +913,9 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
self.assure_not_empty_repo()
source_repo = self.db_repo
+ app_settings = c.rc_config
+ c.ai_enabled = app_settings.get("rhodecode_ai_features_enabled", False)
+
commit_id = self.request.GET.get("commit")
branch_ref = self.request.GET.get("branch")
bookmark_ref = self.request.GET.get("bookmark")
@@ -971,6 +974,9 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
# Get security scan setting for pre-checking the checkbox
c.pr_security_scan_enabled = self._get_repo_setting(source_repo, "rhodecode_pr_security_scan_enabled", False)
+ c.ai_pr_review = self._get_repo_setting(
+ source_repo, "rhodecode_ai_default_code_review", app_settings.get("rhodecode_ai_default_code_review", False)
+ )
return self._get_template_context(c)
@LoginRequired()
@@ -1311,6 +1317,11 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
except ImportError:
log.warning("EE security audit tasks not available, skipping")
+ rc_settings = SettingsModel()
+ ai_enabled = rc_settings.get_setting_by_name("ai_features_enabled")
+ if ai_enabled and _form.get("run_ai_codereview", False):
+ self._try_start_ai_code_review(_, pull_request, add_existing_users=True)
+
Session().commit()
h.flash(_("Successfully opened new pull request"), category="success")
@@ -1373,62 +1384,46 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
log.warning("Code review already finished.")
return False
- admin_permissions = (
- "repository.admin",
- "hg.admin",
- )
- is_admin = h.HasRepoPermissionAny(*admin_permissions)(
- user=self._rhodecode_user, repo_name=pull_request.target_repo.repo_name
- )
+ ai_user = User.get_ai_user()
+ log.debug("Initiating code review for pull request id: %s", pull_request.pull_request_id)
- if is_admin:
- ai_user = User.get_ai_user()
- log.debug("Initiating code review for pull request id: %s", pull_request.pull_request_id)
+ reviewers_data = []
- reviewers_data = []
-
- if add_existing_users:
- current_reviewers = PullRequestReviewers.get_pull_request_reviewers(
- pull_request.pull_request_id, role=PullRequestReviewers.ROLE_REVIEWER
- )
- for existing_reviewer in current_reviewers:
- reviewers_data.append(
- (
- existing_reviewer.user_id,
- existing_reviewer.reasons,
- existing_reviewer.mandatory,
- existing_reviewer.role,
- existing_reviewer.rule_data,
- )
+ if add_existing_users:
+ current_reviewers = PullRequestReviewers.get_pull_request_reviewers(
+ pull_request.pull_request_id, role=PullRequestReviewers.ROLE_REVIEWER
+ )
+ for existing_reviewer in current_reviewers:
+ reviewers_data.append(
+ (
+ existing_reviewer.user_id,
+ existing_reviewer.reasons,
+ existing_reviewer.mandatory,
+ existing_reviewer.role,
+ existing_reviewer.rule_data,
)
-
- reviewers_data.append(
- (
- ai_user.user_id,
- ["adds system ai user for review"],
- False,
- PullRequestReviewers.ROLE_REVIEWER,
- pull_request.reviewer_data,
)
+
+ reviewers_data.append(
+ (
+ ai_user.user_id,
+ ["adds system ai user for review"],
+ False,
+ PullRequestReviewers.ROLE_REVIEWER,
+ pull_request.reviewer_data,
)
+ )
- PullRequestModel().update_reviewers(pull_request, reviewers_data, self._rhodecode_db_user)
+ PullRequestModel().update_reviewers(pull_request, reviewers_data, self._rhodecode_db_user)
- Session().commit()
+ Session().commit()
- run_task(tasks.start_ai_code_review, pull_request.pull_request_id)
- self._set_ai_pr_state_pending(pull_request)
+ run_task(tasks.start_ai_code_review, pull_request.pull_request_id)
+ self._set_ai_pr_state_pending(pull_request)
+
+ msg = _("AI code review has started. The review will be ready in about 1–3 minutes.")
+ h.flash(msg, category="success")
- msg = _("AI code review has started. The review will be ready in about 1–3 minutes.")
- h.flash(msg, category="success")
- else:
- log.debug("AI code review canceled, only admin can initiate AI code review.")
- msg = _("AI code review is not available. This feature is in BETA and can only be initiated by an admin.")
- h.flash(
- msg,
- category="warning",
- )
- return False
return True
@LoginRequired()
diff --git a/rhodecode/apps/repository/views/repo_settings_vcs.py b/rhodecode/apps/repository/views/repo_settings_vcs.py
index 25cd59bd..b6a9279c 100644
--- a/rhodecode/apps/repository/views/repo_settings_vcs.py
+++ b/rhodecode/apps/repository/views/repo_settings_vcs.py
@@ -71,7 +71,18 @@ class RepoSettingsVcsView(RepoAppView):
c = self.load_default_context()
model = VcsSettingsModel(repo=self.db_repo_name)
+ app_settings = c.rc_config
+
c.active = "vcs"
+ c.repo_vcs_settings = True
+
+ c.ai_features_enabled = app_settings.get("rhodecode_ai_features_enabled", False)
+ c.ai_default_code_review = self._get_repo_setting(
+ self.db_repo,
+ "rhodecode_ai_default_code_review",
+ app_settings.get("rhodecode_ai_default_code_review", False),
+ )
+
c.global_svn_branch_patterns = model.get_global_svn_branch_patterns()
c.global_svn_tag_patterns = model.get_global_svn_tag_patterns()
c.svn_branch_patterns = model.get_repo_svn_branch_patterns()
diff --git a/rhodecode/model/forms.py b/rhodecode/model/forms.py
index 69915d53..31cb9681 100644
--- a/rhodecode/model/forms.py
+++ b/rhodecode/model/forms.py
@@ -444,6 +444,7 @@ class _BaseVcsSettingsForm(formencode.Schema):
rhodecode_auto_merge_enabled = v.StringBoolean(if_missing=False)
rhodecode_use_outdated_comments = v.StringBoolean(if_missing=False)
rhodecode_pr_security_scan_enabled = v.StringBoolean(if_missing=False)
+ rhodecode_ai_default_code_review = v.StringBoolean(if_missing=False)
# hg
extensions_largefiles = v.StringBoolean(if_missing=False)
@@ -673,6 +674,7 @@ def PullRequestForm(localizer, repo_id):
description_renderer = v.UnicodeString(strip=True, required=False)
close_branch_before_merging = v.StringBoolean(if_missing=False)
run_security_audit = v.StringBoolean(if_missing=False)
+ run_ai_codereview = v.StringBoolean(if_missing=False)
return _PullRequestForm
@@ -692,6 +694,7 @@ def AiSettingsForm():
class _AiSettingsForm(formencode.Schema):
allow_extra_fields = True
rhodecode_ai_features_enabled = v.StringBoolean(if_missing=False)
+ rhodecode_ai_default_code_review = v.StringBoolean(if_missing=False)
rhodecode_ai_model = v.UnicodeString(strip=True, required=True)
rhodecode_ai_model_version = v.UnicodeString(strip=True, required=True)
rhodecode_ai_api_key = v.UnicodeString(strip=True)
diff --git a/rhodecode/model/settings.py b/rhodecode/model/settings.py
index 59863017..37efe92a 100644
--- a/rhodecode/model/settings.py
+++ b/rhodecode/model/settings.py
@@ -457,6 +457,7 @@ class VcsSettingsModel:
"pr_merge_enabled",
"auto_merge_enabled",
"pr_security_scan_enabled",
+ "ai_default_code_review",
"hg_use_rebase_for_merging",
"hg_close_branch_before_merging",
"hg_merge_strategy_selector",
diff --git a/rhodecode/templates/admin/settings/settings_ai.mako b/rhodecode/templates/admin/settings/settings_ai.mako
index 4c68763b..38b39ae7 100644
--- a/rhodecode/templates/admin/settings/settings_ai.mako
+++ b/rhodecode/templates/admin/settings/settings_ai.mako
@@ -1,3 +1,9 @@
+
+
${_('Ai Configuration')}
@@ -15,6 +21,16 @@
+
+
+ ${_('Turn on AI code review by default for new PRs')}:
+ Warning : can potentially spend a lot of tokens
+
+
+ ${h.checkbox('rhodecode_ai_default_code_review',value=True, checked=c.ai_default_code_review==True)}
+
+
+
${_('Model')}
@@ -79,6 +95,7 @@ import json
const $model = $('#rhodecode_ai_model');
const $slot = $('#model_version_slot');
const $enable = $('#rhodecode_ai_features_enabled');
+ const $codeReview = $('#rhodecode_ai_default_code_review');
const $form = $('#ai_features_form');
const $updateModelsBtn = $('#model_version_button_update');
@@ -181,7 +198,8 @@ import json
data: {
'rhodecode_ai_model': $model.val(),
'rhodecode_ai_api_key': $apiKey.val(),
- 'rhodecode_ai_features_enabled': $enable.is(':checked')
+ 'rhodecode_ai_features_enabled': $enable.is(':checked'),
+ 'rhodecode_ai_default_code_review': $codeReview.is(':checked')
},
success: function (response) {
$.Topic('/notifications').publish({
diff --git a/rhodecode/templates/base/vcs_settings.mako b/rhodecode/templates/base/vcs_settings.mako
index 8a6d671c..d821b465 100644
--- a/rhodecode/templates/base/vcs_settings.mako
+++ b/rhodecode/templates/base/vcs_settings.mako
@@ -279,6 +279,34 @@
${_('When enabled, the security scan checkbox will be pre-selected when creating pull requests. This scans the PR diff for exposed secrets and credentials.')}
%endif
+
+ %if hasattr(c, 'repo_vcs_settings') and c.repo_vcs_settings:
+
+ %if c.rhodecode_edition_id != 'EE':
+
+
+ ${_('Enable AI review for pull requests')}
+
+
+
${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='sales@rhodecode.com ')|n}
+
+ %else:
+
+ %if c.ai_features_enabled:
+ ${h.checkbox('rhodecode_ai_default_code_review' + suffix, 'True', checked=c.ai_default_code_review, **kwargs)}
+ ${_('Enable AI review for pull requests')}
+ %else:
+
+ ${h.checkbox('rhodecode_ai_default_code_review' + suffix, 'True', checked=c.ai_default_code_review, disabled=True, **kwargs)}
+ ${_('Enable AI review for pull requests')}
+
+ %endif
+
+
+ ${_('When enabled, the AI code review checkbox will be pre-selected when creating pull requests. This will schedule AI code review for the PR.')}
+
+ %endif
+ %endif
% endif
diff --git a/rhodecode/templates/pullrequests/pullrequest.mako b/rhodecode/templates/pullrequests/pullrequest.mako
index 4b3323cb..b24c89e1 100644
--- a/rhodecode/templates/pullrequests/pullrequest.mako
+++ b/rhodecode/templates/pullrequests/pullrequest.mako
@@ -247,6 +247,31 @@
% endif
+
+ % if c.ai_enabled and c.rhodecode_edition_id == 'EE':
+
+ ${h.checkbox('run_ai_codereview', checked=c.ai_pr_review, value=True)}
+
+ ${h.literal(_('Run run AI code review'))}
+
+
+ % elif not c.ai_enabled:
+
+ ${h.checkbox('run_ai_codereview', checked=False, value=True, disabled=True, **{'class': 'disabled-checkbox'})}
+
+ ${h.literal(_('Run AI code review'))}
+ [?]
+
+
+ % elif c.rhodecode_edition_id != 'EE':
+
+ ${h.checkbox('run_ai_codereview', checked=False, value=True, disabled=True, **{'class': 'disabled-checkbox'})}
+
+ ${h.literal(_('Run AI code review'))}
+ [EE Only]
+
+
+ % endif
diff --git a/rhodecode/tests/models/settings/test_vcs_settings.py b/rhodecode/tests/models/settings/test_vcs_settings.py
index d3ace4f5..5986333d 100644
--- a/rhodecode/tests/models/settings/test_vcs_settings.py
+++ b/rhodecode/tests/models/settings/test_vcs_settings.py
@@ -37,6 +37,7 @@ GENERAL_FORM_DATA = {
"rhodecode_auto_merge_enabled": True,
"rhodecode_use_outdated_comments": True,
"rhodecode_pr_security_scan_enabled": True,
+ "rhodecode_ai_default_code_review": True,
"rhodecode_hg_use_rebase_for_merging": True,
"rhodecode_hg_close_branch_before_merging": True,
"rhodecode_hg_merge_strategy_selector": True,