Support role shorthand in include/import tasks

This commit is contained in:
Virgil 2026-04-02 02:57:51 +00:00
parent 1fa2b78fed
commit c5712c696d
5 changed files with 59 additions and 91 deletions

View file

@ -1708,31 +1708,27 @@ func (e *Executor) resolveIncludeRoleRef(host string, task *Task) *RoleRef {
return nil
}
var roleName, tasksFrom, defaultsFrom, varsFrom string
var handlersFrom string
var roleVars map[string]any
var apply *TaskApply
var ref *RoleRef
if task.IncludeRole != nil {
roleName = task.IncludeRole.Name
tasksFrom = task.IncludeRole.TasksFrom
defaultsFrom = task.IncludeRole.DefaultsFrom
varsFrom = task.IncludeRole.VarsFrom
handlersFrom = task.IncludeRole.HandlersFrom
roleVars = task.IncludeRole.Vars
apply = task.IncludeRole.Apply
ref = task.IncludeRole
} else if task.ImportRole != nil {
roleName = task.ImportRole.Name
tasksFrom = task.ImportRole.TasksFrom
defaultsFrom = task.ImportRole.DefaultsFrom
varsFrom = task.ImportRole.VarsFrom
handlersFrom = task.ImportRole.HandlersFrom
roleVars = task.ImportRole.Vars
apply = task.ImportRole.Apply
ref = task.ImportRole
} else {
return nil
}
roleName := ref.Role
if roleName == "" {
roleName = ref.Name
}
tasksFrom := ref.TasksFrom
defaultsFrom := ref.DefaultsFrom
varsFrom := ref.VarsFrom
handlersFrom := ref.HandlersFrom
roleVars := ref.Vars
apply := ref.Apply
renderedVars := mergeTaskVars(roleVars, task.Vars)
if len(renderedVars) > 0 {
renderedVars = e.templateArgs(renderedVars, host, task)
@ -1746,7 +1742,7 @@ func (e *Executor) resolveIncludeRoleRef(host string, task *Task) *RoleRef {
HandlersFrom: e.templateString(handlersFrom, host, task),
Vars: renderedVars,
Apply: apply,
Public: task.IncludeRole != nil && task.IncludeRole.Public || task.ImportRole != nil && task.ImportRole.Public,
Public: ref.Public,
When: task.When,
Tags: task.Tags,
}

View file

@ -819,17 +819,8 @@ func TestExecutorExtra_RunIncludeRole_Good_InheritsTaskVars(t *testing.T) {
require.NoError(t, e.runTaskOnHosts(context.Background(), []string{"localhost"}, &Task{
Name: "Load role",
IncludeRole: &struct {
Name string `yaml:"name"`
TasksFrom string `yaml:"tasks_from,omitempty"`
DefaultsFrom string `yaml:"defaults_from,omitempty"`
VarsFrom string `yaml:"vars_from,omitempty"`
HandlersFrom string `yaml:"handlers_from,omitempty"`
Vars map[string]any `yaml:"vars,omitempty"`
Apply *TaskApply `yaml:"apply,omitempty"`
Public bool `yaml:"public,omitempty"`
}{
Name: "demo",
IncludeRole: &RoleRef{
Role: "demo",
},
Vars: map[string]any{"role_message": "hello from role"},
}, play))
@ -874,17 +865,8 @@ func TestExecutorExtra_RunIncludeRole_Good_AppliesRoleDefaults(t *testing.T) {
// Re-run with callback attached so we can inspect the merged task state.
require.NoError(t, e.runTaskOnHosts(context.Background(), []string{"localhost"}, &Task{
Name: "Load role with apply",
IncludeRole: &struct {
Name string `yaml:"name"`
TasksFrom string `yaml:"tasks_from,omitempty"`
DefaultsFrom string `yaml:"defaults_from,omitempty"`
VarsFrom string `yaml:"vars_from,omitempty"`
HandlersFrom string `yaml:"handlers_from,omitempty"`
Vars map[string]any `yaml:"vars,omitempty"`
Apply *TaskApply `yaml:"apply,omitempty"`
Public bool `yaml:"public,omitempty"`
}{
Name: "app",
IncludeRole: &RoleRef{
Role: "app",
Apply: &TaskApply{
Tags: []string{"role-apply"},
Vars: map[string]any{
@ -933,17 +915,8 @@ func TestExecutorExtra_RunIncludeRole_Good_PublicVarsPersist(t *testing.T) {
Tasks: []Task{
{
Name: "Load public role",
IncludeRole: &struct {
Name string `yaml:"name"`
TasksFrom string `yaml:"tasks_from,omitempty"`
DefaultsFrom string `yaml:"defaults_from,omitempty"`
VarsFrom string `yaml:"vars_from,omitempty"`
HandlersFrom string `yaml:"handlers_from,omitempty"`
Vars map[string]any `yaml:"vars,omitempty"`
Apply *TaskApply `yaml:"apply,omitempty"`
Public bool `yaml:"public,omitempty"`
}{
Name: "shared",
IncludeRole: &RoleRef{
Role: "shared",
Public: true,
},
Vars: map[string]any{"shared_message": "hello from public role"},

View file

@ -656,17 +656,8 @@ func TestExecutor_RunIncludeRole_Good_TemplatesRoleName(t *testing.T) {
}
err := e.runIncludeRole(context.Background(), []string{"localhost"}, &Task{
IncludeRole: &struct {
Name string `yaml:"name"`
TasksFrom string `yaml:"tasks_from,omitempty"`
DefaultsFrom string `yaml:"defaults_from,omitempty"`
VarsFrom string `yaml:"vars_from,omitempty"`
HandlersFrom string `yaml:"handlers_from,omitempty"`
Vars map[string]any `yaml:"vars,omitempty"`
Apply *TaskApply `yaml:"apply,omitempty"`
Public bool `yaml:"public,omitempty"`
}{
Name: "{{ role_name }}",
IncludeRole: &RoleRef{
Role: "{{ role_name }}",
},
}, &Play{})
require.NoError(t, err)

View file

@ -122,33 +122,15 @@ type Task struct {
Until string `yaml:"until,omitempty"`
// Include/import directives
IncludeTasks string `yaml:"include_tasks,omitempty"`
ImportTasks string `yaml:"import_tasks,omitempty"`
WithFile any `yaml:"with_file,omitempty"`
WithFileGlob any `yaml:"with_fileglob,omitempty"`
WithSequence any `yaml:"with_sequence,omitempty"`
WithTogether any `yaml:"with_together,omitempty"`
WithSubelements any `yaml:"with_subelements,omitempty"`
IncludeRole *struct {
Name string `yaml:"name"`
TasksFrom string `yaml:"tasks_from,omitempty"`
DefaultsFrom string `yaml:"defaults_from,omitempty"`
VarsFrom string `yaml:"vars_from,omitempty"`
HandlersFrom string `yaml:"handlers_from,omitempty"`
Vars map[string]any `yaml:"vars,omitempty"`
Apply *TaskApply `yaml:"apply,omitempty"`
Public bool `yaml:"public,omitempty"`
} `yaml:"include_role,omitempty"`
ImportRole *struct {
Name string `yaml:"name"`
TasksFrom string `yaml:"tasks_from,omitempty"`
DefaultsFrom string `yaml:"defaults_from,omitempty"`
VarsFrom string `yaml:"vars_from,omitempty"`
HandlersFrom string `yaml:"handlers_from,omitempty"`
Vars map[string]any `yaml:"vars,omitempty"`
Apply *TaskApply `yaml:"apply,omitempty"`
Public bool `yaml:"public,omitempty"`
} `yaml:"import_role,omitempty"`
IncludeTasks string `yaml:"include_tasks,omitempty"`
ImportTasks string `yaml:"import_tasks,omitempty"`
WithFile any `yaml:"with_file,omitempty"`
WithFileGlob any `yaml:"with_fileglob,omitempty"`
WithSequence any `yaml:"with_sequence,omitempty"`
WithTogether any `yaml:"with_together,omitempty"`
WithSubelements any `yaml:"with_subelements,omitempty"`
IncludeRole *RoleRef `yaml:"include_role,omitempty"`
ImportRole *RoleRef `yaml:"import_role,omitempty"`
// Raw YAML for module extraction
raw map[string]any

View file

@ -611,6 +611,32 @@ include_role:
assert.Equal(t, "production", task.IncludeRole.Apply.Environment["APP_ENV"])
}
func TestTypes_Task_UnmarshalYAML_Good_IncludeRoleStringForm(t *testing.T) {
input := `
name: Include role
include_role: common
`
var task Task
err := yaml.Unmarshal([]byte(input), &task)
require.NoError(t, err)
require.NotNil(t, task.IncludeRole)
assert.Equal(t, "common", task.IncludeRole.Role)
}
func TestTypes_Task_UnmarshalYAML_Good_ImportRoleStringForm(t *testing.T) {
input := `
name: Import role
import_role: common
`
var task Task
err := yaml.Unmarshal([]byte(input), &task)
require.NoError(t, err)
require.NotNil(t, task.ImportRole)
assert.Equal(t, "common", task.ImportRole.Role)
}
func TestTypes_Task_UnmarshalYAML_Good_BecomeFields(t *testing.T) {
input := `
name: Privileged task