| #!/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 |
| |
| for seen in "${seen_projects[@]}"; do |
| if [[ "${seen}" == "${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 |
| done |
| seen_projects+=("${project}") |
| |
| # 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 "$@" |