diff --git a/README.md b/README.md index 22f9ec5..3c06985 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,18 @@ Run `./setup.sh`. It will clone all repos and set up the "upstream" and "downstr If you want to also have your own forks as "origin", set it up manually in each created directory (e.g. `git remote add origin git@github.com:me/flowlogs-pipeline.git`) +## Non-admin users (PR mode) + +If you don't have push access to the downstream `openshift/*` repositories, use the `-p` flag on any command. This pushes to your fork and creates a PR instead of pushing directly to downstream: + +```bash +./set-z.sh -p 2.0.1 +./sync.sh -p release-2.1 +./new-branches.sh -p release-2.0 release-2.1 +``` + +The scripts will automatically detect your GitHub fork (even if it has a different name than the downstream repo) and create PRs against the appropriate downstream branches. + ## Create new release branch After a y-stream release, we generally prepare the next y-stream branch. Run with the appropriate arguments (current / next): @@ -42,6 +54,14 @@ WARNING: Merge failed in "operator", branch "release-2.0"; resolve conflicts, me You need to resolve them manually, finish the pending merge with `git merge --continue`, then push with something like `git push downstream HEAD:release-2.1`. +## Project structure + +- `common.sh` — shared definitions (repo arrays, helpers) sourced by all scripts +- `setup.sh` — initial clone and remote setup +- `set-z.sh` — bump z-stream version after a release +- `new-branches.sh` — create new release branches +- `sync.sh` — sync downstream from upstream + ### Common conflicts - GitHub workflows, in `.github/`, have been removed from downstream. If they changed upstream, you get a conflict. Just keep deleting those files. diff --git a/common.sh b/common.sh new file mode 100644 index 0000000..05c4476 --- /dev/null +++ b/common.sh @@ -0,0 +1,138 @@ +#!/bin/bash + +# Shared definitions and helpers for sync scripts. +# Source this file from the other scripts: +# source "$(dirname "$0")/common.sh" + +############################################################ +# Repo arrays # +############################################################ + +repos=(operator ebpf-agent flowlogs-pipeline console-plugin cli) +upstream_repos=("network-observability-operator" "netobserv-ebpf-agent" "flowlogs-pipeline" "netobserv-web-console" "netobserv-cli") +downstream_repos=("network-observability-operator" "network-observability-ebpf-agent" "network-observability-flowlogs-pipeline" "network-observability-console-plugin" "network-observability-cli") +tekton_all_cpnt=("network-observability-operator" "netobserv-ebpf-agent" "flowlogs-pipeline" "network-observability-console-plugin" "network-observability-cli") +cp_variants=(pf4 pf5) + +############################################################ +# SED detection (macOS compatibility) # +############################################################ + +if command -v gsed &>/dev/null; then + SED=gsed +else + SED=sed +fi + +############################################################ +# Helpers # +############################################################ + +confirm() { + local prompt=${1:-"Continue?"} + if [[ $yes_mode != 1 ]]; then + read -p "${prompt} [yN] " yn + echo + if [[ ! $yn =~ ^[Yy]$ ]]; then + return 1 + fi + fi + return 0 +} + +warnings=() + +print_warnings() { + for warning in "${warnings[@]}"; do + echo "WARNING: $warning" + done +} + +get_dockerfile_args_path() { + local repo=$1 + if [[ "$repo" == "flowlogs-pipeline" ]]; then + echo "./contrib/docker/Dockerfile-args.downstream" + else + echo "./Dockerfile-args.downstream" + fi +} + +############################################################ +# Push or create PR # +############################################################ + +push_or_pr() { + local downstream_repo=$1 + local target_branch=$2 + local commit_title=$3 + + if [[ $pr_mode == 1 ]]; then + local pr_branch="${commit_title}-${target_branch}" + pr_branch=$(echo "$pr_branch" | tr ' ' '-' | tr '[:upper:]' '[:lower:]') + local gh_user=$(gh api user --jq '.login') + # Add fork remote if not present + if ! git remote | grep -q "^fork$"; then + local fork_name="" + if gh api "repos/${gh_user}/${downstream_repo}" &>/dev/null; then + fork_name="${downstream_repo}" + fi + if [[ -z "$fork_name" ]]; then + local source_repo=$(gh api "repos/openshift/${downstream_repo}" --jq '.source.full_name // empty' 2>/dev/null) + if [[ -n "$source_repo" ]]; then + local source_name=$(basename "$source_repo") + if gh api "repos/${gh_user}/${source_name}" &>/dev/null; then + fork_name="${source_name}" + fi + fi + fi + if [[ -z "$fork_name" ]]; then + echo " No fork found. Forking openshift/${downstream_repo}..." + gh repo fork "openshift/${downstream_repo}" --clone=false + fork_name="${downstream_repo}" + fi + local fork_url="git@github.com:${gh_user}/${fork_name}.git" + echo " Using fork: ${gh_user}/${fork_name}" + git remote add fork "${fork_url}" + fi + echo " Pushing to fork branch ${pr_branch}..." + git push fork HEAD:${pr_branch} -f + echo " Creating PR against openshift/${downstream_repo}:${target_branch}..." + gh pr create --repo "openshift/${downstream_repo}" --base "${target_branch}" --head "${gh_user}:${pr_branch}" --title "${commit_title}" --body "${commit_title}" + else + git push downstream HEAD:${target_branch} + fi +} + +############################################################ +# Sanity checks # +############################################################ + +sanity_check_repos() { + local branch=$1 + for repo in "${repos[@]}"; do + echo -e "\n\033[1mSanity check on $repo\033[0m" + pushd $repo + git fetch downstream + git ls-remote --exit-code --heads downstream refs/heads/$branch + if [[ "$?" != "0" ]]; then + echo "Branch downstream/$branch not found. Stopping here." + exit 1 + fi + git diff HEAD --exit-code + if [[ "$?" != "0" ]]; then + echo "There are uncommited changes in $repo, commit or reset manually before running this script. Stopping here." + exit 1 + fi + if [[ "$repo" == "console-plugin" ]]; then + for variant in "${cp_variants[@]}"; do + echo -e "\n\033[1mVariant: $variant\033[0m" + git ls-remote --exit-code --heads downstream refs/heads/$branch-$variant + if [[ "$?" != "0" ]]; then + echo "Branch downstream/$branch-$variant not found. Stopping here." + exit 1 + fi + done + fi + popd + done +} diff --git a/new-branches.sh b/new-branches.sh index cfdd05a..30e4810 100755 --- a/new-branches.sh +++ b/new-branches.sh @@ -1,5 +1,7 @@ #!/bin/bash +source "$(dirname "$0")/common.sh" + ############################################################ # Help # ############################################################ @@ -7,10 +9,11 @@ show_help() { echo "Create new branches on downstream repositories, and bump version accordingly." echo - echo "Syntax: new-branches.sh [-h|-y] SOURCE TARGET" + echo "Syntax: new-branches.sh [-h|-y|-p] SOURCE TARGET" echo "Options:" echo " -h Print this help." echo " -y Yes-mode (non-interactive: proceed without asking)." + echo " -p PR-mode (push to fork and create PRs instead of pushing directly to downstream)." echo echo "Arguments:" echo " SOURCE Source downstream branch" @@ -18,16 +21,16 @@ show_help() echo echo "Example:" echo " ./new-branches.sh release-1.12 release-1.13" + echo " ./new-branches.sh -p release-1.12 release-1.13 # for non-admin users" echo } # Reset in case getopts has been used previously in the shell. OPTIND=1 yes_mode=0 -repos=(operator ebpf-agent flowlogs-pipeline console-plugin cli) -cp_variants=(pf4 pf5) +pr_mode=0 -while getopts "h?y" opt; do +while getopts "h?yp" opt; do case "$opt" in h|\?) show_help @@ -36,6 +39,9 @@ while getopts "h?y" opt; do y) yes_mode=1 ;; + p) + pr_mode=1 + ;; esac done @@ -54,102 +60,66 @@ if [ "$#" != "2" ]; then exit 1 fi -source="$1" +source_branch="$1" target="$2" -# Sanity checks -for repo in "${repos[@]}"; do - echo -e "\n\033[1mSanity check on $repo\033[0m" - pushd $repo - git fetch downstream - git ls-remote --exit-code --heads downstream refs/heads/$source - if [[ "$?" != "0" ]]; then - echo "Branch downstream/$source not found. Stopping here." - exit 1 - fi - git diff HEAD --exit-code - if [[ "$?" != "0" ]]; then - echo "There are uncommited changes in $repo, commit or reset manually before running this script. Stopping here." - exit 1 - fi - if [[ "$repo" == "console-plugin" ]]; then - for variant in "${cp_variants[@]}"; do - echo -e "\n\033[1mVariant: $variant\033[0m" - git ls-remote --exit-code --heads downstream refs/heads/$source-$variant - if [[ "$?" != "0" ]]; then - echo "Branch downstream/$source-$variant not found. Stopping here." - exit 1 - fi - done - fi - popd -done +sanity_check_repos "$source_branch" x=`echo ${target} | cut -d - -f2 | cut -d . -f1` y=`echo ${target} | cut -d - -f2 | cut -d . -f2` echo "" -echo "Creating branches \"downstream/$target\" as copies of \"downstream/$source\", then bumping to $x.$y.0" +echo "Creating branches \"downstream/$target\" as copies of \"downstream/$source_branch\", then bumping to $x.$y.0" -if [[ $yes_mode != 1 ]]; then - read -p "Continue? [yN] " yn - echo - if [[ ! $yn =~ ^[Yy]$ ]] ; then - exit 1 - fi -fi +confirm || exit 1 bump_and_push() { local repo=$1 - local source_branch=$2 + local src_branch=$2 local target_branch=$3 + local downstream_repo=$4 local tmp_branch="tmp-$target_branch" - git checkout -B $tmp_branch downstream/$source_branch + git checkout -B $tmp_branch downstream/$src_branch if [[ "$?" != "0" ]]; then echo "Could not check out, please make sure all repos are in a clean state without uncommited changes. Stopping here." exit 1 fi - git reset --hard downstream/$source_branch + git reset --hard downstream/$src_branch - local dockerfile_args_path="./Dockerfile-args.downstream" - if [[ "$repo" == "flowlogs-pipeline" ]]; then - dockerfile_args_path="./contrib/docker/Dockerfile-args.downstream" - fi + local dockerfile_args_path + dockerfile_args_path=$(get_dockerfile_args_path "$repo") echo " Updating ${dockerfile_args_path}..." - sed -i -r "s/^BUILDVERSION=.+/BUILDVERSION=${x}.${y}.0/" ${dockerfile_args_path} - sed -i -r "s/^BUILDVERSION_Y=.+/BUILDVERSION_Y=${x}.${y}/" ${dockerfile_args_path} + $SED -i -r "s/^BUILDVERSION=.+/BUILDVERSION=${x}.${y}.0/" ${dockerfile_args_path} + $SED -i -r "s/^BUILDVERSION_Y=.+/BUILDVERSION_Y=${x}.${y}/" ${dockerfile_args_path} echo " Setting branch '${target_branch}' in ./tekton..." - find .tekton -type f -exec sed -i -e "s/${source_branch}/${target_branch}/g" {} \; + find .tekton -type f -exec $SED -i -e "s/${src_branch}/${target_branch}/g" {} \; echo " Displaying diff..." git add -A git diff HEAD - if [[ $yes_mode != 1 ]]; then - read -p "Looks good to you, and proceed to commit and push ${target_branch}? (you can bring manual changes before answering) [yN] " yn - echo - if [[ ! $yn =~ ^[Yy]$ ]] ; then - exit 1 - fi - fi + confirm "Looks good to you, and proceed to commit and push ${target_branch}? (you can bring manual changes before answering)" || exit 1 echo " Commiting and pushing to ${target_branch}..." git commit --allow-empty -m "Prepare ${target_branch}" - git push downstream HEAD:${target_branch} + push_or_pr "${downstream_repo}" "${target_branch}" "Prepare ${target_branch}" } +i_cpnt=0 for repo in "${repos[@]}"; do echo -e "\n\033[1mProcessing $repo\033[0m" pushd $repo - bump_and_push $repo $source $target + ds_repo=${downstream_repos[$i_cpnt]} + bump_and_push $repo $source_branch $target $ds_repo if [[ "$repo" == "console-plugin" ]]; then for variant in "${cp_variants[@]}"; do echo -e "\n\033[1mVariant: $variant\033[0m" - bump_and_push $repo $source-$variant $target-$variant + bump_and_push $repo $source_branch-$variant $target-$variant $ds_repo done fi popd + i_cpnt="$((i_cpnt+1))" done diff --git a/set-z.sh b/set-z.sh index cfebf49..69fc9c5 100755 --- a/set-z.sh +++ b/set-z.sh @@ -1,5 +1,7 @@ #!/bin/bash +source "$(dirname "$0")/common.sh" + ############################################################ # Help # ############################################################ @@ -7,27 +9,27 @@ show_help() { echo "Set the z-stream version after a release. Switch tekton from ystream to zstream if necessary." echo - echo "Syntax: set-z.sh [-h|-y] VERSION" + echo "Syntax: set-z.sh [-h|-y|-p] VERSION" echo "Options:" echo " -h Print this help." echo " -y Yes-mode (non-interactive: proceed without asking)." + echo " -p PR-mode (push to fork and create PRs instead of pushing directly to downstream)." echo echo "Arguments:" echo " VERSION Version to set for the next z-stream." echo echo "Example:" echo " ./set-z.sh 2.0.1" + echo " ./set-z.sh -p 2.0.1 # for non-admin users" echo } # Reset in case getopts has been used previously in the shell. OPTIND=1 yes_mode=0 -repos=(operator ebpf-agent flowlogs-pipeline console-plugin cli) -tekton_all_cpnt=("network-observability-operator" "netobserv-ebpf-agent" "flowlogs-pipeline" "network-observability-console-plugin" "network-observability-cli") -cp_variants=(pf4 pf5) +pr_mode=0 -while getopts "h?y" opt; do +while getopts "h?yp" opt; do case "$opt" in h|\?) show_help @@ -36,6 +38,9 @@ while getopts "h?y" opt; do y) yes_mode=1 ;; + p) + pr_mode=1 + ;; esac done @@ -60,52 +65,12 @@ y=`echo ${version} | cut -d . -f2` z=`echo ${version} | cut -d . -f3` target="release-${x}.${y}" -# Sanity checks -for repo in "${repos[@]}"; do - echo -e "\n\033[1mSanity check on $repo\033[0m" - pushd $repo - git fetch downstream - git ls-remote --exit-code --heads downstream refs/heads/$target - if [[ "$?" != "0" ]]; then - echo "Branch downstream/$target not found. Stopping here." - exit 1 - fi - git diff HEAD --exit-code - if [[ "$?" != "0" ]]; then - echo "There are uncommited changes in $repo, commit or reset manually before running this script. Stopping here." - exit 1 - fi - if [[ "$repo" == "console-plugin" ]]; then - for variant in "${cp_variants[@]}"; do - echo -e "\n\033[1mVariant: $variant\033[0m" - git ls-remote --exit-code --heads downstream refs/heads/$target-$variant - if [[ "$?" != "0" ]]; then - echo "Branch downstream/$target-$variant not found. Stopping here." - exit 1 - fi - done - fi - popd -done +sanity_check_repos "$target" echo "" echo "Bump branches \"downstream/$target\" to $x.$y.$z" -if [[ $yes_mode != 1 ]]; then - read -p "Continue? [yN] " yn - echo - if [[ ! $yn =~ ^[Yy]$ ]] ; then - exit 1 - fi -fi - -warnings=() - -print_warnings() { - for warning in "${warnings[@]}"; do - echo "WARNING: $warning" - done -} +confirm || exit 1 check_tekton_file_names() { local tekton_y=$1 @@ -125,6 +90,7 @@ bump_and_push() { local repo=$1 local target_branch=$2 local tekton_component=$3 + local downstream_repo=$4 local tmp_branch="tmp-$target_branch" git checkout -B $tmp_branch downstream/$target_branch @@ -134,10 +100,8 @@ bump_and_push() { fi git reset --hard downstream/$target_branch - local dockerfile_args_path="./Dockerfile-args.downstream" - if [[ "$repo" == "flowlogs-pipeline" ]]; then - dockerfile_args_path="./contrib/docker/Dockerfile-args.downstream" - fi + local dockerfile_args_path + dockerfile_args_path=$(get_dockerfile_args_path "$repo") old=`cat ${dockerfile_args_path} | grep "BUILDVERSION=" | sed -r 's/BUILDVERSION=(.+)/\1/'` oldx=`echo ${old} | cut -d . -f1` @@ -152,10 +116,10 @@ bump_and_push() { fi echo " Updating ${dockerfile_args_path}..." - sed -i -r "s/^BUILDVERSION=.+/BUILDVERSION=${x}.${y}.${z}/" ${dockerfile_args_path} + $SED -i -r "s/^BUILDVERSION=.+/BUILDVERSION=${x}.${y}.${z}/" ${dockerfile_args_path} echo " Checking ./tekton files..." - find .tekton -type f -exec sed -i -e "s/ystream/zstream/g" {} \; + find .tekton -type f -exec $SED -i -e "s/ystream/zstream/g" {} \; check_tekton_file_names "./.tekton/${tekton_component}-ystream-pull-request.yaml" "./.tekton/${tekton_component}-zstream-pull-request.yaml" check_tekton_file_names "./.tekton/${tekton_component}-ystream-push.yaml" "./.tekton/${tekton_component}-zstream-push.yaml" if [[ "$repo" == "operator" ]]; then @@ -168,17 +132,11 @@ bump_and_push() { git add -A git diff HEAD - if [[ $yes_mode != 1 ]]; then - read -p "Looks good to you, and proceed to commit and push ${target_branch}? (you can bring manual changes before answering) [yN] " yn - echo - if [[ ! $yn =~ ^[Yy]$ ]] ; then - return - fi - fi + confirm "Looks good to you, and proceed to commit and push ${target_branch}? (you can bring manual changes before answering)" || return echo " Commit and push to ${target_branch}..." git commit --allow-empty -m "Prepare ${x}.${y}.${z}" - git push downstream HEAD:${target_branch} + push_or_pr "${downstream_repo}" "${target_branch}" "Prepare ${x}.${y}.${z}" } i_cpnt=0 @@ -186,11 +144,12 @@ for repo in "${repos[@]}"; do echo -e "\n\033[1mProcessing $repo\033[0m" pushd $repo tekton_cpnt=${tekton_all_cpnt[$i_cpnt]} - bump_and_push $repo $target $tekton_cpnt + ds_repo=${downstream_repos[$i_cpnt]} + bump_and_push $repo $target $tekton_cpnt $ds_repo if [[ "$repo" == "console-plugin" ]]; then for variant in "${cp_variants[@]}"; do echo -e "\n\033[1mVariant: $variant\033[0m" - bump_and_push $repo $target-$variant $tekton_cpnt-$variant + bump_and_push $repo $target-$variant $tekton_cpnt-$variant $ds_repo done fi popd diff --git a/setup.sh b/setup.sh index 6339f92..bc163a4 100755 --- a/setup.sh +++ b/setup.sh @@ -1,5 +1,7 @@ #!/bin/bash +source "$(dirname "$0")/common.sh" + ############################################################ # Help # ############################################################ @@ -44,45 +46,17 @@ fi echo "Cloning and setting up repositories in current directory." -if [[ $yes_mode != 1 ]]; then - read -p "Continue? [yN] " yn - echo - if [[ ! $yn =~ ^[Yy]$ ]] ; then - exit 1 - fi -fi - -git clone -o upstream git@github.com:netobserv/network-observability-operator.git operator -pushd operator -git remote add downstream git@github.com:openshift/network-observability-operator.git -git fetch upstream -git fetch downstream -popd - -git clone -o upstream git@github.com:netobserv/netobserv-ebpf-agent.git ebpf-agent -pushd ebpf-agent -git remote add downstream git@github.com:openshift/network-observability-ebpf-agent.git -git fetch upstream -git fetch downstream -popd - -git clone -o upstream git@github.com:netobserv/flowlogs-pipeline.git flowlogs-pipeline -pushd flowlogs-pipeline -git remote add downstream git@github.com:openshift/network-observability-flowlogs-pipeline.git -git fetch upstream -git fetch downstream -popd - -git clone -o upstream git@github.com:netobserv/netobserv-web-console.git console-plugin -pushd console-plugin -git remote add downstream git@github.com:openshift/network-observability-console-plugin.git -git fetch upstream -git fetch downstream -popd - -git clone -o upstream git@github.com:netobserv/netobserv-cli.git cli -pushd cli -git remote add downstream git@github.com:openshift/network-observability-cli.git -git fetch upstream -git fetch downstream -popd +confirm || exit 1 + +i=0 +for repo in "${repos[@]}"; do + upstream="${upstream_repos[$i]}" + downstream="${downstream_repos[$i]}" + git clone -o upstream "git@github.com:netobserv/${upstream}.git" "$repo" + pushd "$repo" + git remote add downstream "git@github.com:openshift/${downstream}.git" + git fetch upstream + git fetch downstream + popd + i="$((i+1))" +done diff --git a/sync.sh b/sync.sh index 6311b7c..4a83eba 100755 --- a/sync.sh +++ b/sync.sh @@ -1,5 +1,7 @@ #!/bin/bash +source "$(dirname "$0")/common.sh" + ############################################################ # Help # ############################################################ @@ -7,17 +9,19 @@ show_help() { echo "Synchronize downstream repositories from upstream" echo - echo "Syntax: sync.sh [-h|-d|-y] TARGET" + echo "Syntax: sync.sh [-h|-d|-y|-p] TARGET" echo "Options:" echo " -h Print this help." echo " -d Dry run (do not push to remote downstream)." echo " -y Yes-mode (non-interactive: proceed without asking)." + echo " -p PR-mode (push to fork and create PRs instead of pushing directly to downstream)." echo echo "Arguments:" echo " TARGET Target downstream branch" echo echo "Example:" echo " ./sync.sh release-1.12" + echo " ./sync.sh -p release-1.12 # for non-admin users" echo } @@ -25,10 +29,9 @@ show_help() OPTIND=1 dry_run=0 yes_mode=0 -repos=(operator ebpf-agent flowlogs-pipeline console-plugin cli) -cp_variants=(pf4 pf5) +pr_mode=0 -while getopts "h?dy" opt; do +while getopts "h?dyp" opt; do case "$opt" in h|\?) show_help @@ -40,6 +43,9 @@ while getopts "h?dy" opt; do y) yes_mode=1 ;; + p) + pr_mode=1 + ;; esac done @@ -68,26 +74,13 @@ target="$1" echo "Synchronizing \"downstream/$target\" with \"upstream/main${dry_run_text}\". A temporary local branch named \"tmp-$target\" will be created/overwritten." -if [[ $yes_mode != 1 ]]; then - read -p "Continue? [yN] " yn - echo - if [[ ! $yn =~ ^[Yy]$ ]] ; then - exit 1 - fi -fi - -warnings=() - -print_warnings() { - for warning in "${warnings[@]}"; do - echo "WARNING: $warning" - done -} +confirm || exit 1 merge_and_push() { local repo=$1 local downstream_branch=$2 local upstream_branch=$3 + local downstream_repo=$4 local tmp_branch="tmp-$downstream_branch" git checkout -B $tmp_branch downstream/$downstream_branch @@ -99,18 +92,12 @@ merge_and_push() { elif [[ $dry_run == 1 ]]; then echo "DRY RUN: skip push $tmp_branch to downstream/$downstream_branch. You can push manually if you wish." else - if [[ $yes_mode != 1 ]]; then - read -p "Merge done. Proceed with push? [yN] " yn - echo - if [[ ! $yn =~ ^[Yy]$ ]] ; then - return - fi - fi - # Proceed with push - git push downstream HEAD:$downstream_branch + confirm "Merge done. Proceed with push?" || return + push_or_pr "${downstream_repo}" "${downstream_branch}" "Sync ${downstream_branch} from upstream" fi } +i_cpnt=0 for repo in "${repos[@]}"; do echo -e "\n\033[1mProcessing $repo\033[0m" pushd $repo @@ -121,7 +108,8 @@ for repo in "${repos[@]}"; do echo "Branch downstream/$target not found. Create the branches before running sync.sh. You can use new-branches.sh." exit 1 fi - merge_and_push $repo $target main + ds_repo=${downstream_repos[$i_cpnt]} + merge_and_push $repo $target main $ds_repo if [[ "$repo" == "console-plugin" ]]; then for variant in "${cp_variants[@]}"; do @@ -135,11 +123,12 @@ for repo in "${repos[@]}"; do echo "Branch downstream/$target-$variant not found. Create the branches before running sync.sh. You can use new-branches.sh." exit 1 fi - merge_and_push $repo $target-$variant main-$variant + merge_and_push $repo $target-$variant main-$variant $ds_repo fi done fi popd + i_cpnt="$((i_cpnt+1))" done print_warnings