mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-19 11:20:22 -07:00
Initial commit
This commit is contained in:
commit
aebc1b03fd
4861 changed files with 812621 additions and 0 deletions
333
plugins/modules/source_control/github/github_deploy_key.py
Normal file
333
plugins/modules/source_control/github/github_deploy_key.py
Normal file
|
@ -0,0 +1,333 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: github_deploy_key
|
||||
author: "Ali (@bincyber)"
|
||||
short_description: Manages deploy keys for GitHub repositories.
|
||||
description:
|
||||
- "Adds or removes deploy keys for GitHub repositories. Supports authentication using username and password,
|
||||
username and password and 2-factor authentication code (OTP), OAuth2 token, or personal access token. Admin
|
||||
rights on the repository are required."
|
||||
options:
|
||||
github_url:
|
||||
description:
|
||||
- The base URL of the GitHub API
|
||||
required: false
|
||||
type: str
|
||||
default: https://api.github.com
|
||||
owner:
|
||||
description:
|
||||
- The name of the individual account or organization that owns the GitHub repository.
|
||||
required: true
|
||||
aliases: [ 'account', 'organization' ]
|
||||
repo:
|
||||
description:
|
||||
- The name of the GitHub repository.
|
||||
required: true
|
||||
aliases: [ 'repository' ]
|
||||
name:
|
||||
description:
|
||||
- The name for the deploy key.
|
||||
required: true
|
||||
aliases: [ 'title', 'label' ]
|
||||
key:
|
||||
description:
|
||||
- The SSH public key to add to the repository as a deploy key.
|
||||
required: true
|
||||
read_only:
|
||||
description:
|
||||
- If C(true), the deploy key will only be able to read repository contents. Otherwise, the deploy key will be able to read and write.
|
||||
type: bool
|
||||
default: 'yes'
|
||||
state:
|
||||
description:
|
||||
- The state of the deploy key.
|
||||
default: "present"
|
||||
choices: [ "present", "absent" ]
|
||||
force:
|
||||
description:
|
||||
- If C(true), forcefully adds the deploy key by deleting any existing deploy key with the same public key or title.
|
||||
type: bool
|
||||
default: 'no'
|
||||
username:
|
||||
description:
|
||||
- The username to authenticate with. Should not be set when using personal access token
|
||||
password:
|
||||
description:
|
||||
- The password to authenticate with. Alternatively, a personal access token can be used instead of I(username) and I(password) combination.
|
||||
token:
|
||||
description:
|
||||
- The OAuth2 token or personal access token to authenticate with. Mutually exclusive with I(password).
|
||||
otp:
|
||||
description:
|
||||
- The 6 digit One Time Password for 2-Factor Authentication. Required together with I(username) and I(password).
|
||||
aliases: ['2fa_token']
|
||||
notes:
|
||||
- "Refer to GitHub's API documentation here: https://developer.github.com/v3/repos/keys/."
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# add a new read-only deploy key to a GitHub repository using basic authentication
|
||||
- github_deploy_key:
|
||||
owner: "johndoe"
|
||||
repo: "example"
|
||||
name: "new-deploy-key"
|
||||
key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAwXxn7kIMNWzcDfou..."
|
||||
read_only: yes
|
||||
username: "johndoe"
|
||||
password: "supersecretpassword"
|
||||
|
||||
# remove an existing deploy key from a GitHub repository
|
||||
- github_deploy_key:
|
||||
owner: "johndoe"
|
||||
repository: "example"
|
||||
name: "new-deploy-key"
|
||||
key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAwXxn7kIMNWzcDfou..."
|
||||
force: yes
|
||||
username: "johndoe"
|
||||
password: "supersecretpassword"
|
||||
state: absent
|
||||
|
||||
# add a new deploy key to a GitHub repository, replace an existing key, use an OAuth2 token to authenticate
|
||||
- github_deploy_key:
|
||||
owner: "johndoe"
|
||||
repository: "example"
|
||||
name: "new-deploy-key"
|
||||
key: "{{ lookup('file', '~/.ssh/github.pub') }}"
|
||||
force: yes
|
||||
token: "ABAQDAwXxn7kIMNWzcDfo..."
|
||||
|
||||
# re-add a deploy key to a GitHub repository but with a different name
|
||||
- github_deploy_key:
|
||||
owner: "johndoe"
|
||||
repository: "example"
|
||||
name: "replace-deploy-key"
|
||||
key: "{{ lookup('file', '~/.ssh/github.pub') }}"
|
||||
username: "johndoe"
|
||||
password: "supersecretpassword"
|
||||
|
||||
# add a new deploy key to a GitHub repository using 2FA
|
||||
- github_deploy_key:
|
||||
owner: "johndoe"
|
||||
repo: "example"
|
||||
name: "new-deploy-key-2"
|
||||
key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAwXxn7kIMNWzcDfou..."
|
||||
username: "johndoe"
|
||||
password: "supersecretpassword"
|
||||
otp: 123456
|
||||
|
||||
# add a read-only deploy key to a repository hosted on GitHub Enterprise
|
||||
- github_deploy_key:
|
||||
github_url: "https://api.example.com"
|
||||
owner: "janedoe"
|
||||
repo: "example"
|
||||
name: "new-deploy-key"
|
||||
key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAwXxn7kIMNWzcDfou..."
|
||||
read_only: yes
|
||||
username: "janedoe"
|
||||
password: "supersecretpassword"
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: the status message describing what occurred
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Deploy key added successfully"
|
||||
|
||||
http_status_code:
|
||||
description: the HTTP status code returned by the GitHub API
|
||||
returned: failed
|
||||
type: int
|
||||
sample: 400
|
||||
|
||||
error:
|
||||
description: the error message returned by the GitHub API
|
||||
returned: failed
|
||||
type: str
|
||||
sample: "key is already in use"
|
||||
|
||||
id:
|
||||
description: the key identifier assigned by GitHub for the deploy key
|
||||
returned: changed
|
||||
type: int
|
||||
sample: 24381901
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
from re import findall
|
||||
|
||||
|
||||
class GithubDeployKey(object):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
|
||||
self.github_url = self.module.params['github_url']
|
||||
self.name = module.params['name']
|
||||
self.key = module.params['key']
|
||||
self.state = module.params['state']
|
||||
self.read_only = module.params.get('read_only', True)
|
||||
self.force = module.params.get('force', False)
|
||||
self.username = module.params.get('username', None)
|
||||
self.password = module.params.get('password', None)
|
||||
self.token = module.params.get('token', None)
|
||||
self.otp = module.params.get('otp', None)
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
owner = self.module.params['owner']
|
||||
repo = self.module.params['repo']
|
||||
return "{0}/repos/{1}/{2}/keys".format(self.github_url, owner, repo)
|
||||
|
||||
@property
|
||||
def headers(self):
|
||||
if self.username is not None and self.password is not None:
|
||||
self.module.params['url_username'] = self.username
|
||||
self.module.params['url_password'] = self.password
|
||||
self.module.params['force_basic_auth'] = True
|
||||
if self.otp is not None:
|
||||
return {"X-GitHub-OTP": self.otp}
|
||||
elif self.token is not None:
|
||||
return {"Authorization": "token {0}".format(self.token)}
|
||||
else:
|
||||
return None
|
||||
|
||||
def paginate(self, url):
|
||||
while url:
|
||||
resp, info = fetch_url(self.module, url, headers=self.headers, method="GET")
|
||||
|
||||
if info["status"] == 200:
|
||||
yield self.module.from_json(resp.read())
|
||||
|
||||
links = {}
|
||||
for x, y in findall(r'<([^>]+)>;\s*rel="(\w+)"', info["link"]):
|
||||
links[y] = x
|
||||
|
||||
url = links.get('next')
|
||||
else:
|
||||
self.handle_error(method="GET", info=info)
|
||||
|
||||
def get_existing_key(self):
|
||||
for keys in self.paginate(self.url):
|
||||
if keys:
|
||||
for i in keys:
|
||||
existing_key_id = str(i["id"])
|
||||
if i["key"].split() == self.key.split()[:2]:
|
||||
return existing_key_id
|
||||
elif i['title'] == self.name and self.force:
|
||||
return existing_key_id
|
||||
else:
|
||||
return None
|
||||
|
||||
def add_new_key(self):
|
||||
request_body = {"title": self.name, "key": self.key, "read_only": self.read_only}
|
||||
|
||||
resp, info = fetch_url(self.module, self.url, data=self.module.jsonify(request_body), headers=self.headers, method="POST", timeout=30)
|
||||
|
||||
status_code = info["status"]
|
||||
|
||||
if status_code == 201:
|
||||
response_body = self.module.from_json(resp.read())
|
||||
key_id = response_body["id"]
|
||||
self.module.exit_json(changed=True, msg="Deploy key successfully added", id=key_id)
|
||||
elif status_code == 422:
|
||||
self.module.exit_json(changed=False, msg="Deploy key already exists")
|
||||
else:
|
||||
self.handle_error(method="POST", info=info)
|
||||
|
||||
def remove_existing_key(self, key_id):
|
||||
resp, info = fetch_url(self.module, "{0}/{1}".format(self.url, key_id), headers=self.headers, method="DELETE")
|
||||
|
||||
status_code = info["status"]
|
||||
|
||||
if status_code == 204:
|
||||
if self.state == 'absent':
|
||||
self.module.exit_json(changed=True, msg="Deploy key successfully deleted", id=key_id)
|
||||
else:
|
||||
self.handle_error(method="DELETE", info=info, key_id=key_id)
|
||||
|
||||
def handle_error(self, method, info, key_id=None):
|
||||
status_code = info['status']
|
||||
body = info.get('body')
|
||||
if body:
|
||||
err = self.module.from_json(body)['message']
|
||||
|
||||
if status_code == 401:
|
||||
self.module.fail_json(msg="Failed to connect to {0} due to invalid credentials".format(self.github_url), http_status_code=status_code, error=err)
|
||||
elif status_code == 404:
|
||||
self.module.fail_json(msg="GitHub repository does not exist", http_status_code=status_code, error=err)
|
||||
else:
|
||||
if method == "GET":
|
||||
self.module.fail_json(msg="Failed to retrieve existing deploy keys", http_status_code=status_code, error=err)
|
||||
elif method == "POST":
|
||||
self.module.fail_json(msg="Failed to add deploy key", http_status_code=status_code, error=err)
|
||||
elif method == "DELETE":
|
||||
self.module.fail_json(msg="Failed to delete existing deploy key", id=key_id, http_status_code=status_code, error=err)
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
github_url=dict(required=False, type='str', default="https://api.github.com"),
|
||||
owner=dict(required=True, type='str', aliases=['account', 'organization']),
|
||||
repo=dict(required=True, type='str', aliases=['repository']),
|
||||
name=dict(required=True, type='str', aliases=['title', 'label']),
|
||||
key=dict(required=True, type='str'),
|
||||
read_only=dict(required=False, type='bool', default=True),
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
force=dict(required=False, type='bool', default=False),
|
||||
username=dict(required=False, type='str'),
|
||||
password=dict(required=False, type='str', no_log=True),
|
||||
otp=dict(required=False, type='int', aliases=['2fa_token'], no_log=True),
|
||||
token=dict(required=False, type='str', no_log=True)
|
||||
),
|
||||
mutually_exclusive=[
|
||||
['password', 'token']
|
||||
],
|
||||
required_together=[
|
||||
['username', 'password'],
|
||||
['otp', 'username', 'password']
|
||||
],
|
||||
required_one_of=[
|
||||
['username', 'token']
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
deploy_key = GithubDeployKey(module)
|
||||
|
||||
if module.check_mode:
|
||||
key_id = deploy_key.get_existing_key()
|
||||
if deploy_key.state == "present" and key_id is None:
|
||||
module.exit_json(changed=True)
|
||||
elif deploy_key.state == "present" and key_id is not None:
|
||||
module.exit_json(changed=False)
|
||||
|
||||
# to forcefully modify an existing key, the existing key must be deleted first
|
||||
if deploy_key.state == 'absent' or deploy_key.force:
|
||||
key_id = deploy_key.get_existing_key()
|
||||
|
||||
if key_id is not None:
|
||||
deploy_key.remove_existing_key(key_id)
|
||||
elif deploy_key.state == 'absent':
|
||||
module.exit_json(changed=False, msg="Deploy key does not exist")
|
||||
|
||||
if deploy_key.state == "present":
|
||||
deploy_key.add_new_key()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
197
plugins/modules/source_control/github/github_hooks.py
Normal file
197
plugins/modules/source_control/github/github_hooks.py
Normal file
|
@ -0,0 +1,197 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, Phillip Gentry <phillip@cx.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['deprecated'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: github_hooks
|
||||
short_description: Manages GitHub service hooks.
|
||||
deprecated:
|
||||
removed_in: "2.12"
|
||||
why: Replaced by more granular modules
|
||||
alternative: Use M(github_webhook) and M(github_webhook_info) instead.
|
||||
description:
|
||||
- Adds service hooks and removes service hooks that have an error status.
|
||||
options:
|
||||
user:
|
||||
description:
|
||||
- GitHub username.
|
||||
required: true
|
||||
oauthkey:
|
||||
description:
|
||||
- The oauth key provided by GitHub. It can be found/generated on GitHub under "Edit Your Profile" >> "Developer settings" >> "Personal Access Tokens"
|
||||
required: true
|
||||
repo:
|
||||
description:
|
||||
- >
|
||||
This is the API url for the repository you want to manage hooks for. It should be in the form of: https://api.github.com/repos/user:/repo:.
|
||||
Note this is different than the normal repo url.
|
||||
required: true
|
||||
hookurl:
|
||||
description:
|
||||
- When creating a new hook, this is the url that you want GitHub to post to. It is only required when creating a new hook.
|
||||
required: false
|
||||
action:
|
||||
description:
|
||||
- This tells the githooks module what you want it to do.
|
||||
required: true
|
||||
choices: [ "create", "cleanall", "list", "clean504" ]
|
||||
validate_certs:
|
||||
description:
|
||||
- If C(no), SSL certificates for the target repo will not be validated. This should only be used
|
||||
on personally controlled sites using self-signed certificates.
|
||||
required: false
|
||||
default: 'yes'
|
||||
type: bool
|
||||
content_type:
|
||||
description:
|
||||
- Content type to use for requests made to the webhook
|
||||
required: false
|
||||
default: 'json'
|
||||
choices: ['json', 'form']
|
||||
|
||||
author: "Phillip Gentry, CX Inc (@pcgentry)"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Example creating a new service hook. It ignores duplicates.
|
||||
- github_hooks:
|
||||
action: create
|
||||
hookurl: http://11.111.111.111:2222
|
||||
user: '{{ gituser }}'
|
||||
oauthkey: '{{ oauthkey }}'
|
||||
repo: https://api.github.com/repos/pcgentry/Github-Auto-Deploy
|
||||
|
||||
# Cleaning all hooks for this repo that had an error on the last update. Since this works for all hooks in a repo it is probably best that this would
|
||||
# be called from a handler.
|
||||
- github_hooks:
|
||||
action: cleanall
|
||||
user: '{{ gituser }}'
|
||||
oauthkey: '{{ oauthkey }}'
|
||||
repo: '{{ repo }}'
|
||||
delegate_to: localhost
|
||||
'''
|
||||
|
||||
import json
|
||||
import base64
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
from ansible.module_utils._text import to_bytes
|
||||
|
||||
|
||||
def request(module, url, user, oauthkey, data='', method='GET'):
|
||||
auth = base64.b64encode(to_bytes('%s:%s' % (user, oauthkey)).replace('\n', ''))
|
||||
headers = {
|
||||
'Authorization': 'Basic %s' % auth,
|
||||
}
|
||||
response, info = fetch_url(module, url, headers=headers, data=data, method=method)
|
||||
return response, info
|
||||
|
||||
|
||||
def _list(module, oauthkey, repo, user):
|
||||
url = "%s/hooks" % repo
|
||||
response, info = request(module, url, user, oauthkey)
|
||||
if info['status'] != 200:
|
||||
return False, ''
|
||||
else:
|
||||
return False, response.read()
|
||||
|
||||
|
||||
def _clean504(module, oauthkey, repo, user):
|
||||
current_hooks = _list(module, oauthkey, repo, user)[1]
|
||||
decoded = json.loads(current_hooks)
|
||||
|
||||
for hook in decoded:
|
||||
if hook['last_response']['code'] == 504:
|
||||
_delete(module, oauthkey, repo, user, hook['id'])
|
||||
|
||||
return 0, current_hooks
|
||||
|
||||
|
||||
def _cleanall(module, oauthkey, repo, user):
|
||||
current_hooks = _list(module, oauthkey, repo, user)[1]
|
||||
decoded = json.loads(current_hooks)
|
||||
|
||||
for hook in decoded:
|
||||
if hook['last_response']['code'] != 200:
|
||||
_delete(module, oauthkey, repo, user, hook['id'])
|
||||
|
||||
return 0, current_hooks
|
||||
|
||||
|
||||
def _create(module, hookurl, oauthkey, repo, user, content_type):
|
||||
url = "%s/hooks" % repo
|
||||
values = {
|
||||
"active": True,
|
||||
"name": "web",
|
||||
"config": {
|
||||
"url": "%s" % hookurl,
|
||||
"content_type": "%s" % content_type
|
||||
}
|
||||
}
|
||||
data = json.dumps(values)
|
||||
response, info = request(module, url, user, oauthkey, data=data, method='POST')
|
||||
if info['status'] != 200:
|
||||
return 0, '[]'
|
||||
else:
|
||||
return 0, response.read()
|
||||
|
||||
|
||||
def _delete(module, oauthkey, repo, user, hookid):
|
||||
url = "%s/hooks/%s" % (repo, hookid)
|
||||
response, info = request(module, url, user, oauthkey, method='DELETE')
|
||||
return response.read()
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
action=dict(required=True, choices=['list', 'clean504', 'cleanall', 'create']),
|
||||
hookurl=dict(required=False),
|
||||
oauthkey=dict(required=True, no_log=True),
|
||||
repo=dict(required=True),
|
||||
user=dict(required=True),
|
||||
validate_certs=dict(default='yes', type='bool'),
|
||||
content_type=dict(default='json', choices=['json', 'form']),
|
||||
)
|
||||
)
|
||||
|
||||
action = module.params['action']
|
||||
hookurl = module.params['hookurl']
|
||||
oauthkey = module.params['oauthkey']
|
||||
repo = module.params['repo']
|
||||
user = module.params['user']
|
||||
content_type = module.params['content_type']
|
||||
|
||||
if action == "list":
|
||||
(rc, out) = _list(module, oauthkey, repo, user)
|
||||
|
||||
if action == "clean504":
|
||||
(rc, out) = _clean504(module, oauthkey, repo, user)
|
||||
|
||||
if action == "cleanall":
|
||||
(rc, out) = _cleanall(module, oauthkey, repo, user)
|
||||
|
||||
if action == "create":
|
||||
(rc, out) = _create(module, hookurl, oauthkey, repo, user, content_type)
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg="failed", result=out)
|
||||
|
||||
module.exit_json(msg="success", result=out)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
118
plugins/modules/source_control/github/github_issue.py
Normal file
118
plugins/modules/source_control/github/github_issue.py
Normal file
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Copyright: (c) 2017-18, Abhijeet Kasurde <akasurde@redhat.com>
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
module: github_issue
|
||||
short_description: View GitHub issue.
|
||||
description:
|
||||
- View GitHub issue for a given repository and organization.
|
||||
options:
|
||||
repo:
|
||||
description:
|
||||
- Name of repository from which issue needs to be retrieved.
|
||||
required: true
|
||||
organization:
|
||||
description:
|
||||
- Name of the GitHub organization in which the repository is hosted.
|
||||
required: true
|
||||
issue:
|
||||
description:
|
||||
- Issue number for which information is required.
|
||||
required: true
|
||||
action:
|
||||
description:
|
||||
- Get various details about issue depending upon action specified.
|
||||
default: 'get_status'
|
||||
choices:
|
||||
- 'get_status'
|
||||
author:
|
||||
- Abhijeet Kasurde (@Akasurde)
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
get_status:
|
||||
description: State of the GitHub issue
|
||||
type: str
|
||||
returned: success
|
||||
sample: open, closed
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Check if GitHub issue is closed or not
|
||||
github_issue:
|
||||
organization: ansible
|
||||
repo: ansible
|
||||
issue: 23642
|
||||
action: get_status
|
||||
register: r
|
||||
|
||||
- name: Take action depending upon issue status
|
||||
debug:
|
||||
msg: Do something when issue 23642 is open
|
||||
when: r.issue_status == 'open'
|
||||
'''
|
||||
|
||||
import json
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
organization=dict(required=True),
|
||||
repo=dict(required=True),
|
||||
issue=dict(type='int', required=True),
|
||||
action=dict(choices=['get_status'], default='get_status'),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
organization = module.params['organization']
|
||||
repo = module.params['repo']
|
||||
issue = module.params['issue']
|
||||
action = module.params['action']
|
||||
|
||||
result = dict()
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/vnd.github.v3+json',
|
||||
}
|
||||
|
||||
url = "https://api.github.com/repos/%s/%s/issues/%s" % (organization, repo, issue)
|
||||
|
||||
response, info = fetch_url(module, url, headers=headers)
|
||||
if not (200 <= info['status'] < 400):
|
||||
if info['status'] == 404:
|
||||
module.fail_json(msg="Failed to find issue %s" % issue)
|
||||
module.fail_json(msg="Failed to send request to %s: %s" % (url, info['msg']))
|
||||
|
||||
gh_obj = json.loads(response.read())
|
||||
|
||||
if action == 'get_status' or action is None:
|
||||
if module.check_mode:
|
||||
result.update(changed=True)
|
||||
else:
|
||||
result.update(changed=True, issue_status=gh_obj['state'])
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
242
plugins/modules/source_control/github/github_key.py
Normal file
242
plugins/modules/source_control/github/github_key.py
Normal file
|
@ -0,0 +1,242 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Copyright: Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
module: github_key
|
||||
short_description: Manage GitHub access keys.
|
||||
description:
|
||||
- Creates, removes, or updates GitHub access keys.
|
||||
options:
|
||||
token:
|
||||
description:
|
||||
- GitHub Access Token with permission to list and create public keys.
|
||||
required: true
|
||||
name:
|
||||
description:
|
||||
- SSH key name
|
||||
required: true
|
||||
pubkey:
|
||||
description:
|
||||
- SSH public key value. Required when C(state=present).
|
||||
state:
|
||||
description:
|
||||
- Whether to remove a key, ensure that it exists, or update its value.
|
||||
choices: ['present', 'absent']
|
||||
default: 'present'
|
||||
force:
|
||||
description:
|
||||
- The default is C(yes), which will replace the existing remote key
|
||||
if it's different than C(pubkey). If C(no), the key will only be
|
||||
set if no key with the given C(name) exists.
|
||||
type: bool
|
||||
default: 'yes'
|
||||
|
||||
author: Robert Estelle (@erydo)
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
deleted_keys:
|
||||
description: An array of key objects that were deleted. Only present on state=absent
|
||||
type: list
|
||||
returned: When state=absent
|
||||
sample: [{'id': 0, 'key': 'BASE64 encoded key', 'url': 'http://example.com/github key', 'created_at': 'YYYY-MM-DDTHH:MM:SZ', 'read_only': False}]
|
||||
matching_keys:
|
||||
description: An array of keys matching the specified name. Only present on state=present
|
||||
type: list
|
||||
returned: When state=present
|
||||
sample: [{'id': 0, 'key': 'BASE64 encoded key', 'url': 'http://example.com/github key', 'created_at': 'YYYY-MM-DDTHH:MM:SZ', 'read_only': False}]
|
||||
key:
|
||||
description: Metadata about the key just created. Only present on state=present
|
||||
type: dict
|
||||
returned: success
|
||||
sample: {'id': 0, 'key': 'BASE64 encoded key', 'url': 'http://example.com/github key', 'created_at': 'YYYY-MM-DDTHH:MM:SZ', 'read_only': False}
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Read SSH public key to authorize
|
||||
shell: cat /home/foo/.ssh/id_rsa.pub
|
||||
register: ssh_pub_key
|
||||
|
||||
- name: Authorize key with GitHub
|
||||
local_action:
|
||||
module: github_key
|
||||
name: Access Key for Some Machine
|
||||
token: '{{ github_access_token }}'
|
||||
pubkey: '{{ ssh_pub_key.stdout }}'
|
||||
'''
|
||||
|
||||
|
||||
import json
|
||||
import re
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
|
||||
|
||||
API_BASE = 'https://api.github.com'
|
||||
|
||||
|
||||
class GitHubResponse(object):
|
||||
def __init__(self, response, info):
|
||||
self.content = response.read()
|
||||
self.info = info
|
||||
|
||||
def json(self):
|
||||
return json.loads(self.content)
|
||||
|
||||
def links(self):
|
||||
links = {}
|
||||
if 'link' in self.info:
|
||||
link_header = self.info['link']
|
||||
matches = re.findall('<([^>]+)>; rel="([^"]+)"', link_header)
|
||||
for url, rel in matches:
|
||||
links[rel] = url
|
||||
return links
|
||||
|
||||
|
||||
class GitHubSession(object):
|
||||
def __init__(self, module, token):
|
||||
self.module = module
|
||||
self.token = token
|
||||
|
||||
def request(self, method, url, data=None):
|
||||
headers = {
|
||||
'Authorization': 'token %s' % self.token,
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/vnd.github.v3+json',
|
||||
}
|
||||
response, info = fetch_url(
|
||||
self.module, url, method=method, data=data, headers=headers)
|
||||
if not (200 <= info['status'] < 400):
|
||||
self.module.fail_json(
|
||||
msg=(" failed to send request %s to %s: %s"
|
||||
% (method, url, info['msg'])))
|
||||
return GitHubResponse(response, info)
|
||||
|
||||
|
||||
def get_all_keys(session):
|
||||
url = API_BASE + '/user/keys'
|
||||
result = []
|
||||
while url:
|
||||
r = session.request('GET', url)
|
||||
result.extend(r.json())
|
||||
url = r.links().get('next')
|
||||
return result
|
||||
|
||||
|
||||
def create_key(session, name, pubkey, check_mode):
|
||||
if check_mode:
|
||||
from datetime import datetime
|
||||
now = datetime.utcnow()
|
||||
return {
|
||||
'id': 0,
|
||||
'key': pubkey,
|
||||
'title': name,
|
||||
'url': 'http://example.com/CHECK_MODE_GITHUB_KEY',
|
||||
'created_at': datetime.strftime(now, '%Y-%m-%dT%H:%M:%SZ'),
|
||||
'read_only': False,
|
||||
'verified': False
|
||||
}
|
||||
else:
|
||||
return session.request(
|
||||
'POST',
|
||||
API_BASE + '/user/keys',
|
||||
data=json.dumps({'title': name, 'key': pubkey})).json()
|
||||
|
||||
|
||||
def delete_keys(session, to_delete, check_mode):
|
||||
if check_mode:
|
||||
return
|
||||
|
||||
for key in to_delete:
|
||||
session.request('DELETE', API_BASE + '/user/keys/%s' % key["id"])
|
||||
|
||||
|
||||
def ensure_key_absent(session, name, check_mode):
|
||||
to_delete = [key for key in get_all_keys(session) if key['title'] == name]
|
||||
delete_keys(session, to_delete, check_mode=check_mode)
|
||||
|
||||
return {'changed': bool(to_delete),
|
||||
'deleted_keys': to_delete}
|
||||
|
||||
|
||||
def ensure_key_present(module, session, name, pubkey, force, check_mode):
|
||||
all_keys = get_all_keys(session)
|
||||
matching_keys = [k for k in all_keys if k['title'] == name]
|
||||
deleted_keys = []
|
||||
|
||||
new_signature = pubkey.split(' ')[1]
|
||||
for key in all_keys:
|
||||
existing_signature = key['key'].split(' ')[1]
|
||||
if new_signature == existing_signature and key['title'] != name:
|
||||
module.fail_json(msg=(
|
||||
"another key with the same content is already registered "
|
||||
"under the name |{0}|").format(key['title']))
|
||||
|
||||
if matching_keys and force and matching_keys[0]['key'].split(' ')[1] != new_signature:
|
||||
delete_keys(session, matching_keys, check_mode=check_mode)
|
||||
(deleted_keys, matching_keys) = (matching_keys, [])
|
||||
|
||||
if not matching_keys:
|
||||
key = create_key(session, name, pubkey, check_mode=check_mode)
|
||||
else:
|
||||
key = matching_keys[0]
|
||||
|
||||
return {
|
||||
'changed': bool(deleted_keys or not matching_keys),
|
||||
'deleted_keys': deleted_keys,
|
||||
'matching_keys': matching_keys,
|
||||
'key': key
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = {
|
||||
'token': {'required': True, 'no_log': True},
|
||||
'name': {'required': True},
|
||||
'pubkey': {},
|
||||
'state': {'choices': ['present', 'absent'], 'default': 'present'},
|
||||
'force': {'default': True, 'type': 'bool'},
|
||||
}
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
token = module.params['token']
|
||||
name = module.params['name']
|
||||
state = module.params['state']
|
||||
force = module.params['force']
|
||||
pubkey = module.params.get('pubkey')
|
||||
|
||||
if pubkey:
|
||||
pubkey_parts = pubkey.split(' ')
|
||||
# Keys consist of a protocol, the key data, and an optional comment.
|
||||
if len(pubkey_parts) < 2:
|
||||
module.fail_json(msg='"pubkey" parameter has an invalid format')
|
||||
elif state == 'present':
|
||||
module.fail_json(msg='"pubkey" is required when state=present')
|
||||
|
||||
session = GitHubSession(module, token)
|
||||
if state == 'present':
|
||||
result = ensure_key_present(module, session, name, pubkey, force=force,
|
||||
check_mode=module.check_mode)
|
||||
elif state == 'absent':
|
||||
result = ensure_key_absent(session, name, check_mode=module.check_mode)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
218
plugins/modules/source_control/github/github_release.py
Normal file
218
plugins/modules/source_control/github/github_release.py
Normal file
|
@ -0,0 +1,218 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright: Ansible Team
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: github_release
|
||||
short_description: Interact with GitHub Releases
|
||||
description:
|
||||
- Fetch metadata about GitHub Releases
|
||||
options:
|
||||
token:
|
||||
description:
|
||||
- GitHub Personal Access Token for authenticating. Mutually exclusive with C(password).
|
||||
user:
|
||||
description:
|
||||
- The GitHub account that owns the repository
|
||||
required: true
|
||||
password:
|
||||
description:
|
||||
- The GitHub account password for the user. Mutually exclusive with C(token).
|
||||
repo:
|
||||
description:
|
||||
- Repository name
|
||||
required: true
|
||||
action:
|
||||
description:
|
||||
- Action to perform
|
||||
required: true
|
||||
choices: [ 'latest_release', 'create_release' ]
|
||||
tag:
|
||||
description:
|
||||
- Tag name when creating a release. Required when using action is set to C(create_release).
|
||||
target:
|
||||
description:
|
||||
- Target of release when creating a release
|
||||
name:
|
||||
description:
|
||||
- Name of release when creating a release
|
||||
body:
|
||||
description:
|
||||
- Description of the release when creating a release
|
||||
draft:
|
||||
description:
|
||||
- Sets if the release is a draft or not. (boolean)
|
||||
type: 'bool'
|
||||
default: 'no'
|
||||
prerelease:
|
||||
description:
|
||||
- Sets if the release is a prerelease or not. (boolean)
|
||||
type: bool
|
||||
default: 'no'
|
||||
|
||||
author:
|
||||
- "Adrian Moisey (@adrianmoisey)"
|
||||
requirements:
|
||||
- "github3.py >= 1.0.0a3"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Get latest release of a public repository
|
||||
github_release:
|
||||
user: ansible
|
||||
repo: ansible
|
||||
action: latest_release
|
||||
|
||||
- name: Get latest release of testuseer/testrepo
|
||||
github_release:
|
||||
token: tokenabc1234567890
|
||||
user: testuser
|
||||
repo: testrepo
|
||||
action: latest_release
|
||||
|
||||
- name: Get latest release of test repo using username and password. Ansible 2.4.
|
||||
github_release:
|
||||
user: testuser
|
||||
password: secret123
|
||||
repo: testrepo
|
||||
action: latest_release
|
||||
|
||||
- name: Create a new release
|
||||
github_release:
|
||||
token: tokenabc1234567890
|
||||
user: testuser
|
||||
repo: testrepo
|
||||
action: create_release
|
||||
tag: test
|
||||
target: master
|
||||
name: My Release
|
||||
body: Some description
|
||||
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
create_release:
|
||||
description:
|
||||
- Version of the created release
|
||||
- "For Ansible version 2.5 and later, if specified release version already exists, then State is unchanged"
|
||||
- "For Ansible versions prior to 2.5, if specified release version already exists, then State is skipped"
|
||||
type: str
|
||||
returned: success
|
||||
sample: 1.1.0
|
||||
|
||||
latest_release:
|
||||
description: Version of the latest release
|
||||
type: str
|
||||
returned: success
|
||||
sample: 1.1.0
|
||||
'''
|
||||
|
||||
import traceback
|
||||
|
||||
GITHUB_IMP_ERR = None
|
||||
try:
|
||||
import github3
|
||||
|
||||
HAS_GITHUB_API = True
|
||||
except ImportError:
|
||||
GITHUB_IMP_ERR = traceback.format_exc()
|
||||
HAS_GITHUB_API = False
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
repo=dict(required=True),
|
||||
user=dict(required=True),
|
||||
password=dict(no_log=True),
|
||||
token=dict(no_log=True),
|
||||
action=dict(
|
||||
required=True, choices=['latest_release', 'create_release']),
|
||||
tag=dict(type='str'),
|
||||
target=dict(type='str'),
|
||||
name=dict(type='str'),
|
||||
body=dict(type='str'),
|
||||
draft=dict(type='bool', default=False),
|
||||
prerelease=dict(type='bool', default=False),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
mutually_exclusive=(('password', 'token'),),
|
||||
required_if=[('action', 'create_release', ['tag']),
|
||||
('action', 'create_release', ['password', 'token'], True)],
|
||||
)
|
||||
|
||||
if not HAS_GITHUB_API:
|
||||
module.fail_json(msg=missing_required_lib('github3.py >= 1.0.0a3'),
|
||||
exception=GITHUB_IMP_ERR)
|
||||
|
||||
repo = module.params['repo']
|
||||
user = module.params['user']
|
||||
password = module.params['password']
|
||||
login_token = module.params['token']
|
||||
action = module.params['action']
|
||||
tag = module.params.get('tag')
|
||||
target = module.params.get('target')
|
||||
name = module.params.get('name')
|
||||
body = module.params.get('body')
|
||||
draft = module.params.get('draft')
|
||||
prerelease = module.params.get('prerelease')
|
||||
|
||||
# login to github
|
||||
try:
|
||||
if password:
|
||||
gh_obj = github3.login(user, password=password)
|
||||
elif login_token:
|
||||
gh_obj = github3.login(token=login_token)
|
||||
else:
|
||||
gh_obj = github3.GitHub()
|
||||
|
||||
# test if we're actually logged in
|
||||
if password or login_token:
|
||||
gh_obj.me()
|
||||
except github3.exceptions.AuthenticationFailed as e:
|
||||
module.fail_json(msg='Failed to connect to GitHub: %s' % to_native(e),
|
||||
details="Please check username and password or token "
|
||||
"for repository %s" % repo)
|
||||
|
||||
repository = gh_obj.repository(user, repo)
|
||||
|
||||
if not repository:
|
||||
module.fail_json(msg="Repository %s/%s doesn't exist" % (user, repo))
|
||||
|
||||
if action == 'latest_release':
|
||||
release = repository.latest_release()
|
||||
if release:
|
||||
module.exit_json(tag=release.tag_name)
|
||||
else:
|
||||
module.exit_json(tag=None)
|
||||
|
||||
if action == 'create_release':
|
||||
release_exists = repository.release_from_tag(tag)
|
||||
if release_exists:
|
||||
module.exit_json(changed=False, msg="Release for tag %s already exists." % tag)
|
||||
|
||||
release = repository.create_release(
|
||||
tag, target, name, body, draft, prerelease)
|
||||
if release:
|
||||
module.exit_json(changed=True, tag=release.tag_name)
|
||||
else:
|
||||
module.exit_json(changed=False, tag=None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
284
plugins/modules/source_control/github/github_webhook.py
Normal file
284
plugins/modules/source_control/github/github_webhook.py
Normal file
|
@ -0,0 +1,284 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright: (c) 2018, Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: github_webhook
|
||||
short_description: Manage GitHub webhooks
|
||||
description:
|
||||
- "Create and delete GitHub webhooks"
|
||||
requirements:
|
||||
- "PyGithub >= 1.3.5"
|
||||
options:
|
||||
repository:
|
||||
description:
|
||||
- Full name of the repository to configure a hook for
|
||||
required: true
|
||||
aliases:
|
||||
- repo
|
||||
url:
|
||||
description:
|
||||
- URL to which payloads will be delivered
|
||||
required: true
|
||||
content_type:
|
||||
description:
|
||||
- The media type used to serialize the payloads
|
||||
required: false
|
||||
choices: [ form, json ]
|
||||
default: form
|
||||
secret:
|
||||
description:
|
||||
- The shared secret between GitHub and the payload URL.
|
||||
required: false
|
||||
insecure_ssl:
|
||||
description:
|
||||
- >
|
||||
Flag to indicate that GitHub should skip SSL verification when calling
|
||||
the hook.
|
||||
required: false
|
||||
type: bool
|
||||
default: false
|
||||
events:
|
||||
description:
|
||||
- >
|
||||
A list of GitHub events the hook is triggered for. Events are listed at
|
||||
U(https://developer.github.com/v3/activity/events/types/). Required
|
||||
unless C(state) is C(absent)
|
||||
required: false
|
||||
active:
|
||||
description:
|
||||
- Whether or not the hook is active
|
||||
required: false
|
||||
type: bool
|
||||
default: true
|
||||
state:
|
||||
description:
|
||||
- Whether the hook should be present or absent
|
||||
required: false
|
||||
choices: [ absent, present ]
|
||||
default: present
|
||||
user:
|
||||
description:
|
||||
- User to authenticate to GitHub as
|
||||
required: true
|
||||
password:
|
||||
description:
|
||||
- Password to authenticate to GitHub with
|
||||
required: false
|
||||
token:
|
||||
description:
|
||||
- Token to authenticate to GitHub with
|
||||
required: false
|
||||
github_url:
|
||||
description:
|
||||
- Base URL of the GitHub API
|
||||
required: false
|
||||
default: https://api.github.com
|
||||
|
||||
author:
|
||||
- "Chris St. Pierre (@stpierre)"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: create a new webhook that triggers on push (password auth)
|
||||
github_webhook:
|
||||
repository: ansible/ansible
|
||||
url: https://www.example.com/hooks/
|
||||
events:
|
||||
- push
|
||||
user: "{{ github_user }}"
|
||||
password: "{{ github_password }}"
|
||||
|
||||
- name: create a new webhook in a github enterprise installation with multiple event triggers (token auth)
|
||||
github_webhook:
|
||||
repository: myorg/myrepo
|
||||
url: https://jenkins.example.com/ghprbhook/
|
||||
content_type: json
|
||||
secret: "{{ github_shared_secret }}"
|
||||
insecure_ssl: True
|
||||
events:
|
||||
- issue_comment
|
||||
- pull_request
|
||||
user: "{{ github_user }}"
|
||||
token: "{{ github_user_api_token }}"
|
||||
github_url: https://github.example.com
|
||||
|
||||
- name: delete a webhook (password auth)
|
||||
github_webhook:
|
||||
repository: ansible/ansible
|
||||
url: https://www.example.com/hooks/
|
||||
state: absent
|
||||
user: "{{ github_user }}"
|
||||
password: "{{ github_password }}"
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
---
|
||||
hook_id:
|
||||
description: The GitHub ID of the hook created/updated
|
||||
returned: when state is 'present'
|
||||
type: int
|
||||
sample: 6206
|
||||
'''
|
||||
|
||||
import traceback
|
||||
|
||||
GITHUB_IMP_ERR = None
|
||||
try:
|
||||
import github
|
||||
HAS_GITHUB = True
|
||||
except ImportError:
|
||||
GITHUB_IMP_ERR = traceback.format_exc()
|
||||
HAS_GITHUB = False
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
def _create_hook_config(module):
|
||||
return {
|
||||
"url": module.params["url"],
|
||||
"content_type": module.params["content_type"],
|
||||
"secret": module.params.get("secret"),
|
||||
"insecure_ssl": "1" if module.params["insecure_ssl"] else "0"
|
||||
}
|
||||
|
||||
|
||||
def create_hook(repo, module):
|
||||
config = _create_hook_config(module)
|
||||
try:
|
||||
hook = repo.create_hook(
|
||||
name="web",
|
||||
config=config,
|
||||
events=module.params["events"],
|
||||
active=module.params["active"])
|
||||
except github.GithubException as err:
|
||||
module.fail_json(msg="Unable to create hook for repository %s: %s" % (
|
||||
repo.full_name, to_native(err)))
|
||||
|
||||
data = {"hook_id": hook.id}
|
||||
return True, data
|
||||
|
||||
|
||||
def update_hook(repo, hook, module):
|
||||
config = _create_hook_config(module)
|
||||
try:
|
||||
hook.update()
|
||||
hook.edit(
|
||||
name="web",
|
||||
config=config,
|
||||
events=module.params["events"],
|
||||
active=module.params["active"])
|
||||
|
||||
changed = hook.update()
|
||||
except github.GithubException as err:
|
||||
module.fail_json(msg="Unable to modify hook for repository %s: %s" % (
|
||||
repo.full_name, to_native(err)))
|
||||
|
||||
data = {"hook_id": hook.id}
|
||||
return changed, data
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
repository=dict(type='str', required=True, aliases=['repo']),
|
||||
url=dict(type='str', required=True),
|
||||
content_type=dict(
|
||||
type='str',
|
||||
choices=('json', 'form'),
|
||||
required=False,
|
||||
default='form'),
|
||||
secret=dict(type='str', required=False, no_log=True),
|
||||
insecure_ssl=dict(type='bool', required=False, default=False),
|
||||
events=dict(type='list', elements='str', required=False),
|
||||
active=dict(type='bool', required=False, default=True),
|
||||
state=dict(
|
||||
type='str',
|
||||
required=False,
|
||||
choices=('absent', 'present'),
|
||||
default='present'),
|
||||
user=dict(type='str', required=True),
|
||||
password=dict(type='str', required=False, no_log=True),
|
||||
token=dict(type='str', required=False, no_log=True),
|
||||
github_url=dict(
|
||||
type='str', required=False, default="https://api.github.com")),
|
||||
mutually_exclusive=(('password', 'token'),),
|
||||
required_one_of=(("password", "token"),),
|
||||
required_if=(("state", "present", ("events",)),),
|
||||
)
|
||||
|
||||
if not HAS_GITHUB:
|
||||
module.fail_json(msg=missing_required_lib('PyGithub'),
|
||||
exception=GITHUB_IMP_ERR)
|
||||
|
||||
try:
|
||||
github_conn = github.Github(
|
||||
module.params["user"],
|
||||
module.params.get("password") or module.params.get("token"),
|
||||
base_url=module.params["github_url"])
|
||||
except github.GithubException as err:
|
||||
module.fail_json(msg="Could not connect to GitHub at %s: %s" % (
|
||||
module.params["github_url"], to_native(err)))
|
||||
|
||||
try:
|
||||
repo = github_conn.get_repo(module.params["repository"])
|
||||
except github.BadCredentialsException as err:
|
||||
module.fail_json(msg="Could not authenticate to GitHub at %s: %s" % (
|
||||
module.params["github_url"], to_native(err)))
|
||||
except github.UnknownObjectException as err:
|
||||
module.fail_json(
|
||||
msg="Could not find repository %s in GitHub at %s: %s" % (
|
||||
module.params["repository"], module.params["github_url"],
|
||||
to_native(err)))
|
||||
except Exception as err:
|
||||
module.fail_json(
|
||||
msg="Could not fetch repository %s from GitHub at %s: %s" %
|
||||
(module.params["repository"], module.params["github_url"],
|
||||
to_native(err)),
|
||||
exception=traceback.format_exc())
|
||||
|
||||
hook = None
|
||||
try:
|
||||
for hook in repo.get_hooks():
|
||||
if hook.config.get("url") == module.params["url"]:
|
||||
break
|
||||
else:
|
||||
hook = None
|
||||
except github.GithubException as err:
|
||||
module.fail_json(msg="Unable to get hooks from repository %s: %s" % (
|
||||
module.params["repository"], to_native(err)))
|
||||
|
||||
changed = False
|
||||
data = {}
|
||||
if hook is None and module.params["state"] == "present":
|
||||
changed, data = create_hook(repo, module)
|
||||
elif hook is not None and module.params["state"] == "absent":
|
||||
try:
|
||||
hook.delete()
|
||||
except github.GithubException as err:
|
||||
module.fail_json(
|
||||
msg="Unable to delete hook from repository %s: %s" % (
|
||||
repo.full_name, to_native(err)))
|
||||
else:
|
||||
changed = True
|
||||
elif hook is not None and module.params["state"] == "present":
|
||||
changed, data = update_hook(repo, hook, module)
|
||||
# else, there is no hook and we want there to be no hook
|
||||
|
||||
module.exit_json(changed=changed, **data)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
1
plugins/modules/source_control/github/github_webhook_facts.py
Symbolic link
1
plugins/modules/source_control/github/github_webhook_facts.py
Symbolic link
|
@ -0,0 +1 @@
|
|||
github_webhook_info.py
|
174
plugins/modules/source_control/github/github_webhook_info.py
Normal file
174
plugins/modules/source_control/github/github_webhook_info.py
Normal file
|
@ -0,0 +1,174 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright: (c) 2018, Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: github_webhook_info
|
||||
short_description: Query information about GitHub webhooks
|
||||
description:
|
||||
- "Query information about GitHub webhooks"
|
||||
- This module was called C(github_webhook_facts) before Ansible 2.9. The usage did not change.
|
||||
requirements:
|
||||
- "PyGithub >= 1.3.5"
|
||||
options:
|
||||
repository:
|
||||
description:
|
||||
- Full name of the repository to configure a hook for
|
||||
required: true
|
||||
aliases:
|
||||
- repo
|
||||
user:
|
||||
description:
|
||||
- User to authenticate to GitHub as
|
||||
required: true
|
||||
password:
|
||||
description:
|
||||
- Password to authenticate to GitHub with
|
||||
required: false
|
||||
token:
|
||||
description:
|
||||
- Token to authenticate to GitHub with
|
||||
required: false
|
||||
github_url:
|
||||
description:
|
||||
- Base URL of the github api
|
||||
required: false
|
||||
default: https://api.github.com
|
||||
|
||||
author:
|
||||
- "Chris St. Pierre (@stpierre)"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: list hooks for a repository (password auth)
|
||||
github_webhook_info:
|
||||
repository: ansible/ansible
|
||||
user: "{{ github_user }}"
|
||||
password: "{{ github_password }}"
|
||||
register: ansible_webhooks
|
||||
|
||||
- name: list hooks for a repository on GitHub Enterprise (token auth)
|
||||
github_webhook_info:
|
||||
repository: myorg/myrepo
|
||||
user: "{{ github_user }}"
|
||||
token: "{{ github_user_api_token }}"
|
||||
github_url: https://github.example.com/api/v3/
|
||||
register: myrepo_webhooks
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
---
|
||||
hooks:
|
||||
description: A list of hooks that exist for the repo
|
||||
returned: always
|
||||
type: list
|
||||
sample: >
|
||||
[{"has_shared_secret": true,
|
||||
"url": "https://jenkins.example.com/ghprbhook/",
|
||||
"events": ["issue_comment", "pull_request"],
|
||||
"insecure_ssl": "1",
|
||||
"content_type": "json",
|
||||
"active": true,
|
||||
"id": 6206,
|
||||
"last_response": {"status": "active", "message": "OK", "code": 200}}]
|
||||
'''
|
||||
|
||||
import traceback
|
||||
|
||||
GITHUB_IMP_ERR = None
|
||||
try:
|
||||
import github
|
||||
HAS_GITHUB = True
|
||||
except ImportError:
|
||||
GITHUB_IMP_ERR = traceback.format_exc()
|
||||
HAS_GITHUB = False
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
def _munge_hook(hook_obj):
|
||||
retval = {
|
||||
"active": hook_obj.active,
|
||||
"events": hook_obj.events,
|
||||
"id": hook_obj.id,
|
||||
"url": hook_obj.url,
|
||||
}
|
||||
retval.update(hook_obj.config)
|
||||
retval["has_shared_secret"] = "secret" in retval
|
||||
if "secret" in retval:
|
||||
del retval["secret"]
|
||||
|
||||
retval["last_response"] = hook_obj.last_response.raw_data
|
||||
return retval
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
repository=dict(type='str', required=True, aliases=["repo"]),
|
||||
user=dict(type='str', required=True),
|
||||
password=dict(type='str', required=False, no_log=True),
|
||||
token=dict(type='str', required=False, no_log=True),
|
||||
github_url=dict(
|
||||
type='str', required=False, default="https://api.github.com")),
|
||||
mutually_exclusive=(('password', 'token'), ),
|
||||
required_one_of=(("password", "token"), ),
|
||||
supports_check_mode=True)
|
||||
if module._name == 'github_webhook_facts':
|
||||
module.deprecate("The 'github_webhook_facts' module has been renamed to 'github_webhook_info'", version='2.13')
|
||||
|
||||
if not HAS_GITHUB:
|
||||
module.fail_json(msg=missing_required_lib('PyGithub'),
|
||||
exception=GITHUB_IMP_ERR)
|
||||
|
||||
try:
|
||||
github_conn = github.Github(
|
||||
module.params["user"],
|
||||
module.params.get("password") or module.params.get("token"),
|
||||
base_url=module.params["github_url"])
|
||||
except github.GithubException as err:
|
||||
module.fail_json(msg="Could not connect to GitHub at %s: %s" % (
|
||||
module.params["github_url"], to_native(err)))
|
||||
|
||||
try:
|
||||
repo = github_conn.get_repo(module.params["repository"])
|
||||
except github.BadCredentialsException as err:
|
||||
module.fail_json(msg="Could not authenticate to GitHub at %s: %s" % (
|
||||
module.params["github_url"], to_native(err)))
|
||||
except github.UnknownObjectException as err:
|
||||
module.fail_json(
|
||||
msg="Could not find repository %s in GitHub at %s: %s" % (
|
||||
module.params["repository"], module.params["github_url"],
|
||||
to_native(err)))
|
||||
except Exception as err:
|
||||
module.fail_json(
|
||||
msg="Could not fetch repository %s from GitHub at %s: %s" %
|
||||
(module.params["repository"], module.params["github_url"],
|
||||
to_native(err)),
|
||||
exception=traceback.format_exc())
|
||||
|
||||
try:
|
||||
hooks = [_munge_hook(h) for h in repo.get_hooks()]
|
||||
except github.GithubException as err:
|
||||
module.fail_json(
|
||||
msg="Unable to get hooks from repository %s: %s" %
|
||||
(module.params["repository"], to_native(err)),
|
||||
exception=traceback.format_exc())
|
||||
|
||||
module.exit_json(changed=False, hooks=hooks)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue