diff --git a/lib/ansible/modules/windows/win_psrepository_info.ps1 b/lib/ansible/modules/windows/win_psrepository_info.ps1 new file mode 100644 index 00000000000..93e3585bef2 --- /dev/null +++ b/lib/ansible/modules/windows/win_psrepository_info.ps1 @@ -0,0 +1,68 @@ +#!powershell + +# Copyright: (c) 2020, Brian Scholer <@briantist> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#AnsibleRequires -CSharpUtil Ansible.Basic +#Requires -Module Ansible.ModuleUtils.CamelConversion +#Requires -Module PowerShellGet + +$spec = @{ + options = @{ + name = @{ type = 'str' ; default = '*' } + } + supports_check_mode = $true +} +$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) + +function Convert-ObjectToSnakeCase { + <# + .SYNOPSIS + Converts an object with CamelCase properties to a dictionary with snake_case keys. + Works in the spirit of and depends on the existing CamelConversion module util. + #> + [CmdletBinding()] + param( + [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [OutputType([System.Collections.Specialized.OrderedDictionary])] + [Object] + $InputObject , + + [Parameter()] + [Switch] + $NoRecurse , + + [Parameter()] + [Switch] + $OmitNull + ) + + Process { + $result = [Ordered]@{} + foreach ($property in $InputObject.PSObject.Properties) { + $value = $property.Value + if (-not $NoRecurse -and $value -is [System.Collections.IDictionary]) { + $value = Convert-DictToSnakeCase -dict $value + } + elseif (-not $NoRecurse -and ($value -is [Array] -or $value -is [System.Collections.ArrayList])) { + $value = Convert-ListToSnakeCase -list $value + } + elseif ($null -eq $value) { + if ($OmitNull) { + continue + } + } + elseif (-not $NoRecurse -and $value -isnot [System.ValueType] -and $value -isnot [string]) { + $value = Convert-ObjectToSnakeCase -InputObject $value + } + + $name = Convert-StringToSnakeCase -string $property.Name + $result[$name] = $value + } + $result + } +} + +$module.Result.repositories = @(Get-PSRepository -Name $module.Params.name | Convert-ObjectToSnakeCase) + +$module.ExitJson() diff --git a/lib/ansible/modules/windows/win_psrepository_info.py b/lib/ansible/modules/windows/win_psrepository_info.py new file mode 100644 index 00000000000..1bcbee1bb5a --- /dev/null +++ b/lib/ansible/modules/windows/win_psrepository_info.py @@ -0,0 +1,112 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2020, Brian Scholer <@briantist> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = r''' +--- +module: win_psrepository_info +version_added: '2.10' +short_description: Gather information about PSRepositories +description: + - Gather information about all or a specific PSRepository. +options: + name: + description: + - The name of the repository to retrieve. + - Supports any wildcard pattern supported by C(Get-PSRepository). + - If omitted then all repositories will returned. + type: str + default: '*' +requirements: + - C(PowerShellGet) module +seealso: + - module: win_psrepository +author: + - Brian Scholer (@briantist) +''' + +EXAMPLES = r''' +- name: Get info for a single repository + win_psrepository_info: + name: PSGallery + register: repo_info + +- name: Find all repositories that start with 'MyCompany' + win_psrepository_info: + name: MyCompany* + +- name: Get info for all repositories + win_psrepository_info: + register: repo_info + +- name: Remove all repositories that don't have a publish_location set + win_psrepository: + name: "{{ item }}" + state: absent + loop: "{{ repo_info.repositories | rejectattr('publish_location', 'none') | list }}" +''' + +RETURN = r''' +repositories: + description: + - A list of repositories (or an empty list is there are none). + returned: always + type: list + elements: dict + contains: + name: + description: + - The name of the repository. + type: str + sample: PSGallery + installation_policy: + description: + - The installation policy of the repository. The sample values are the only possible values. + type: str + sample: + - Trusted + - Untrusted + trusted: + description: + - A boolean flag reflecting the value of C(installation_policy) as to whether the repository is trusted. + type: bool + package_management_provider: + description: + - The name of the package management provider for this repository. + type: str + sample: NuGet + provider_options: + description: + - Provider-specific options for this repository. + type: dict + source_location: + description: + - The location used to find and retrieve modules. This should always have a value. + type: str + sample: https://www.powershellgallery.com/api/v2 + publish_location: + description: + - The location used to publish modules. + type: str + sample: https://www.powershellgallery.com/api/v2/package/ + script_source_location: + description: + - The location used to find and retrieve scripts. + type: str + sample: https://www.powershellgallery.com/api/v2/items/psscript + script_publish_location: + description: + - The location used to publish scripts. + type: str + sample: https://www.powershellgallery.com/api/v2/package/ + registered: + description: + - Whether the module is registered. Should always be C(True) + type: bool +''' diff --git a/test/integration/targets/win_psrepository_info/aliases b/test/integration/targets/win_psrepository_info/aliases new file mode 100644 index 00000000000..423ce391085 --- /dev/null +++ b/test/integration/targets/win_psrepository_info/aliases @@ -0,0 +1 @@ +shippable/windows/group2 diff --git a/test/integration/targets/win_psrepository_info/defaults/main.yml b/test/integration/targets/win_psrepository_info/defaults/main.yml new file mode 100644 index 00000000000..e0270798759 --- /dev/null +++ b/test/integration/targets/win_psrepository_info/defaults/main.yml @@ -0,0 +1,10 @@ +--- +run_check_mode: False +suffix: "{{ '(check mode)' if run_check_mode else '' }}" +default_repository_name: PSGallery + +second_repository_name: PowerShellGetDemo +second_repository_source_location: https://www.myget.org/F/powershellgetdemo/api/v2 + +third_repository_name: OtherRepo +third_repository_source_location: http://httpbin.org/get diff --git a/test/integration/targets/win_psrepository_info/meta/main.yml b/test/integration/targets/win_psrepository_info/meta/main.yml new file mode 100644 index 00000000000..504d9eb7707 --- /dev/null +++ b/test/integration/targets/win_psrepository_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - setup_win_psget diff --git a/test/integration/targets/win_psrepository_info/tasks/contains_all_fields.yml b/test/integration/targets/win_psrepository_info/tasks/contains_all_fields.yml new file mode 100644 index 00000000000..6f3e6f50094 --- /dev/null +++ b/test/integration/targets/win_psrepository_info/tasks/contains_all_fields.yml @@ -0,0 +1,21 @@ +# This file is part of Ansible + +# Copyright: (c) 2020, Brian Scholer <@briantist> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Check for key ('{{ key }}') in result + assert: + that: key in dict_to_check + loop_control: + loop_var: key + loop: + - name + - installation_policy + - package_management_provider + - provider_options + - publish_location + - source_location + - script_source_location + - script_publish_location + - registered + - trusted diff --git a/test/integration/targets/win_psrepository_info/tasks/empty.yml b/test/integration/targets/win_psrepository_info/tasks/empty.yml new file mode 100644 index 00000000000..9bc6d4c644a --- /dev/null +++ b/test/integration/targets/win_psrepository_info/tasks/empty.yml @@ -0,0 +1,19 @@ +# This file is part of Ansible + +# Copyright: (c) 2020, Brian Scholer <@briantist> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Tests against the empty set of repositories + block: + - name: Get repository info {{ suffix }} + win_psrepository_info: + register: repo_info + + - name: Assert that the correct structure is returned {{ suffix }} + assert: + that: + - repo_info.repositories is defined + - repo_info.repositories is sequence() + - repo_info.repositories | length == 0 + # block + check_mode: "{{ run_check_mode }}" diff --git a/test/integration/targets/win_psrepository_info/tasks/main.yml b/test/integration/targets/win_psrepository_info/tasks/main.yml new file mode 100644 index 00000000000..8e92dc63212 --- /dev/null +++ b/test/integration/targets/win_psrepository_info/tasks/main.yml @@ -0,0 +1,51 @@ +# This file is part of Ansible + +# Copyright: (c) 2020, Brian Scholer <@briantist> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Unregister all repositories + win_shell: | + Get-PSRepository | Unregister-PSRepository + +- block: + - name: Run Empty Tests + import_tasks: empty.yml + + - name: Run Empty Tests (check mode) + import_tasks: empty.yml + vars: + run_check_mode: True + + - name: Add the default repository + win_shell: | + Register-PSRepository -Default + + - name: Single Repository Tests + import_tasks: single.yml + + - name: Single Repository Tests (check mode) + import_tasks: single.yml + vars: + run_check_mode: True + + - name: Add two more repositories + win_shell: | + Register-PSRepository -Name '{{ second_repository_name }}' -SourceLocation '{{ second_repository_source_location }}' + Register-PSRepository -Name '{{ third_repository_name }}' -SourceLocation '{{ third_repository_source_location }}' + + - name: Multi Repository Tests + import_tasks: multiple.yml + + - name: Multi Repository Tests (check mode) + import_tasks: multiple.yml + vars: + run_check_mode: True + + always: + - name: Unregister all repositories + win_shell: | + Get-PSRepository | Unregister-PSRepository + + - name: Ensure only the default repository remains + win_shell: | + Register-PSRepository -Default diff --git a/test/integration/targets/win_psrepository_info/tasks/multiple.yml b/test/integration/targets/win_psrepository_info/tasks/multiple.yml new file mode 100644 index 00000000000..8c5b986e7a2 --- /dev/null +++ b/test/integration/targets/win_psrepository_info/tasks/multiple.yml @@ -0,0 +1,37 @@ +# This file is part of Ansible + +# Copyright: (c) 2020, Brian Scholer <@briantist> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Tests against mutiple repositories + block: + - name: Get all repository info {{ suffix }} + win_psrepository_info: + register: repo_info + + - name: Assert that the correct structure is returned {{ suffix }} + assert: + that: + - repo_info.repositories is defined + - repo_info.repositories is sequence() + - repo_info.repositories | length == 3 + + - include_tasks: contains_all_fields.yml + vars: + dict_to_check: "{{ item }}" + loop: "{{ repo_info.repositories }}" + + - name: Get two repositories with a filter {{ suffix }} + win_psrepository_info: + name: P* + register: repo_info + + - name: Assert that the correct two repositories were returned {{ suffix }} + assert: + that: + - repo_info.repositories | length == 2 + - default_repository_name in (repo_info.repositories | map(attribute='name') | list) + - second_repository_name in (repo_info.repositories | map(attribute='name') | list) + + # block + check_mode: "{{ run_check_mode }}" diff --git a/test/integration/targets/win_psrepository_info/tasks/single.yml b/test/integration/targets/win_psrepository_info/tasks/single.yml new file mode 100644 index 00000000000..00071ec556a --- /dev/null +++ b/test/integration/targets/win_psrepository_info/tasks/single.yml @@ -0,0 +1,26 @@ +# This file is part of Ansible + +# Copyright: (c) 2020, Brian Scholer <@briantist> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Tests against a single repository ({{ default_repository_name }}) + block: + - name: Get repository info {{ suffix }} + win_psrepository_info: + name: "{{ default_repository_name }}" + register: repo_info + + - name: Assert that the correct structure is returned {{ suffix }} + assert: + that: + - repo_info.repositories is defined + - repo_info.repositories is sequence() + - repo_info.repositories | length == 1 + - repo_info.repositories[0].name == default_repository_name + + - include_tasks: contains_all_fields.yml + vars: + dict_to_check: "{{ repo_info.repositories[0] }}" + + # block + check_mode: "{{ run_check_mode }}"