1#!/usr/local/bin/bash -eu 2 3# Script to dual-home the upstream and downstream Collection in a single repo 4# 5# This script will build or test a downstream collection, removing any 6# upstream components that will not ship in the downstream release 7# 8# NOTES: 9# - All functions are prefixed with f_ so it's obvious where they come 10# from when in use throughout the script 11 12DOWNSTREAM_VERSION="1.1.2" 13KEEP_DOWNSTREAM_TMPDIR="${KEEP_DOWNSTREAM_TMPDIR:-''}" 14_build_dir="" 15 16f_log_info() 17{ 18 printf "%s:LOG:INFO: %s\n" "${0}" "${1}" 19} 20 21f_show_help() 22{ 23 printf "Usage: downstream.sh [OPTION]\n" 24 printf "\t-s\t\tCreate a temporary downstream release and perform sanity tests.\n" 25 printf "\t-i\t\tCreate a temporary downstream release and perform integration tests.\n" 26 printf "\t-m\t\tCreate a temporary downstream release and perform molecule tests.\n" 27 printf "\t-b\t\tCreate a downstream release and stage for release.\n" 28 printf "\t-r\t\tCreate a downstream release and publish release.\n" 29} 30 31f_text_sub() 32{ 33 # Switch FQCN and dependent components 34 OKD_sed_files="${_build_dir}/README.md ${_build_dir}/CHANGELOG.rst ${_build_dir}/changelogs/config.yaml ${_build_dir}/ci/downstream.sh ${_build_dir}/galaxy.yml" 35 # shellcheck disable=SC2068 36 for okd_file in ${OKD_sed_files[@]}; do sed -i.bak "s/OKD/OpenShift/g" "${okd_file}"; done 37 38 sed -i.bak "s/============================/==================================/" "${_build_dir}/CHANGELOG.rst" 39 sed -i.bak "s/Ansible Galaxy/Automation Hub/" "${_build_dir}/README.md" 40 sed -i.bak "s/community-okd/redhat-openshift/" "${_build_dir}/Makefile" 41 sed -i.bak "s/community\/okd/redhat\/openshift/" "${_build_dir}/Makefile" 42 sed -i.bak "s/^VERSION\:/VERSION: ${DOWNSTREAM_VERSION}/" "${_build_dir}/Makefile" 43 sed -i.bak "s/name\:.*$/name: openshift/" "${_build_dir}/galaxy.yml" 44 sed -i.bak "s/namespace\:.*$/namespace: redhat/" "${_build_dir}/galaxy.yml" 45 sed -i.bak "s/Kubernetes/OpenShift/g" "${_build_dir}/galaxy.yml" 46 sed -i.bak "s/^version\:.*$/version: ${DOWNSTREAM_VERSION}/" "${_build_dir}/galaxy.yml" 47 sed -i.bak "/STARTREMOVE/,/ENDREMOVE/d" "${_build_dir}/README.md" 48 49 find "${_build_dir}" -type f -exec sed -i.bak "s/community\.okd/redhat\.openshift/g" {} \; 50 find "${_build_dir}" -type f -name "*.bak" -delete 51} 52 53f_prep() 54{ 55 f_log_info "${FUNCNAME[0]}" 56 # Array of excluded files from downstream build (relative path) 57 _file_exclude=( 58 ) 59 60 # Files to copy downstream (relative repo root dir path) 61 _file_manifest=( 62 CHANGELOG.rst 63 galaxy.yml 64 LICENSE 65 README.md 66 Makefile 67 setup.cfg 68 .yamllint 69 requirements.txt 70 ) 71 72 # Directories to recursively copy downstream (relative repo root dir path) 73 _dir_manifest=( 74 changelogs 75 ci 76 meta 77 molecule 78 plugins 79 tests 80 ) 81 82 # Modules with inherited doc fragments from kubernetes.core that need 83 # rendering to deal with Galaxy/AH lack of functionality. 84 _doc_fragment_modules=( 85 k8s 86 openshift_process 87 openshift_route 88 ) 89 90 91 # Temp build dir 92 _tmp_dir=$(mktemp -d) 93 _start_dir="${PWD}" 94 _build_dir="${_tmp_dir}/ansible_collections/redhat/openshift" 95 mkdir -p "${_build_dir}" 96} 97 98 99f_cleanup() 100{ 101 f_log_info "${FUNCNAME[0]}" 102 if [[ -n "${_build_dir}" ]]; then 103 if [[ -n ${KEEP_DOWNSTREAM_TMPDIR} ]]; then 104 if [[ -d ${_build_dir} ]]; then 105 rm -fr "${_build_dir}" 106 fi 107 fi 108 else 109 exit 0 110 fi 111} 112 113# Exit and handle cleanup processes if needed 114f_exit() 115{ 116 f_cleanup 117 exit "$0" 118} 119 120f_create_collection_dir_structure() 121{ 122 f_log_info "${FUNCNAME[0]}" 123 # Create the Collection 124 for f_name in "${_file_manifest[@]}"; 125 do 126 cp "./${f_name}" "${_build_dir}/${f_name}" 127 done 128 for d_name in "${_dir_manifest[@]}"; 129 do 130 cp -r "./${d_name}" "${_build_dir}/${d_name}" 131 done 132 if [ -n "${_file_exclude:-}" ]; then 133 for exclude_file in "${_file_exclude[@]}"; 134 do 135 if [[ -f "${_build_dir}/${exclude_file}" ]]; then 136 rm -f "${_build_dir}/${exclude_file}" 137 fi 138 done 139 fi 140} 141 142f_handle_doc_fragments_workaround() 143{ 144 f_log_info "${FUNCNAME[0]}" 145 local install_collections_dir="${_build_dir}/collections/" 146 local temp_fragments_json="${_tmp_dir}/fragments.json" 147 local temp_start="${_tmp_dir}/startfile.txt" 148 local temp_end="${_tmp_dir}/endfile.txt" 149 local rendered_fragments="./rendereddocfragments.txt" 150 151 # Build the collection, export docs, render them, stitch it all back together 152 pushd "${_build_dir}" || return 153 ansible-galaxy collection build 154 ansible-galaxy collection install -p "${install_collections_dir}" ./*.tar.gz 155 rm ./*.tar.gz 156 for doc_fragment_mod in "${_doc_fragment_modules[@]}" 157 do 158 local module_py="plugins/modules/${doc_fragment_mod}.py" 159 f_log_info "Processing doc fragments for ${module_py}" 160 # We need following variable for ansible-doc only 161 # shellcheck disable=SC2097,SC2098 162 ANSIBLE_COLLECTIONS_PATH="${install_collections_dir}" \ 163 ANSIBLE_COLLECTIONS_PATHS="${ANSIBLE_COLLECTIONS_PATH}:${install_collections_dir}" \ 164 ansible-doc -j "redhat.openshift.${doc_fragment_mod}" > "${temp_fragments_json}" 165 # FIXME: Check Python interpreter from environment variable to work with prow 166 if [ -e /usr/bin/python3.6 ]; then 167 PYTHON="/usr/bin/python3.6" 168 else 169 PYTHON="python" 170 fi 171 "${PYTHON}" "${_start_dir}/ci/downstream_fragments.py" "redhat.openshift.${doc_fragment_mod}" "${temp_fragments_json}" 172 sed -n '/STARTREMOVE/q;p' "${module_py}" > "${temp_start}" 173 sed '1,/ENDREMOVE/d' "${module_py}" > "${temp_end}" 174 cat "${temp_start}" "${rendered_fragments}" "${temp_end}" > "${module_py}" 175 done 176 rm -f "${rendered_fragments}" 177 rm -fr "${install_collections_dir}" 178 popd 179 180} 181 182f_install_kubernetes_core() 183{ 184 f_log_info "${FUNCNAME[0]}" 185 local install_collections_dir="${_tmp_dir}/ansible_collections" 186 187 pushd "${_tmp_dir}" 188 ansible-galaxy collection install -p "${install_collections_dir}" kubernetes.core 189 popd 190} 191 192 193f_copy_collection_to_working_dir() 194{ 195 f_log_info "${FUNCNAME[0]}" 196 # Copy the Collection build result into original working dir 197 cp "${_build_dir}"/*.tar.gz ./ 198} 199 200f_common_steps() 201{ 202 f_log_info "${FUNCNAME[0]}" 203 f_prep 204 f_create_collection_dir_structure 205 f_text_sub 206 f_handle_doc_fragments_workaround 207} 208 209# Run the test sanity scanerio 210f_test_sanity_option() 211{ 212 f_log_info "${FUNCNAME[0]}" 213 f_common_steps 214 f_install_kubernetes_core 215 pushd "${_build_dir}" || return 216 ansible-galaxy collection build 217 f_log_info "SANITY TEST PWD: ${PWD}" 218 ## Can't do this because the upstream kubernetes.core dependency logic 219 ## is bound as a Makefile dep to the test-sanity target 220 #SANITY_TEST_ARGS="--docker --color --python 3.6" make test-sanity 221 # Run tests in docker if available, venv otherwise 222 if command -v docker &> /dev/null 223 then 224 ansible-test sanity --docker -v --exclude ci/ --color --python 3.6 225 else 226 ansible-test sanity --venv -v --exclude ci/ --color --python 3.6 227 fi 228 popd || return 229 f_cleanup 230} 231 232# Run the test integration 233f_test_integration_option() 234{ 235 f_log_info "${FUNCNAME[0]}" 236 f_common_steps 237 f_install_kubernetes_core 238 pushd "${_build_dir}" || return 239 f_log_info "INTEGRATION TEST WD: ${PWD}" 240 OVERRIDE_COLLECTION_PATH="${_tmp_dir}" molecule test 241 popd || return 242 f_cleanup 243} 244 245# Run the build scanerio 246f_build_option() 247{ 248 f_log_info "${FUNCNAME[0]}" 249 f_common_steps 250 pushd "${_build_dir}" || return 251 f_log_info "BUILD WD: ${PWD}" 252 # FIXME 253 # This doesn't work because we end up either recursively curl'ing 254 # kubernetes.core and redoing the text replacement over and over 255 # 256 # make build 257 ansible-galaxy collection build 258 259 popd || return 260 f_copy_collection_to_working_dir 261 f_cleanup 262} 263 264# If no options are passed, display usage and exit 265if [[ "${#}" -eq "0" ]]; then 266 f_show_help 267 f_exit 0 268fi 269 270# Handle options 271while getopts ":sirb" option 272do 273 case $option in 274 s) 275 f_test_sanity_option 276 ;; 277 i) 278 f_test_integration_option 279 ;; 280 r) 281 f_release_option 282 ;; 283 b) 284 f_build_option 285 ;; 286 *) 287 printf "ERROR: Unimplemented option chosen.\n" 288 f_show_help 289 f_exit 1 290 ;; # Default. 291 esac 292done 293 294# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 295