Merge pull request !2951 from rhodecode-enterprise-ce feature/RCCE-386_add_ai_code_review_checkbox
feature: implements AI code review PR checkbox; adds AI PR settings
This commit is contained in:
commit
e1a67b7306
12 changed files with 184 additions and 48 deletions
29
docs/ai/ai-code-review.rst
Normal file
29
docs/ai/ai-code-review.rst
Normal file
|
|
@ -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.
|
||||
|
||||
16
docs/ai/ai-configuration.rst
Normal file
16
docs/ai/ai-configuration.rst
Normal file
|
|
@ -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.
|
||||
|
|
@ -47,6 +47,13 @@ and commit files and |repos| while managing their security permissions.
|
|||
|
||||
RhodeCode RCstack Installer <https://docs.rhodecode.com/rcstack/>
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: AI Documentation
|
||||
|
||||
ai/ai-configuration
|
||||
ai/ai-code-review
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Admin Documentation
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
<style>
|
||||
.field > .label {
|
||||
min-width: 300px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">${_('Ai Configuration')}</h3>
|
||||
|
|
@ -15,6 +21,16 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field" id="ai-default-review-toggle" >
|
||||
<div class="label label-checkbox">
|
||||
<label for="rhodecode_ai_default_code_review">${_('Turn on AI code review by default for new PRs')}:</label>
|
||||
<strong>Warning</strong>: can potentially spend a lot of tokens
|
||||
</div>
|
||||
<div class="checkboxes">
|
||||
${h.checkbox('rhodecode_ai_default_code_review',value=True, checked=c.ai_default_code_review==True)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field" id="model" style="display: flex;">
|
||||
<div class="label label">
|
||||
<label for="model">${_('Model')}</label>
|
||||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -279,6 +279,34 @@
|
|||
<span class="help-block">${_('When enabled, the security scan checkbox will be pre-selected when creating pull requests. This scans the PR diff for exposed secrets and credentials.')}</span>
|
||||
</div>
|
||||
%endif
|
||||
|
||||
%if hasattr(c, 'repo_vcs_settings') and c.repo_vcs_settings:
|
||||
|
||||
%if c.rhodecode_edition_id != 'EE':
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" disabled>
|
||||
<label>${_('Enable AI review for pull requests')}</label>
|
||||
</div>
|
||||
<div class="label">
|
||||
<span class="help-block">${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</span>
|
||||
</div>
|
||||
%else:
|
||||
<div class="checkbox">
|
||||
%if c.ai_features_enabled:
|
||||
${h.checkbox('rhodecode_ai_default_code_review' + suffix, 'True', checked=c.ai_default_code_review, **kwargs)}
|
||||
<label for="rhodecode_ai_default_code_review${suffix}">${_('Enable AI review for pull requests')}</label>
|
||||
%else:
|
||||
<span class="tooltip" title="${_('AI features disabled, enable AI features to activate this checkbox.')}">
|
||||
${h.checkbox('rhodecode_ai_default_code_review' + suffix, 'True', checked=c.ai_default_code_review, disabled=True, **kwargs)}
|
||||
<label for="rhodecode_ai_default_code_review${suffix}">${_('Enable AI review for pull requests')}</label>
|
||||
</span>
|
||||
%endif
|
||||
</div>
|
||||
<div class="label">
|
||||
<span class="help-block">${_('When enabled, the AI code review checkbox will be pre-selected when creating pull requests. This will schedule AI code review for the PR.')}</span>
|
||||
</div>
|
||||
%endif
|
||||
%endif
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
||||
|
|
|
|||
|
|
@ -247,6 +247,31 @@
|
|||
</label>
|
||||
</div>
|
||||
% endif
|
||||
|
||||
% if c.ai_enabled and c.rhodecode_edition_id == 'EE':
|
||||
<div class="pull-request-settings" style="margin-left: 220px">
|
||||
${h.checkbox('run_ai_codereview', checked=c.ai_pr_review, value=True)}
|
||||
<label for="run_ai_codereview">
|
||||
${h.literal(_('Run run AI code review'))}
|
||||
</label>
|
||||
</div>
|
||||
% elif not c.ai_enabled:
|
||||
<div class="pull-request-settings" style="margin-left: 220px">
|
||||
${h.checkbox('run_ai_codereview', checked=False, value=True, disabled=True, **{'class': 'disabled-checkbox'})}
|
||||
<label for="run_ai_codereview" class="disabled-label">
|
||||
${h.literal(_('Run AI code review'))}
|
||||
<span class="tooltip" title="${_('Enable AI features to use this checkbox')}">[?]</span>
|
||||
</label>
|
||||
</div>
|
||||
% elif c.rhodecode_edition_id != 'EE':
|
||||
<div class="pull-request-settings" style="margin-left: 220px">
|
||||
${h.checkbox('run_ai_codereview', checked=False, value=True, disabled=True, **{'class': 'disabled-checkbox'})}
|
||||
<label for="run_ai_codereview" class="disabled-label">
|
||||
${h.literal(_('Run AI code review'))}
|
||||
<span class="ee-feature-label">[EE Only]</span>
|
||||
</label>
|
||||
</div>
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue