Add scm_branch to inventory source and inventory update

add scm_branch as optional field awxkit
This commit is contained in:
Seth Foster 2023-03-02 19:29:00 -05:00
parent 7cca6c4cd9
commit a952ab0a75
7 changed files with 61 additions and 4 deletions

View File

@ -2000,6 +2000,7 @@ class InventorySourceOptionsSerializer(BaseSerializer):
'source',
'source_path',
'source_vars',
'scm_branch',
'credential',
'enabled_var',
'enabled_value',
@ -2164,10 +2165,14 @@ class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOpt
if ('source' in attrs or 'source_project' in attrs) and get_field_from_model_or_attrs('source_project') is None:
raise serializers.ValidationError({"source_project": _("Project required for scm type sources.")})
else:
redundant_scm_fields = list(filter(lambda x: attrs.get(x, None), ['source_project', 'source_path']))
redundant_scm_fields = list(filter(lambda x: attrs.get(x, None), ['source_project', 'source_path', 'scm_branch']))
if redundant_scm_fields:
raise serializers.ValidationError({"detail": _("Cannot set %s if not SCM type." % ' '.join(redundant_scm_fields))})
project = get_field_from_model_or_attrs('source_project')
if get_field_from_model_or_attrs('scm_branch') and not project.allow_override:
raise serializers.ValidationError({'scm_branch': _('Project does not allow overriding branch.')})
attrs = super(InventorySourceSerializer, self).validate(attrs)
# Check type consistency of source and cloud credential, if provided

View File

@ -0,0 +1,32 @@
# Generated by Django 3.2.16 on 2023-03-03 20:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0174_ensure_org_ee_admin_roles'),
]
operations = [
migrations.AddField(
model_name='inventorysource',
name='scm_branch',
field=models.CharField(
blank=True,
default='',
help_text='Inventory source SCM branch. Project default used if blank. Only allowed if project allow_override field is set to true.',
max_length=1024,
),
),
migrations.AddField(
model_name='inventoryupdate',
name='scm_branch',
field=models.CharField(
blank=True,
default='',
help_text='Inventory source SCM branch. Project default used if blank. Only allowed if project allow_override field is set to true.',
max_length=1024,
),
),
]

View File

@ -872,6 +872,12 @@ class InventorySourceOptions(BaseModel):
default='',
help_text=_('Inventory source variables in YAML or JSON format.'),
)
scm_branch = models.CharField(
max_length=1024,
default='',
blank=True,
help_text=_('Inventory source SCM branch. Project default used if blank. Only allowed if project allow_override field is set to true.'),
)
enabled_var = models.TextField(
blank=True,
default='',

View File

@ -759,7 +759,7 @@ class SourceControlMixin(BaseTask):
def sync_and_copy(self, project, private_data_dir, scm_branch=None):
self.acquire_lock(project, self.instance.id)
is_commit = False
try:
original_branch = None
failed_reason = project.get_reason_if_failed()
@ -771,6 +771,7 @@ class SourceControlMixin(BaseTask):
if os.path.exists(project_path):
git_repo = git.Repo(project_path)
if git_repo.head.is_detached:
is_commit = True
original_branch = git_repo.head.commit
else:
original_branch = git_repo.active_branch
@ -782,7 +783,11 @@ class SourceControlMixin(BaseTask):
# for git project syncs, non-default branches can be problems
# restore to branch the repo was on before this run
try:
original_branch.checkout()
if is_commit:
git_repo.head.set_commit(original_branch)
git_repo.head.reset(index=True, working_tree=True)
else:
original_branch.checkout()
except Exception:
# this could have failed due to dirty tree, but difficult to predict all cases
logger.exception(f'Failed to restore project repo to prior state after {self.instance.id}')
@ -1581,7 +1586,7 @@ class RunInventoryUpdate(SourceControlMixin, BaseTask):
if inventory_update.source == 'scm':
if not source_project:
raise RuntimeError('Could not find project to run SCM inventory update from.')
self.sync_and_copy(source_project, private_data_dir)
self.sync_and_copy(source_project, private_data_dir, scm_branch=inventory_update.inventory_source.scm_branch)
else:
# If source is not SCM make an empty project directory, content is built inside inventory folder
super(RunInventoryUpdate, self).build_project_dir(inventory_update, private_data_dir)

View File

@ -105,6 +105,11 @@ options:
description:
- Project to use as source with scm option
type: str
scm_branch:
description:
- Inventory source SCM branch.
- Project must have branch override enabled.
type: str
state:
description:
- Desired state of the resource.
@ -178,6 +183,7 @@ def main():
update_on_launch=dict(type='bool'),
update_cache_timeout=dict(type='int'),
source_project=dict(),
scm_branch=dict(type='str'),
notification_templates_started=dict(type="list", elements='str'),
notification_templates_success=dict(type="list", elements='str'),
notification_templates_error=dict(type="list", elements='str'),
@ -272,6 +278,7 @@ def main():
'enabled_var',
'enabled_value',
'host_filter',
'scm_branch',
)
# Layer in all remaining optional information

View File

@ -112,6 +112,7 @@ def test_falsy_value(run_module, admin_user, base_inventory):
# credential ? ? o o r r r r r r r o
# source_project ? ? r - - - - - - - - -
# source_path ? ? r - - - - - - - - -
# scm_branch ? ? r - - - - - - - - -
# verbosity ? ? o o o o o o o o o o
# overwrite ? ? o o o o o o o o o o
# overwrite_vars ? ? o o o o o o o o o o

View File

@ -319,6 +319,7 @@ class InventorySource(HasCreate, HasNotifications, UnifiedJobTemplate):
optional_fields = (
'source_path',
'source_vars',
'scm_branch',
'timeout',
'overwrite',
'overwrite_vars',