| #!/usr/bin/env bash | |
| # Copyright 2019 The Fuchsia Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| #### CATEGORY=Source tree | |
| ### Creates an integration CL to test other CLs in the global integration commit queue. | |
| ## usage: fx make-integration-patch | |
| ## | |
| ## The command prints instructions and prompts the user for input. Once | |
| ## all input has been collected, it creates a patches.json file in | |
| ## integration/, creates a changelist and pushes it to Gerrit. | |
| source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/../lib/vars.sh || exit $? | |
| fx-config-read | |
| function print-instructions { | |
| echo "INSTRUCTIONS:" | |
| echo | |
| echo "For each change you wish to test with global integration:" | |
| echo " 1) Navigate to the change in Gerrit's web UI" | |
| echo " 2) Click on Download Patch (in the menu at the top right)" | |
| echo " 3) Copy any of the download options" | |
| echo " 4) Paste it here followed by a newline" | |
| echo | |
| echo "When all changes have been added, type ^D" | |
| echo | |
| echo "... GO!" | |
| echo | |
| } | |
| function print-help { | |
| echo "usage: fx make-integration-patch [OPTIONS]" | |
| echo " -h, --help this help message" | |
| echo " -m, --message commit message" | |
| echo | |
| print-instructions | |
| } | |
| function print-after-instructions { | |
| echo | |
| echo "The URL for your change is above. You can now navigate there and" | |
| echo "CQ+1 (dry run) the CL to test global integration with your patches." | |
| } | |
| function abort-if-unclean { | |
| local dir="$1" | |
| if ! git -C "${dir}" status --porcelain; then | |
| echo "ERROR: git repo at ${dir} must be clean." > /dev/stderr | |
| exit 1 | |
| fi | |
| } | |
| function write-patches-json { | |
| local file="$1/patches.json" | |
| local contents="$2" | |
| echo "$contents" > "$file" | |
| } | |
| function prompt-or-exit { | |
| local prompt="$1" | |
| read -p "${prompt} [yN] " -n 1 -r yesno | |
| echo | |
| if [[ ! "$yesno" =~ ^[Yy]$ ]]; then | |
| exit 0 | |
| fi | |
| } | |
| function create-git-commit-and-upload { | |
| local dir="$1" | |
| local message="$2" | |
| git -C "$dir" add -A | |
| if [[ "$message" = "" ]]; then | |
| git -C "$dir" commit -m "DO NOT SUBMIT - testing unsubmitted changes in GI" | |
| else | |
| git -C "$dir" commit -m "$message" | |
| fi | |
| git -C "$dir" push origin "HEAD:refs/for/master%wip" | |
| return $? | |
| } | |
| function read-patches-from-stdin { | |
| local line host project ref first=true | |
| declare -A seen_projects | |
| while read line; do | |
| local url=$(echo "$line" | cut -d " " -f 3 | sed 's/"//g') | |
| host=$(echo "$url" | cut -d / -f 3) | |
| project=$(echo "$url" | cut -d / -f 4-) | |
| ref=$(echo "$line" | cut -d " " -f 4) | |
| if [ -z "$url" ]; then | |
| continue | |
| fi | |
| if [[ ${seen_projects["$project"]} ]]; then | |
| fx-error "You are limited to one patch per project. Project '${project}' saw two patches." | |
| fx-error "Please collapse all changes in one project into a single change." | |
| return 1 | |
| fi | |
| seen_projects["$project"]=1 | |
| # The patches.json requires host-review.googlesource.com, while Gerrit's download | |
| # commands vend host.googlesource.com or just host. For example, some | |
| # repositories will show up as sso://host/project, in which case we extract | |
| # host and need to append -review.googlesource.com to it. | |
| if [[ "$host" =~ .*googlesource.* ]]; then | |
| if [[ "$host" =~ .*-review.* ]]; then | |
| fx-error "Invalid hostname. Make sure you paste the line from" \ | |
| "the 'Download' section of the Gerrit CL, not the Gerrit CL itself." | |
| exit 1 | |
| fi | |
| host=$(echo "$host" | sed "s/\.googlesource/-review\.googlesource/") | |
| else | |
| host="$host-review.googlesource.com" | |
| fi | |
| if [[ ${first} = false ]]; then | |
| printf ',\n' | |
| fi | |
| printf ' {\n "ref": "%s",\n "host": "%s",\n "project": "%s"\n }' "$ref" "$host" "$project" | |
| first=false | |
| done < /dev/stdin | |
| } | |
| function main { | |
| local integration_dir="${FUCHSIA_DIR}/integration" | |
| local message= | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| -h|--help) | |
| print-help | |
| exit 0 | |
| ;; | |
| -m|--message) | |
| shift | |
| message="$1" | |
| ;; | |
| *) | |
| echo "Invalid flag $1" | |
| print-help | |
| exit 1 | |
| esac | |
| shift | |
| done | |
| abort-if-unclean "$integration_dir" | |
| print-instructions | |
| # Track seen projects. We are limited to a single patch per project. | |
| local patches | |
| patches=$(read-patches-from-stdin) | |
| local result=$? | |
| if [[ $result -ne 0 ]]; then | |
| exit 1 | |
| fi | |
| local patch_file_contents=$(printf '[\n%s\n]' "$patches") | |
| echo | |
| echo "I'm about to write ${integration_dir}/patches.json with the following contents" | |
| echo "and then upload the patch file to Gerrit:" | |
| echo | |
| echo "$patch_file_contents" | |
| echo | |
| prompt-or-exit "Do you want to continue?" | |
| write-patches-json "$integration_dir" "$patch_file_contents" | |
| if create-git-commit-and-upload "$integration_dir" "$message"; then | |
| print-after-instructions | |
| else | |
| echo | |
| echo "ERROR: could not push your patch change to Gerrit. See details above." | |
| echo "Once you have resolve the error, you can push the change to Gerrit " | |
| echo "manually by invoking: " | |
| echo | |
| echo "git -C integration push origin HEAD:refs/for/master" | |
| fi | |
| } | |
| main "$@" |