blob: 128fa5ffd3ef736e50accefee88677fe4aa7176b [file]
#!/bin/bash
# Copyright 2025 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=Other
### Create a pair of changes that will be submitted atomically. It will modify
### the top commit in fuchsia.git and in another repository (vendor/google by
### default), and make them depend on each other.
## usage: fx atomic-commit [--no-upload] [--repo <path>]
##
## --no-upload Amend the commits but don't push them.
## --repo <path> Path of the other repository, relative to the Fuchsia
## checkout. Defaults to vendor/google. The repository must
## support circular dependencies with fuchsia.git, e.g.
## third_party/cobalt_config.
set -o errexit
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/lib/vars.sh
fx-config-read
function update_footer() {
local repo_dir=$1
local dependency_id=$2
local upload=$3
(
cd "${repo_dir}" || exit 1
local message=$(git log -1 --pretty=%B)
local new_footer="""Depends-on: ${dependency_id}
Change-Id:"""
local modified_message=${message/"Change-Id:"/${new_footer}}
git commit --amend -m "${modified_message}"
if [[ "${upload}" == "true" ]]; then
git push origin
fi
)
}
# Prints the Gerrit host short name (e.g. "fuchsia" or "turquoise-internal")
# of the repository's origin remote.
function gerrit_host() {
local repo_dir=$1
git -C "${repo_dir}" config --get remote.origin.url |
sed -E 's#^[a-z]+://([^/.]+).*#\1#'
}
# Prints the `Depends-on` value for the top commit of `dep_dir`, as seen from a
# CL in `repo_dir`. The Gerrit host prefix is only needed if the two
# repositories are on different hosts.
function dependency_id() {
local repo_dir=$1
local dep_dir=$2
local change_id=$(
cd "${dep_dir}"
git log -1 | grep "Change-Id" | sed "s/Change-Id://g" | xargs
)
local dep_host=$(gerrit_host "${dep_dir}")
if [[ "$(gerrit_host "${repo_dir}")" == "${dep_host}" ]]; then
echo "${change_id}"
else
echo "${dep_host}:${change_id}"
fi
}
function print_usage_guidance() {
local other_repo=$1
echo
echo "To create atomic-commit, make sure your changes are on the top of"
echo "commit stacks in both fuchsia and ${other_repo}."
echo
echo "--- Current top commit in fuchsia.git ---"
echo
echo $(cd $FUCHSIA_DIR && git log -1 --pretty=medium)
echo
echo "--- Current top commit in ${other_repo} ---"
echo
echo $(cd ${FUCHSIA_DIR}/${other_repo} && git log -1 --pretty=medium)
echo
read -p "Does this look correct to you?[y|n]" value
if [[ "${value}" != "y" && "${value}" != "Y" ]]; then
exit
fi
}
function print_tip() {
local upload=$1
echo
echo "Your changes are raised."
if [[ "${upload}" == "true" ]]; then
echo "Please enable Auto-Submit on both CLs to enable atomic-commit."
else
echo "Changes were not uploaded (--no-upload)."
echo "You will need to manually push them to enable atomic-commit."
fi
echo
}
main() {
local upload="true"
local other_repo="vendor/google"
while [[ $# -gt 0 ]]; do
case "$1" in
--no-upload)
upload="false"
;;
--repo)
if [[ $# -lt 2 ]]; then
echo "--repo requires a path"
exit 1
fi
other_repo="${2%/}"
shift
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
shift
done
local other_dir="${FUCHSIA_DIR}/${other_repo}"
if ! git -C "${other_dir}" rev-parse --git-dir >/dev/null 2>&1; then
echo "${other_repo} is not a git repository in ${FUCHSIA_DIR}"
exit 1
fi
print_usage_guidance "${other_repo}"
local dep_on_fuchsia=$(dependency_id "${other_dir}" "${FUCHSIA_DIR}")
local dep_on_other=$(dependency_id "${FUCHSIA_DIR}" "${other_dir}")
update_footer "${other_dir}" "${dep_on_fuchsia}" "${upload}"
update_footer "${FUCHSIA_DIR}" "${dep_on_other}" "${upload}"
print_tip "${upload}"
}
main "$@"