diff --git a/awx/ui/client/features/output/details.component.js b/awx/ui/client/features/output/details.component.js index 9bddc202f7..d6da44d913 100644 --- a/awx/ui/client/features/output/details.component.js +++ b/awx/ui/client/features/output/details.component.js @@ -343,6 +343,17 @@ function getProjectUpdateDetails (updateId) { return { link, tooltip }; } +function getSCMBranchDetails (scmBranch) { + const label = strings.get('labels.SCM_BRANCH'); + const value = scmBranch || resource.model.get('scm_branch'); + + if (!value) { + return null; + } + + return { label, value }; +} + function getInventoryScmDetails (updateId, updateStatus) { const projectId = resource.model.get('summary_fields.source_project.id'); const projectName = resource.model.get('summary_fields.source_project.name'); @@ -800,6 +811,7 @@ function JobDetailsController ( vm.project = getProjectDetails(); vm.projectUpdate = getProjectUpdateDetails(); vm.projectStatus = getProjectStatusDetails(); + vm.scmBranch = getSCMBranchDetails(); vm.scmRevision = getSCMRevisionDetails(); vm.inventoryScm = getInventoryScmDetails(); vm.playbook = getPlaybookDetails(); @@ -840,6 +852,7 @@ function JobDetailsController ( started, finished, scm, + scmBranch, inventoryScm, scmRevision, instanceGroup, @@ -851,6 +864,7 @@ function JobDetailsController ( vm.finished = getFinishDetails(finished); vm.projectUpdate = getProjectUpdateDetails(scm.id); vm.projectStatus = getProjectStatusDetails(scm.status); + vm.scmBranch = getSCMBranchDetails(scmBranch); vm.environment = getEnvironmentDetails(environment); vm.artifacts = getArtifactsDetails(artifacts); vm.executionNode = getExecutionNodeDetails(executionNode); diff --git a/awx/ui/client/features/output/details.partial.html b/awx/ui/client/features/output/details.partial.html index 5ad6dde62e..a3b3b664e0 100644 --- a/awx/ui/client/features/output/details.partial.html +++ b/awx/ui/client/features/output/details.partial.html @@ -218,6 +218,12 @@ + +
' + i18n._('Allow changing the SCM branch or revision in a job template that uses this project.') + '
', + dataTitle: i18n._('Allow branch override'), + dataContainer: 'body', + dataPlacement: 'right', + labelClass: 'checkbox-options stack-inline', + ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)', + ngShow: "scm_type && scm_type.value !== 'insights'", }] }, scm_update_cache_timeout: { diff --git a/awx/ui/client/src/scheduler/schedulerAdd.controller.js b/awx/ui/client/src/scheduler/schedulerAdd.controller.js index 3d6642d6c4..0ff85f7688 100644 --- a/awx/ui/client/src/scheduler/schedulerAdd.controller.js +++ b/awx/ui/client/src/scheduler/schedulerAdd.controller.js @@ -161,6 +161,7 @@ export default ['$filter', '$state', '$stateParams', '$http', 'Wait', !launchConf.ask_tags_on_launch && !launchConf.ask_skip_tags_on_launch && !launchConf.ask_diff_mode_on_launch && + !launchConf.ask_scm_branch_on_launch && !launchConf.survey_enabled && !launchConf.credential_needed_to_start && !launchConf.inventory_needed_to_start && @@ -248,6 +249,7 @@ export default ['$filter', '$state', '$stateParams', '$http', 'Wait', !launchConf.ask_tags_on_launch && !launchConf.ask_skip_tags_on_launch && !launchConf.ask_diff_mode_on_launch && + !launchConf.ask_scm_branch_on_launch && !launchConf.survey_enabled && !launchConf.credential_needed_to_start && !launchConf.inventory_needed_to_start && diff --git a/awx/ui/client/src/scheduler/schedulerEdit.controller.js b/awx/ui/client/src/scheduler/schedulerEdit.controller.js index 75ed397e7b..7a180724e9 100644 --- a/awx/ui/client/src/scheduler/schedulerEdit.controller.js +++ b/awx/ui/client/src/scheduler/schedulerEdit.controller.js @@ -335,6 +335,7 @@ function($filter, $state, $stateParams, Wait, $scope, moment, !launchConf.ask_tags_on_launch && !launchConf.ask_skip_tags_on_launch && !launchConf.ask_diff_mode_on_launch && + !launchConf.ask_scm_branch_on_launch && !launchConf.survey_enabled && !launchConf.credential_needed_to_start && !launchConf.inventory_needed_to_start && @@ -433,6 +434,7 @@ function($filter, $state, $stateParams, Wait, $scope, moment, !launchConf.ask_tags_on_launch && !launchConf.ask_skip_tags_on_launch && !launchConf.ask_diff_mode_on_launch && + !launchConf.ask_scm_branch_on_launch && !launchConf.survey_enabled && !launchConf.credential_needed_to_start && !launchConf.inventory_needed_to_start && diff --git a/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js b/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js index b9b2c15ac2..bb3891278f 100644 --- a/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js +++ b/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js @@ -104,7 +104,11 @@ }); CreateSelect2({ element:'#playbook-select', - multiple: false + addNew: true, + multiple: false, + scope: $scope, + options: 'playbook_options', + model: 'playbook' }); CreateSelect2({ element:'#job_template_verbosity', @@ -155,7 +159,11 @@ function sync_playbook_select2() { CreateSelect2({ element:'#playbook-select', - multiple: false + addNew: true, + multiple: false, + scope: $scope, + options: 'playbook_options', + model: 'playbook' }); } @@ -177,6 +185,9 @@ for (i = 0; i < data.length; i++) { opts.push(data[i]); } + if ($scope.playbook && opts.indexOf($scope.playbook) === -1) { + opts.push($scope.playbook); + } $scope.playbook_options = opts; sync_playbook_select2(); Wait('stop'); @@ -195,10 +206,14 @@ // Detect and alert user to potential SCM status issues checkSCMStatus = function (oldValue, newValue) { - if (oldValue !== newValue && !Empty($scope.project)) { + if ((oldValue !== newValue || (oldValue === undefined && newValue === undefined)) && !Empty($scope.project)) { Rest.setUrl(GetBasePath('projects') + $scope.project + '/'); Rest.get() .then(({data}) => { + $scope.allow_branch_override = data.allow_override; + $scope.allow_playbook_selection = true; + selectPlaybook('force_load'); + var msg; switch (data.status) { case 'failed': @@ -219,6 +234,8 @@ ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to get project ' + $scope.project + '. GET returned status: ' + status }); }); + } else { + $scope.allow_playbook_selection = false; } }; @@ -295,6 +312,7 @@ } data.forks = $scope.forks || 0; data.ask_diff_mode_on_launch = $scope.ask_diff_mode_on_launch ? $scope.ask_diff_mode_on_launch : false; + data.ask_scm_branch_on_launch = $scope.ask_scm_branch_on_launch ? $scope.ask_scm_branch_on_launch : false; data.ask_tags_on_launch = $scope.ask_tags_on_launch ? $scope.ask_tags_on_launch : false; data.ask_skip_tags_on_launch = $scope.ask_skip_tags_on_launch ? $scope.ask_skip_tags_on_launch : false; data.ask_limit_on_launch = $scope.ask_limit_on_launch ? $scope.ask_limit_on_launch : false; diff --git a/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js b/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js index 8280801ab8..53d73eee91 100644 --- a/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js +++ b/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js @@ -104,7 +104,11 @@ export default playbookNotFound = false; } } + if ($scope.playbook && $scope.playbook_options.indexOf($scope.playbook) === -1) { + $scope.playbook_options.push($scope.playbook); + } $scope.playbookNotFound = playbookNotFound; + $scope.allow_playbook_selection = true; sync_playbook_select2(); if ($scope.playbook) { jobTemplateLoadFinished(); @@ -125,6 +129,7 @@ export default Rest.setUrl(GetBasePath('projects') + $scope.project + '/'); promises.push(Rest.get() .then(({data}) => { + $scope.allow_branch_override = data.allow_override; var msg; switch (data.status) { case 'failed': @@ -177,7 +182,11 @@ export default function sync_playbook_select2() { select2LoadDefer.push(CreateSelect2({ element:'#playbook-select', - multiple: false + addNew: true, + multiple: false, + scope: $scope, + options: 'playbook_options', + model: 'playbook' })); } @@ -377,6 +386,9 @@ export default $scope.ask_diff_mode_on_launch = (jobTemplateData.ask_diff_mode_on_launch) ? true : false; master.ask_diff_mode_on_launch = $scope.ask_diff_mode_on_launch; + $scope.ask_scm_branch_on_launch = (jobTemplateData.ask_scm_branch_on_launch) ? true : false; + master.ask_scm_branch_on_launch = $scope.ask_scm_branch_on_launch; + $scope.job_tag_options = (jobTemplateData.job_tags) ? jobTemplateData.job_tags.split(',') .map((i) => ({name: i, label: i, value: i})) : []; $scope.job_tags = $scope.job_tag_options; @@ -656,7 +668,8 @@ export default else { if (fld !== 'extra_vars' && fld !== 'survey' && - fld !== 'forks') { + fld !== 'forks' && + (fld === 'scm_branch' && $scope.allow_branch_override)) { data[fld] = $scope[fld]; } } @@ -664,6 +677,7 @@ export default data.forks = $scope.forks || 0; data.ask_diff_mode_on_launch = $scope.ask_diff_mode_on_launch ? $scope.ask_diff_mode_on_launch : false; + data.ask_scm_branch_on_launch = $scope.ask_scm_branch_on_launch && $scope.allow_branch_override ? $scope.ask_scm_branch_on_launch : false; data.ask_tags_on_launch = $scope.ask_tags_on_launch ? $scope.ask_tags_on_launch : false; data.ask_skip_tags_on_launch = $scope.ask_skip_tags_on_launch ? $scope.ask_skip_tags_on_launch : false; data.ask_limit_on_launch = $scope.ask_limit_on_launch ? $scope.ask_limit_on_launch : false; diff --git a/awx/ui/client/src/templates/job_templates/job-template.form.js b/awx/ui/client/src/templates/job_templates/job-template.form.js index e8e70f17ff..44d178157a 100644 --- a/awx/ui/client/src/templates/job_templates/job-template.form.js +++ b/awx/ui/client/src/templates/job_templates/job-template.form.js @@ -103,15 +103,34 @@ function(NotificationsList, i18n) { ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate) || !canGetAllRelatedResources', awLookupWhen: 'canGetAllRelatedResources' }, + scm_branch: { + label: i18n._('SCM Branch'), + type: 'text', + ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)', + ngShow: 'allow_branch_override', + column: 1, + awPopOver: "" + i18n._("Branch to use in job run. Project default used if blank.") + "
", + dataTitle: i18n._('Project'), + subCheckbox: { + variable: 'ask_scm_branch_on_launch', + text: i18n._('Prompt on launch'), + ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' + }, + dataPlacement: 'right', + dataContainer: "body" + }, playbook: { label: i18n._('Playbook'), type:'select', + defaultText: i18n._('Choose a playbook'), ngOptions: 'book for book in playbook_options track by book', + ngShow: 'allow_playbook_selection', ngDisabled: "!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate) || !canGetAllRelatedResources", id: 'playbook-select', required: true, column: 1, - awPopOver: "" + i18n._("Select the playbook to be executed by this job.") + "
", + awPopOver: "" + i18n._("Select the playbook to be executed by this job." + + "You can select from the dropdown or enter a file within the input.") + "
", dataTitle: i18n._('Playbook'), dataPlacement: 'right', dataContainer: "body", diff --git a/awx/ui/client/src/templates/prompt/prompt.controller.js b/awx/ui/client/src/templates/prompt/prompt.controller.js index 60da76a641..d97b91681b 100644 --- a/awx/ui/client/src/templates/prompt/prompt.controller.js +++ b/awx/ui/client/src/templates/prompt/prompt.controller.js @@ -157,7 +157,7 @@ export default [ 'ProcessErrors', 'CredentialTypeModel', 'TemplatesStrings', '$f activeTab = activeTab || vm.steps.credential.tab; order++; } - if(vm.promptDataClone.launchConf.ask_verbosity_on_launch || vm.promptDataClone.launchConf.ask_job_type_on_launch || vm.promptDataClone.launchConf.ask_limit_on_launch || vm.promptDataClone.launchConf.ask_tags_on_launch || vm.promptDataClone.launchConf.ask_skip_tags_on_launch || (vm.promptDataClone.launchConf.ask_variables_on_launch && !vm.promptDataClone.launchConf.ignore_ask_variables) || vm.promptDataClone.launchConf.ask_diff_mode_on_launch) { + if(vm.promptDataClone.launchConf.ask_verbosity_on_launch || vm.promptDataClone.launchConf.ask_job_type_on_launch || vm.promptDataClone.launchConf.ask_limit_on_launch || vm.promptDataClone.launchConf.ask_tags_on_launch || vm.promptDataClone.launchConf.ask_skip_tags_on_launch || (vm.promptDataClone.launchConf.ask_variables_on_launch && !vm.promptDataClone.launchConf.ignore_ask_variables) || vm.promptDataClone.launchConf.ask_diff_mode_on_launch || vm.promptDataClone.launchConf.ask_scm_branch_on_launch) { vm.steps.other_prompts.includeStep = true; vm.steps.other_prompts.tab = { _active: order === 1 ? true : false, diff --git a/awx/ui/client/src/templates/prompt/prompt.service.js b/awx/ui/client/src/templates/prompt/prompt.service.js index d7fbe60519..338a3ff128 100644 --- a/awx/ui/client/src/templates/prompt/prompt.service.js +++ b/awx/ui/client/src/templates/prompt/prompt.service.js @@ -10,7 +10,8 @@ function PromptService (Empty, $filter) { limit: {}, tags: {}, skipTags: {}, - diffMode: {} + diffMode: {}, + scmBranch: {} }; prompts.credentials.value = _.has(params, 'launchConf.defaults.credentials') ? _.cloneDeep(params.launchConf.defaults.credentials) : []; @@ -41,7 +42,7 @@ function PromptService (Empty, $filter) { prompts.tags.value = (jobTags && jobTags !== "") ? jobTags.split(',').map((i) => ({name: i, label: i, value: i})) : []; prompts.skipTags.value = (skipTags && skipTags !== "") ? skipTags.split(',').map((i) => ({name: i, label: i, value: i})) : []; prompts.diffMode.value = _.has(params, 'currentValues.diff_mode') && typeof params.currentValues.diff_mode === 'boolean' ? params.currentValues.diff_mode : (_.has(params, 'launchConf.defaults.diff_mode') ? params.launchConf.defaults.diff_mode : null); - + prompts.scmBranch.value = _.has(params, 'currentValues.scm_branch') && params.currentValues.scm_branch ? params.currentValues.scm_branch : (_.has(params, 'launchConf.defaults.scm_branch') ? params.launchConf.defaults.scm_branch : ""); return prompts; }; @@ -163,6 +164,9 @@ function PromptService (Empty, $filter) { if (promptData.launchConf.ask_diff_mode_on_launch && _.has(promptData, 'prompts.diffMode.value')) { launchData.diff_mode = promptData.prompts.diffMode.value; } + if (promptData.launchConf.ask_scm_branch_on_launch && _.has(promptData, 'prompts.scmBranch.value')) { + launchData.scm_branch = promptData.prompts.scmBranch.value; + } if (promptData.prompts.credentials.passwords) { _.forOwn(promptData.prompts.credentials.passwords, (val, key) => { if (!launchData.credential_passwords) { @@ -277,7 +281,9 @@ function PromptService (Empty, $filter) { if(_.has(params, 'promptData.prompts.diffMode.value') && _.get(params, 'promptData.launchConf.ask_diff_mode_on_launch')){ promptDataToSave.diff_mode = launchConfDefaults.diff_mode && launchConfDefaults.diff_mode === params.promptData.prompts.diffMode.value ? null : params.promptData.prompts.diffMode.value; } - + if(_.has(params, 'promptData.prompts.scmBranch.value') && _.get(params, 'promptData.launchConf.ask_scm_branch_on_launch')){ + promptDataToSave.scm_branch = launchConfDefaults.scm_branch && launchConfDefaults.scm_branch === params.promptData.prompts.scmBranch.value ? null : params.promptData.prompts.scmBranch.value; + } return promptDataToSave; }; } diff --git a/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.partial.html b/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.partial.html index ca57599137..941582ee7e 100644 --- a/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.partial.html +++ b/awx/ui/client/src/templates/prompt/steps/other-prompts/prompt-other-prompts.partial.html @@ -22,6 +22,22 @@