Adding in Ansible (still a WIP).
This commit is contained in:
+78
@@ -0,0 +1,78 @@
|
||||
---
|
||||
name: Upload Ansible coverage reports with flags
|
||||
description: Does separate codecov uploads with flags taken from ansible-test's --group-by options
|
||||
inputs:
|
||||
additional-flags:
|
||||
description: Additional custom flags (comma separated) to be added to all reports.
|
||||
required: false
|
||||
directory-flag-pattern:
|
||||
description: |
|
||||
A pattern to infer flags from directory names. For example this pattern:
|
||||
{ansible-%}=python-{py%}={%}
|
||||
applied to a directory name like:
|
||||
stable-2.11=python-3.9=rando
|
||||
Results in the flags:
|
||||
ansible-stable-2.11,py3.9,rando
|
||||
required: false
|
||||
file-flag-pattern:
|
||||
description: |
|
||||
A pattern to infer flags from coverage reports. For example this pattern:
|
||||
coverage={%}={target_%}={env_%}=python-{py%}.xml
|
||||
applied to a file name like:
|
||||
coverage=integration=lookup_some_plugin=docker-default=python-3.9.xml
|
||||
Results in the flags:
|
||||
integration,target_lookup_some_plugin,env_docker-default,py3.9
|
||||
required: false
|
||||
default: coverage={%}={target_%}={env_%}.xml
|
||||
directory:
|
||||
description: The directory to scan recursively. Defaults to current working directory.
|
||||
required: false
|
||||
codecov-uploader-version:
|
||||
description: |
|
||||
The version of the codecov uploader to use. 'latest' (default) always gets the latest.
|
||||
See https://uploader.codecov.io/linux for the versions available.
|
||||
required: false
|
||||
default: latest
|
||||
fail-on-error:
|
||||
description: |
|
||||
If 'true' then codecov will be called with '-Z', which will fail the build on an error.
|
||||
Any value other than 'true' will be treated as false.
|
||||
required: false
|
||||
default: 'true'
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Download and verify codecov uploader
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::Installing codecov uploader"
|
||||
|
||||
mkdir -p /tmp/ccbin
|
||||
cd /tmp/ccbin
|
||||
|
||||
echo "/tmp/ccbin" >> ${GITHUB_PATH}
|
||||
|
||||
if command -v codecov ; then
|
||||
./codecov --version
|
||||
else
|
||||
curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --import # One-time step
|
||||
curl -Os https://uploader.codecov.io/${{ inputs.codecov-uploader-version }}/linux/codecov
|
||||
curl -Os https://uploader.codecov.io/${{ inputs.codecov-uploader-version }}/linux/codecov.SHA256SUM
|
||||
curl -Os https://uploader.codecov.io/${{ inputs.codecov-uploader-version }}/linux/codecov.SHA256SUM.sig
|
||||
gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM
|
||||
shasum -a 256 -c codecov.SHA256SUM
|
||||
chmod +x codecov
|
||||
|
||||
./codecov --version
|
||||
fi
|
||||
|
||||
echo "::endgroup::"
|
||||
|
||||
- shell: bash
|
||||
run: >-
|
||||
python -u "${{ github.action_path }}/process.py"
|
||||
--directory "${{ inputs.directory }}"
|
||||
--directory-flag-pattern "${{ inputs.file-flag-pattern }}"
|
||||
--file-flag-pattern "${{ inputs.file-flag-pattern }}"
|
||||
--additional-flags "${{ inputs.additional-flags }}"
|
||||
${{ inputs.fail-on-error == 'true' && '--fail-on-error' || '' }}
|
||||
Vendored
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2021, Brian Scholer (@briantist)
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import re
|
||||
import getopt
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_flags(pattern, input):
|
||||
patpat = r'\{([^\}]+)\}'
|
||||
|
||||
pats = re.findall(patpat, pattern)
|
||||
matcher = re.sub(patpat, r'(.*?)', pattern)
|
||||
match = re.search(matcher, input)
|
||||
|
||||
if match:
|
||||
return [pats[i].replace('%', result) for i, result in enumerate(match.groups())]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def main(argv):
|
||||
additional_flags = file_flag_pattern = directory_flag_pattern = directory = fail_on_error = None
|
||||
|
||||
opts, args = getopt.getopt(argv, '', [
|
||||
'directory=',
|
||||
'directory-flag-pattern=',
|
||||
'file-flag-pattern=',
|
||||
'additional-flags=',
|
||||
'fail-on-error',
|
||||
])
|
||||
|
||||
for opt, arg in opts:
|
||||
if opt == '--directory':
|
||||
directory = arg
|
||||
elif opt == '--directory-flag-pattern':
|
||||
directory_flag_pattern = arg
|
||||
elif opt == '--file-flag-pattern':
|
||||
file_flag_pattern = arg
|
||||
elif opt == '--additional-flags':
|
||||
additional_flags = arg
|
||||
elif opt == '--fail-on-error':
|
||||
fail_on_error = True
|
||||
|
||||
extra_flags = additional_flags.split(',') if additional_flags else []
|
||||
|
||||
flags = {}
|
||||
|
||||
directory = Path(directory) if directory else Path.cwd()
|
||||
|
||||
for f in directory.rglob('*'):
|
||||
if f.is_file():
|
||||
iflags = set()
|
||||
if directory_flag_pattern:
|
||||
for part in f.parent.parts:
|
||||
dflags = get_flags(directory_flag_pattern, part)
|
||||
if dflags:
|
||||
iflags.update(dflags)
|
||||
|
||||
fflags = get_flags(file_flag_pattern, str(f.name))
|
||||
if fflags:
|
||||
iflags.update(fflags)
|
||||
|
||||
for flag in iflags:
|
||||
flags.setdefault(flag, []).append(str(f.resolve()))
|
||||
|
||||
logextra = ' (+%r)' % extra_flags if extra_flags else ''
|
||||
|
||||
for flag, files in flags.items():
|
||||
cmd = ['codecov', '-F', flag]
|
||||
[cmd.extend(['-F', extra]) for extra in extra_flags]
|
||||
[cmd.extend(['-f', file]) for file in files]
|
||||
if fail_on_error:
|
||||
cmd.append('-Z')
|
||||
|
||||
print('::group::Flag: %s%s' % (flag, logextra))
|
||||
|
||||
print('Executing: %r' % cmd)
|
||||
subprocess.run(cmd, stderr=subprocess.STDOUT, check=True)
|
||||
|
||||
print('::endgroup::')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
---
|
||||
name: Ansible Collection via GitHub
|
||||
description: Install Ansible collections direct from GitHub repositories without using ansible-galaxy.
|
||||
branding:
|
||||
icon: git-branch
|
||||
color: yellow
|
||||
inputs:
|
||||
collection:
|
||||
description: The name of the collection in namespace.collection_name form.
|
||||
required: true
|
||||
ref:
|
||||
description: The git ref to install. Defaults to the latest release as listed in GitHub releases. Only supports branches and tags.
|
||||
required: false
|
||||
path:
|
||||
description: The path to clone it to. Defaults to ansible_collections/namespace/collection_name.
|
||||
required: false
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- shell: bash
|
||||
run: |
|
||||
COLLECTION="${{ inputs.collection }}"
|
||||
P_PATH="${{ inputs.path }}"
|
||||
P_REF="${{ inputs.ref }}"
|
||||
|
||||
NS="${COLLECTION%.*}"
|
||||
CN="${COLLECTION#*.}"
|
||||
|
||||
# only collections in the ansible-collections organization are supported right now
|
||||
URLBASE="https://github.com/ansible-collections/${COLLECTION}"
|
||||
URLCLONE="${URLBASE}.git"
|
||||
URLLATEST="${URLBASE}/releases/latest"
|
||||
|
||||
if [[ -n "${P_PATH}" ]]
|
||||
then
|
||||
OUTPATH="${P_PATH}"
|
||||
else
|
||||
OUTPATH="ansible_collections/${NS}/${CN}"
|
||||
fi
|
||||
|
||||
if [[ -n "${P_REF}" ]]
|
||||
then
|
||||
REF="${P_REF}"
|
||||
else
|
||||
# credit to https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-3294173
|
||||
latest=$(curl -fs -o/dev/null -w %{redirect_url} "${URLLATEST}")
|
||||
REF=$(basename ${latest})
|
||||
fi
|
||||
|
||||
git clone --depth=1 --branch "${REF}" "${URLCLONE}" "${OUTPATH}"
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
---
|
||||
name: Get a list of docker image versions
|
||||
description: Gets a list of docker image versions (via tags), limited to a specified number of major, minor, and micro combinations.
|
||||
outputs:
|
||||
versions:
|
||||
description: JSON encoded list of versions.
|
||||
value: ${{ steps.versions.outputs.versions }}
|
||||
inputs:
|
||||
image:
|
||||
description: The docker image name.
|
||||
required: true
|
||||
num_major_versions:
|
||||
description: Number of unique major versions to return.
|
||||
required: false
|
||||
default: '1'
|
||||
num_minor_versions:
|
||||
description: Number of unique minor versions to return.
|
||||
required: false
|
||||
default: '1'
|
||||
num_micro_versions:
|
||||
description: Number of unique micro versions to return.
|
||||
required: false
|
||||
default: '1'
|
||||
include_prerelease:
|
||||
description: If 'true' then pre-release versions are included. Any value other than 'true' will be treated as false.
|
||||
required: false
|
||||
include_postrelease:
|
||||
description: If 'true' then post-release versions are included. Any value other than 'true' will be treated as false.
|
||||
required: false
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Requirements
|
||||
shell: bash
|
||||
run: pip install -r "${{ github.action_path }}/requirements.txt"
|
||||
|
||||
- shell: bash
|
||||
id: versions
|
||||
run: >-
|
||||
python -u "${{ github.action_path }}/versions.py"
|
||||
--image "${{ inputs.image }}"
|
||||
--num_major_versions "${{ inputs.num_major_versions }}"
|
||||
--num_minor_versions "${{ inputs.num_minor_versions }}"
|
||||
--num_micro_versions "${{ inputs.num_micro_versions }}"
|
||||
${{ inputs.include_prerelease == 'true' && '--include_prerelease' || '' }}
|
||||
${{ inputs.include_postrelease == 'true' && '--include_postrelease' || '' }}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
requests
|
||||
packaging
|
||||
urllib3 >= 1.15
|
||||
Vendored
Executable
+126
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2021, Brian Scholer (@briantist)
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
import sys
|
||||
import getopt
|
||||
|
||||
import json
|
||||
|
||||
import requests
|
||||
from urllib3.util.retry import Retry
|
||||
from requests.adapters import HTTPAdapter
|
||||
from warnings import warn
|
||||
from packaging import version
|
||||
|
||||
|
||||
TAG_URI = 'https://registry.hub.docker.com/v2/repositories/%s/%s/tags?page_size=1024'
|
||||
|
||||
|
||||
class WarningRetry(Retry):
|
||||
def new(self, **kwargs):
|
||||
if self.total > 0:
|
||||
warn('Error on request. Retries remaining: %i' % (self.total,))
|
||||
return super().new(**kwargs)
|
||||
|
||||
|
||||
def main(argv):
|
||||
image = None
|
||||
include_prerelease = include_postrelease = False
|
||||
num_major_versions = 1
|
||||
num_minor_versions = 3
|
||||
num_micro_versions = 1
|
||||
|
||||
opts, args = getopt.getopt(argv, '', [
|
||||
'image=',
|
||||
'num_major_versions=',
|
||||
'num_minor_versions=',
|
||||
'num_micro_versions=',
|
||||
'include_prerelease',
|
||||
'include_postrelease',
|
||||
])
|
||||
|
||||
for opt, arg in opts:
|
||||
if opt == '--image':
|
||||
image = image_name = arg
|
||||
elif opt == '--num_major_versions':
|
||||
num_major_versions = int(arg)
|
||||
elif opt == '--num_minor_versions':
|
||||
num_minor_versions = int(arg)
|
||||
elif opt == '--num_micro_versions':
|
||||
num_micro_versions = int(arg)
|
||||
elif opt == '--include_prerelease':
|
||||
include_prerelease = True
|
||||
elif opt == '--include_postrelease':
|
||||
include_postrelease = True
|
||||
|
||||
if image is None:
|
||||
raise ValueError('image must be supplied.')
|
||||
|
||||
if '/' in image:
|
||||
org, image_name = image.split('/')
|
||||
else:
|
||||
org = 'library'
|
||||
|
||||
tag_url = TAG_URI % (org, image_name)
|
||||
|
||||
sess = requests.Session()
|
||||
retry = WarningRetry(total=5, backoff_factor=0.2, respect_retry_after_header=False)
|
||||
adapter = HTTPAdapter(max_retries=retry)
|
||||
sess.mount('https://', adapter)
|
||||
|
||||
response = sess.get(tag_url)
|
||||
|
||||
versions = []
|
||||
for tag in response.json()['results']:
|
||||
vobj = None
|
||||
try:
|
||||
vobj = version.parse(tag['name'])
|
||||
except Exception:
|
||||
continue
|
||||
else:
|
||||
if not isinstance(vobj, version.Version):
|
||||
continue
|
||||
|
||||
if vobj.is_prerelease is include_prerelease and vobj.is_postrelease is include_postrelease:
|
||||
versions.append(vobj)
|
||||
|
||||
majors = set()
|
||||
minors = set()
|
||||
micros = set()
|
||||
keep = []
|
||||
for ver in sorted(versions, reverse=True):
|
||||
if ver.major not in majors:
|
||||
if len(majors) == num_major_versions:
|
||||
break
|
||||
majors.add(ver.major)
|
||||
minors.clear()
|
||||
micros.clear()
|
||||
|
||||
if ver.minor not in minors:
|
||||
if len(minors) == num_minor_versions:
|
||||
continue
|
||||
minors.add(ver.minor)
|
||||
micros.clear()
|
||||
|
||||
if ver.micro not in micros:
|
||||
if len(micros) == num_micro_versions:
|
||||
continue
|
||||
micros.add(ver.micro)
|
||||
|
||||
keep.append(str(ver))
|
||||
|
||||
with open(os.environ.get('GITHUB_OUTPUT', '/dev/stdout'), 'a') as f:
|
||||
f.write('versions=')
|
||||
json.dump(keep, f)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: Pull ansible-test docker images
|
||||
description: Performs a docker pull against ansible-test docker image aliases
|
||||
inputs:
|
||||
working-directory:
|
||||
description: The working directory to operate under. This should be the collection's directory.
|
||||
required: false
|
||||
ansible-test-invocation:
|
||||
description: The options that will be passed to ansible-test.
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- shell: bash
|
||||
run: pip install packaging
|
||||
|
||||
- shell: python
|
||||
run: |
|
||||
import os
|
||||
import sys
|
||||
from packaging import version
|
||||
from ansible.release import __version__ as ansible_version
|
||||
|
||||
ver = version.parse(ansible_version)
|
||||
cutoff = version.parse('2.12')
|
||||
|
||||
nwd = r'${{ inputs.working-directory }}'
|
||||
if nwd:
|
||||
os.chdir(nwd)
|
||||
|
||||
# not using ver >= cutoff because of pre-release/dev comparison logic
|
||||
if ver.major > cutoff.major or (ver.major == cutoff.major and ver.minor >= cutoff.minor):
|
||||
invo = r'${{ inputs.ansible-test-invocation }}'
|
||||
sys.exit(os.system('ansible-test %s --prime-containers' % invo))
|
||||
|
||||
try:
|
||||
from ansible_test._internal.util_common import get_docker_completion
|
||||
except ImportError:
|
||||
# 2.9
|
||||
from ansible_test._internal.util import get_docker_completion
|
||||
|
||||
context = 'collection'
|
||||
wanted = ['default']
|
||||
|
||||
dockers = get_docker_completion()
|
||||
|
||||
for alias, data in dockers.items():
|
||||
if alias in wanted:
|
||||
if 'context' not in data or data['context'] == context:
|
||||
image = data['name']
|
||||
print('pulling %s' % image)
|
||||
os.system('docker pull %s' % image)
|
||||
Reference in New Issue
Block a user