Adding in Ansible (still a WIP).

This commit is contained in:
2025-01-16 16:12:35 -05:00
parent 5495f51326
commit 7298674536
4270 changed files with 606627 additions and 0 deletions
@@ -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' || '' }}
@@ -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:])
@@ -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}"
@@ -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' || '' }}
@@ -0,0 +1,3 @@
requests
packaging
urllib3 >= 1.15
@@ -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:])
@@ -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)
@@ -0,0 +1,9 @@
---
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
@@ -0,0 +1,43 @@
---
name: ansible-builder
on:
push:
paths:
- '.github/workflows/ansible-builder.yml'
- 'meta/execution-environment.yml'
- 'meta/ee-requirements.txt'
pull_request:
paths:
- '.github/workflows/ansible-builder.yml'
- 'meta/execution-environment.yml'
- 'meta/ee-requirements.txt'
schedule:
- cron: '0 13 * * *'
env:
NAMESPACE: community
COLLECTION_NAME: hashi_vault
jobs:
builder:
name: ansible-builder requirements
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
with:
show-progress: false
path: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.11
- name: Install ansible-builder
run: pip install ansible-builder
# this is kind of a naive check, since we aren't comparing the output to anything to verify
# so the only we'll catch with this is an egregious error that causes builder to exit nonzero
- name: Verify Requirements
run: ansible-builder introspect --sanitize .
@@ -0,0 +1,466 @@
name: CI
on:
# Run CI against all pushes (direct commits, also merged PRs), Pull Requests
push:
branches-ignore:
- 'dependabot/**'
paths-ignore:
- 'docs/**'
- '.github/workflows/_shared-*'
- '.github/workflows/docs*.yml'
- '.github/actions/docs/**'
pull_request:
paths-ignore:
- 'docs/**'
- '.github/workflows/_shared-*'
- '.github/workflows/docs*.yml'
- '.github/actions/docs/**'
schedule:
- cron: '0 14 * * *'
env:
NAMESPACE: community
COLLECTION_NAME: hashi_vault
ANSIBLE_FORCE_COLOR: true
ANSIBLE_COLLECTIONS_PATHS: ${{ github.workspace }}
jobs:
###
# Sanity tests (REQUIRED)
# https://docs.ansible.com/ansible/latest/dev_guide/testing_sanity.html
sanity:
name: Sanity (Ⓐ${{ matrix.ansible }})
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
runner:
- ubuntu-latest
test_container:
- default
ansible:
- stable-2.14
- stable-2.15
- stable-2.16
- devel
steps:
# ansible-test requires the collection to be in a directory in the form
# .../ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}/
- name: Initialize env vars
uses: briantist/ezenv@v1
with:
env: |
COLLECTION_PATH=ansible_collections/${NAMESPACE}/${COLLECTION_NAME}
TEST_INVOCATION="sanity --docker ${{ matrix.test_container }} -v --color ${{ github.event_name != 'schedule' && '--coverage' || '' }}"
- name: Check out code
uses: actions/checkout@v4
with:
show-progress: false
path: ${{ env.COLLECTION_PATH }}
- name: Link to .github # easier access to local actions
run: ln -s "${COLLECTION_PATH}/.github" .github
- name: Set up Python
uses: actions/setup-python@v5
with:
# it is just required to run that once as "ansible-test sanity" in the docker image
# will run on all python versions it supports.
python-version: '3.11'
# Install the head of the given branch (devel, stable-2.14)
- name: Install ansible-core (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
- name: Pull Ansible test images
timeout-minutes: 5
continue-on-error: true
uses: ./.github/actions/pull-ansible-test-images
with:
working-directory: ${{ env.COLLECTION_PATH }}
ansible-test-invocation: ${{ env.TEST_INVOCATION }}
# run ansible-test sanity inside of Docker.
# The docker container has all the pinned dependencies that are required
# and all python versions ansible supports.
- name: Run sanity tests
run: ansible-test ${{ env.TEST_INVOCATION }}
working-directory: ${{ env.COLLECTION_PATH }}
- name: Generate coverage report
if: ${{ github.event_name != 'schedule' }}
run: ansible-test coverage xml -v --requirements --group-by command --group-by environment --group-by target
working-directory: ${{ env.COLLECTION_PATH }}
- name: Upload ${{ github.job }} coverage reports
if: ${{ github.event_name != 'schedule' }}
uses: actions/upload-artifact@v4
with:
name: coverage=${{ github.job }}=ansible_${{ matrix.ansible }}=data
path: ${{ env.COLLECTION_PATH }}/tests/output/reports/
if-no-files-found: error
retention-days: 1
units:
runs-on: ${{ matrix.runner }}
name: Units (Ⓐ${{ matrix.ansible }})
strategy:
fail-fast: false
matrix:
runner:
- ubuntu-latest
test_container:
- default
ansible:
- stable-2.14
- stable-2.15
- stable-2.16
- devel
steps:
- name: Initialize env vars
uses: briantist/ezenv@v1
with:
env: |
COLLECTION_PATH=ansible_collections/${NAMESPACE}/${COLLECTION_NAME}
TEST_INVOCATION="units --color --docker ${{ matrix.test_container }} ${{ github.event_name != 'schedule' && '--coverage' || '' }}"
- name: Check out code
uses: actions/checkout@v4
with:
show-progress: false
path: ${{ env.COLLECTION_PATH }}
- name: Link to .github # easier access to local actions
run: ln -s "${COLLECTION_PATH}/.github" .github
- name: Set up Python
uses: actions/setup-python@v5
with:
# it is just required to run that once as "ansible-test units" in the docker image
# will run on all python versions it supports.
python-version: '3.11'
- name: Install ansible-core (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
- name: Pull Ansible test images
timeout-minutes: 5
continue-on-error: true
uses: ./.github/actions/pull-ansible-test-images
with:
working-directory: ${{ env.COLLECTION_PATH }}
ansible-test-invocation: ${{ env.TEST_INVOCATION }}
# Run the unit tests
- name: Run unit test
run: ansible-test ${{ env.TEST_INVOCATION }}
working-directory: ${{ env.COLLECTION_PATH }}
- name: Generate coverage report
if: ${{ github.event_name != 'schedule' }}
run: ansible-test coverage xml -v --requirements --group-by command --group-by environment --group-by target
working-directory: ${{ env.COLLECTION_PATH }}
- name: Upload ${{ github.job }} coverage reports
if: ${{ github.event_name != 'schedule' }}
uses: actions/upload-artifact@v4
with:
name: coverage=${{ github.job }}=ansible_${{ matrix.ansible }}=data
path: ${{ env.COLLECTION_PATH }}/tests/output/reports/
if-no-files-found: error
retention-days: 1
###
# Integration tests (RECOMMENDED)
#
# https://docs.ansible.com/ansible/latest/dev_guide/testing_integration.html
integration:
runs-on: ${{ matrix.runner }}
name: I (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}+V[-${{ matrix.vault_minus }}])
strategy:
fail-fast: false
matrix:
runner:
- ubuntu-latest
test_container:
- default
vault_minus:
- 0
- 1
ansible:
- stable-2.14
- stable-2.15
- stable-2.16
- devel
python:
- '3.6'
- '3.7'
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12'
exclude:
# https://docs.ansible.com/ansible/devel/installation_guide/intro_installation.html#control-node-requirements
# https://docs.ansible.com/ansible/devel/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix
- ansible: 'devel'
python: '3.6'
- ansible: 'devel'
python: '3.7'
- ansible: 'devel'
python: '3.8'
- ansible: 'devel'
python: '3.9'
- ansible: 'stable-2.16'
python: '3.6'
- ansible: 'stable-2.16'
python: '3.7'
- ansible: 'stable-2.16'
python: '3.8'
- ansible: 'stable-2.16'
python: '3.9'
- ansible: 'stable-2.15'
python: '3.6'
- ansible: 'stable-2.15'
python: '3.7'
- ansible: 'stable-2.15'
python: '3.12'
- ansible: 'stable-2.15'
python: '3.8'
- ansible: 'stable-2.14'
python: '3.12'
steps:
- name: Initialize env vars
uses: briantist/ezenv@v1
with:
env: |
COLLECTION_PATH=ansible_collections/${NAMESPACE}/${COLLECTION_NAME}
COLLECTION_INTEGRATION_PATH=${COLLECTION_PATH}/tests/integration
COLLECTION_INTEGRATION_TARGETS=${COLLECTION_INTEGRATION_PATH}/targets
TEST_INVOCATION="integration -v --color --retry-on-error --continue-on-error --python ${{ matrix.python }} --docker ${{ matrix.test_container }} ${{ github.event_name != 'schedule' && '--coverage' || '' }} --docker-network hashi_vault_default"
- name: Check out code
uses: actions/checkout@v4
with:
show-progress: false
path: ${{ env.COLLECTION_PATH }}
- name: Link to .github # easier access to local actions
run: ln -s "${COLLECTION_PATH}/.github" .github
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Get Vault versions
id: vault_versions
uses: ./.github/actions/docker-image-versions
with:
image: hashicorp/vault
num_major_versions: 1
num_minor_versions: 2
num_micro_versions: 1
- name: Install ansible-core (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
- name: Install community.postgresql
uses: ./.github/actions/collection-via-git
with:
collection: community.postgresql
- name: Pull Ansible test images
timeout-minutes: 5
continue-on-error: true
uses: ./.github/actions/pull-ansible-test-images
with:
working-directory: ${{ env.COLLECTION_PATH }}
ansible-test-invocation: ${{ env.TEST_INVOCATION }}
- name: Set Vault Version
uses: briantist/ezenv@v1
with:
env: VAULT_VERSION=${{ fromJSON(steps.vault_versions.outputs.versions)[matrix.vault_minus] }}
- name: Prepare docker dependencies (Vault ${{ env.VAULT_VERSION }})
run: ./setup.sh -e vault_version=${VAULT_VERSION}
working-directory: ${{ env.COLLECTION_INTEGRATION_TARGETS }}/setup_localenv_gha
- name: Run integration test (Vault ${{ env.VAULT_VERSION }})
run: ansible-test ${{ env.TEST_INVOCATION }}
working-directory: ${{ env.COLLECTION_PATH }}
# ansible-test support producing code coverage data
- name: Generate coverage report
if: ${{ github.event_name != 'schedule' }}
run: ansible-test coverage xml -v --requirements --group-by command --group-by environment --group-by target
working-directory: ${{ env.COLLECTION_PATH }}
- name: Upload ${{ github.job }} coverage reports
if: ${{ github.event_name != 'schedule' }}
uses: actions/upload-artifact@v4
with:
name: coverage=${{ github.job }}=ansible_${{ matrix.ansible }}=${{ matrix.python }}=vault_minus_${{ matrix.vault_minus }}=data
path: ${{ env.COLLECTION_PATH }}/tests/output/reports/
if-no-files-found: error
retention-days: 1
local_test_invocation:
runs-on: ${{ matrix.runner }}
name: LI - ${{ matrix.runner }} (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }})
strategy:
fail-fast: false
matrix:
ansible:
- stable-2.16
- devel
delete_canaries:
- true
- false
python:
- '3.12'
runner:
- ubuntu-latest
test_container:
- default
exclude:
- ansible: devel
delete_canaries: false
- ansible: stable-2.16
delete_canaries: true
steps:
- name: Initialize env vars
uses: briantist/ezenv@v1
with:
env: |
COLLECTION_PATH=ansible_collections/${NAMESPACE}/${COLLECTION_NAME}
COLLECTION_INTEGRATION_PATH=${COLLECTION_PATH}/tests/integration
COLLECTION_INTEGRATION_TARGETS=${COLLECTION_INTEGRATION_PATH}/targets
DOCKER_TEST_INVOCATION="integration -v --color --retry-on-error --continue-on-error --controller docker:${{ matrix.test_container }},python=${{ matrix.python }} ${{ github.event_name != 'schedule' && '--coverage' || '' }}"
- name: Check out code
uses: actions/checkout@v4
with:
show-progress: false
path: ${{ env.COLLECTION_PATH }}
- name: Link to .github # easier access to local actions
run: ln -s "${COLLECTION_PATH}/.github" .github
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Install ansible-core (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
- name: Install community.crypto
uses: ./.github/actions/collection-via-git
with:
collection: community.crypto
- name: Install community.docker
uses: ./.github/actions/collection-via-git
with:
collection: community.docker
- name: Install community.postgresql
uses: ./.github/actions/collection-via-git
with:
collection: community.postgresql
- name: Pull Ansible test images
timeout-minutes: 5
continue-on-error: true
uses: ./.github/actions/pull-ansible-test-images
with:
working-directory: ${{ env.COLLECTION_PATH }}
ansible-test-invocation: ${{ env.DOCKER_TEST_INVOCATION }}
- name: localenv_docker - setup
run: |
pwd
pip install --upgrade pip setuptools build wheel
pip install "Cython<3.0" "pyyaml<6" --no-build-isolation
# ^ https://github.com/yaml/pyyaml/issues/601
# ^ https://github.com/docker/compose/issues/10836
pip install -r files/requirements/requirements.txt -c files/requirements/constraints.txt
./setup.sh
working-directory: ${{ env.COLLECTION_INTEGRATION_TARGETS }}/setup_localenv_docker
- name: localenv_docker - Run integration test (in docker)
run: |
ansible-test ${{ env.DOCKER_TEST_INVOCATION }} --docker-network hashi_vault_default
working-directory: ${{ env.COLLECTION_PATH }}
#TODO add capability in the Ansible side once vault_list and vault_delete exist
- name: Delete Vault's cubbyhole contents (ensure test setup is idempotent)
if: matrix.delete_canaries
working-directory: ${{ env.COLLECTION_PATH }}
env:
VAULT_TOKEN: 47542cbc-6bf8-4fba-8eda-02e0a0d29a0a
VAULT_ADDR: http://vault:8200
run: |
echo 'vault list cubbyhole \
| tail -n +3 \
| xargs -I{} -n 1 vault delete cubbyhole/{}' \
| docker run --rm --network hashi_vault_default -e VAULT_TOKEN -e VAULT_ADDR -i hashicorp/vault sh
- name: Run integration again (ensure tests do not break against still-running containers)
working-directory: ${{ env.COLLECTION_PATH }}
run: |
ansible-test ${{ env.DOCKER_TEST_INVOCATION }} --docker-network hashi_vault_default
# ansible-test support producing code coverage data
- name: Generate coverage report
if: ${{ github.event_name != 'schedule' }}
run: ansible-test coverage xml -v --requirements --group-by command --group-by environment --group-by target
working-directory: ${{ env.COLLECTION_PATH }}
- name: Upload ${{ github.job }} coverage reports
if: ${{ github.event_name != 'schedule' }}
uses: actions/upload-artifact@v4
with:
name: coverage=${{ github.job }}=${{ matrix.runner }}=ansible_${{ matrix.ansible }}=${{ matrix.python }}=data
path: ${{ env.COLLECTION_PATH }}/tests/output/reports/
if-no-files-found: error
retention-days: 1
upload-coverage:
needs:
- sanity
- units
- integration
- local_test_invocation
# don't upload coverage on scheduled runs
# https://github.com/ansible-collections/community.hashi_vault/issues/180
if: ${{ github.event_name != 'schedule' }}
name: Upload Codecov reports
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
with:
show-progress: false
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: ./cov
# See the reports at https://codecov.io/gh/ansible-collections/community.hashi_vault
- name: Upload coverage reports to Codecov
uses: ./.github/actions/ansible-codecov
with:
directory: ./cov
directory-flag-pattern: =ansible_{ansible-%}=
@@ -0,0 +1,61 @@
name: Collection Docs
concurrency:
group: docs-push-${{ github.sha }}
cancel-in-progress: true
on:
push:
branches:
- main
tags:
- '*'
schedule:
- cron: '0 13 * * *'
jobs:
validate-docs:
permissions:
contents: read
name: Validate Ansible Docs
uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-push.yml@main
with:
init-lenient: false
init-fail-on-error: true
artifact-upload: false
build-docs:
permissions:
contents: read
name: Build Ansible Docs
uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-push.yml@main
with:
init-dest-dir: docs/preview
# Although we want this to be the most strict, we can't currently achieve this
# with the committed init-dest-dir, hence the validate-docs job, which will
# prevent publish from running in the case of failures.
publish-docs-surge:
# for now we won't run this on forks
if: github.repository == 'ansible-collections/community.hashi_vault'
permissions:
contents: read
needs: [validate-docs, build-docs]
name: Publish Ansible Docs
uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-publish-surge.yml@main
with:
artifact-name: ${{ needs.build-docs.outputs.artifact-name }}
surge-site-name: community-hashi-vault-main.surge.sh
secrets:
SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }}
publish-docs-gh-pages:
# for now we won't run this on forks
if: github.repository == 'ansible-collections/community.hashi_vault'
permissions:
contents: write
needs: [validate-docs, build-docs]
name: Publish Ansible Docs
uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-publish-gh-pages.yml@main
with:
artifact-name: ${{ needs.build-docs.outputs.artifact-name }}
secrets:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,117 @@
name: Collection Docs
concurrency:
group: docs-pr-${{ github.head_ref }}
cancel-in-progress: true
on:
pull_request_target:
types: [opened, synchronize, reopened, closed]
env:
SURGE_PR_SITE: community-hashi-vault-pr${{ github.event.number }}.surge.sh
SURGE_MAIN_SITE: community-hashi-vault-main.surge.sh
GHP_BASE_URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}
jobs:
# this job builds with the most strict options to ensure full compliance
# does not use the collection's committed sphinx-init output
validate-docs:
permissions:
contents: read
name: Validate Ansible Docs
if: github.event.action != 'closed'
uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-push.yml@main
with:
artifact-upload: false
init-lenient: false
init-fail-on-error: true
build-ref: refs/pull/${{ github.event.number }}/merge
# this job builds for the PR comparison and publish, so use the most lenient options
# to give the best possibility of producing a publishable build; the strict build will
# still result in a failure for the PR as a whole, but for review a partial docsite is
# better than none.
# This uses the committed sphinx-init output which already has the lenient options.
build-docs:
permissions:
contents: read
name: Build Ansible Docs
uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-pr.yml@main
with:
init-dest-dir: docs/preview
render-file-line: '> * `$<status>` [$<path_tail>](https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr/${{ github.event.number }}/$<path_tail>)'
publish-docs-surge:
# for now we won't run this on forks
if: github.repository == 'ansible-collections/community.hashi_vault'
permissions:
contents: read
needs: [build-docs]
name: Publish Ansible Docs
uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-publish-surge.yml@main
with:
artifact-name: ${{ needs.build-docs.outputs.artifact-name }}
surge-site-name: community-hashi-vault-pr${{ github.event.number }}.surge.sh
action: ${{ (github.event.action == 'closed' || needs.build-docs.outputs.changed != 'true') && 'teardown' || 'publish' }}
secrets:
SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }}
publish-docs-gh-pages:
# for now we won't run this on forks
if: github.repository == 'ansible-collections/community.hashi_vault'
permissions:
contents: write
needs: [build-docs]
name: Publish Ansible Docs
uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-publish-gh-pages.yml@main
with:
artifact-name: ${{ needs.build-docs.outputs.artifact-name }}
action: ${{ (github.event.action == 'closed' || needs.build-docs.outputs.changed != 'true') && 'teardown' || 'publish' }}
secrets:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
comment:
permissions:
pull-requests: write
runs-on: ubuntu-latest
needs: [build-docs, publish-docs-gh-pages]
name: PR comments
steps:
- name: PR comment
env:
PR_SITE_URL: https://${{ env.SURGE_PR_SITE }}
MAIN_SITE_URL: https://${{ env.SURGE_MAIN_SITE }}
uses: ansible-community/github-docs-build/actions/ansible-docs-build-comment@main
with:
body-includes: '## Docs Build'
reactions: heart
action: ${{ needs.build-docs.outputs.changed != 'true' && 'remove' || '' }}
on-closed-body: |
## Docs Build 📝
This PR is closed and any previously published docsite has been unpublished.
on-merged-body: |
## Docs Build 📝
Thank you for contribution!✨
This PR has been merged and the docs are now incorporated into `main`:
${{ env.GHP_BASE_URL }}/branch/main
body: |
## Docs Build 📝
Thank you for contribution!✨
The docs for **this PR** have been published here:
${{ env.GHP_BASE_URL }}/pr/${{ github.event.number }}
You can compare to the docs for the `main` branch here:
${{ env.GHP_BASE_URL }}/branch/main
The docsite for **this PR** is also available for download as an artifact from this run:
${{ needs.build-docs.outputs.artifact-url }}
File changes:
${{ needs.build-docs.outputs.diff-files-rendered }}
${{ needs.build-docs.outputs.diff-rendered }}
@@ -0,0 +1,73 @@
name: GitHub Release
on:
workflow_dispatch:
inputs:
version:
description: 'Version number to release'
required: true
env:
GHP_BASE_URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}
jobs:
release:
name: Create GitHub Release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
show-progress: false
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.12
- name: Install PyYaml
run: pip install pyyaml ansible-core
- name: Validate version is published to Galaxy
run: ansible-galaxy collection download -vvv -p /tmp 'community.hashi_vault:==${{ github.event.inputs.version }}'
- name: Build release description
shell: python
run: |
import os
import yaml
ver = '${{ github.event.inputs.version }}'
ver_anchor = str.replace(ver, '.', '-')
with open('changelogs/changelog.yaml', 'r') as s:
ri = yaml.safe_load(s)
summary = ri['releases'][ver]['changes']['release_summary']
reldate = ri['releases'][ver]['release_date']
description = '''## Summary
Released: %s
%s
---
View the [complete changelog](https://github.com/ansible-collections/community.hashi_vault/blob/main/CHANGELOG.rst#v%s) to see all changes.
View the [full documentation for release ${{ github.event.inputs.version }}](${{ env.GHP_BASE_URL }}/tag/${{ github.event.inputs.version }}).
''' % (reldate, summary, ver_anchor)
with open(os.environ['GITHUB_ENV'], 'a') as e:
e.write("RELEASE_DESCRIPTION<<EOF\n%s\nEOF" % description)
- name: Create Release
id: create_release
# TODO: this action is no longer maintained, replace
# likely candidate: https://github.com/softprops/action-gh-release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.event.inputs.version }}
release_name: ${{ github.event.inputs.version }}
body: ${{ env.RELEASE_DESCRIPTION }}