blob: 547a1c52bd443fa499e250319de61fa252844c5f [file] [log] [blame]
# Copyright 2023 The LUCI Authors.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# See the License for the specific language governing permissions and
# limitations under the License.
# sample usage and meaning
# ./test-fft -i ~/cr -p 9
# infra-dir patchset-#
# Defensively set the CDPATH to something safe before doing anything.
export CDPATH=
# This script owns the branch below in every git repo ever. This should be safe
# since it contains a UUID.
readonly MY_INFRA_BRANCH='ftt-test-branch-149cb550-9322-46a2-a27d-06c05781102d'
# We use the devel branch in the LUCI repo to make it easier to patch the
# commit series and upload a new chain.
readonly MY_DEVEL_BRANCH='ftt-devel-branch-91e1de00-c43a-4d07-b6fe-ed05322a465b'
# die writes a message to stderr and then exits abnormally.
die() {
printf '%s\n' "$@" 1>&2
exit 1
# checkdep checks for a dependency and dies if it isn't available.
checkdep() {
which -- "$1" 1>/dev/null 2>/dev/null || die 'missing dependency: '"$1"
# backup_self backs up the currently-executing script to ~/test-ftt.
# We do this for convenience.
# The script test-ftt is itself checked into the LUCI git repo.
# It also manipulates the git state, which can cause changes to the script
# to be removed from the working directory. We copy ourselves to the home
# directory in order to make it easier to tweak something and then immediately
# run the script again.
backup_self() {
cp -- "${HOME}/test-ftt" "${HOME}/test-ftt.BAK" 1>/dev/null 2>/dev/null
if cmp --silent -- "${selfpath}" "${HOME}"/test-ftt; then
cp -- "${selfpath}" "${HOME}"/test-ftt || die 'failed to back up self'
# must_check_git_clean checks that the git repo pointed to by $1 is clean.
# We die informatively if it is not clean.
# Submodules being dirty or pointing to the wrong commit is okay here. We are only
# concerend about preventing the user from losing work.
must_check_git_clean() {
[[ -z "$(git -C "$1" status --porcelain --ignore-submodules=all)" ]] || die "directory '$1' is not clean"
# must_checkout_patchset_in_luci_dir checks out the patchset specified by the user in the luci directory.
# This function is only safe to call if we have already checked that the directory is clear.
must_checkout_patchset_in_luci_dir() {
# (1/5) Clear the local version of the dev branch so we have somewhere to work. We don't care whether the branch exists or not.
git -C "$luci_dir" branch -D "$MY_DEVEL_BRANCH" 1>/dev/null 2>/dev/null
# (2/5) Fetch the user-specified patchset. Don't check whether it's the latest or not because I don't know how to do that.
git -C "$luci_dir" fetch refs/changes/51/4917851/"$patchset" || die 'failed to fetch patchset'
# (3/5) Move the working directory to point at the thing that we just fetched.
git -C "$luci_dir" checkout FETCH_HEAD || die 'failed to check out fetch head after fetching patch. Wowzers.'
# (4/5) Drop a branch to save our current location. Use the branch name that we freed in step 1.
git -C "$luci_dir" checkout -b "$MY_DEVEL_BRANCH" || die 'failed to drop development branch for later devleopment'
# (5/5) Set the tracking branch of the branch that we just dropped to the upstream so that we can run 'git cl upload' later.
git -C "$luci_dir" branch -u "origin/main" || die 'failed to set the upstream branch of the development branch correctly'
# main takes the input args and runs the tests.
main() {
local -r usage='test-ftt [-h] [-i infra-dir] [-p patchset-number]
This script produces the branch "ftt-test-branch-149cb550-9322-46a2-a27d-06c05781102d"
in the infra tree. This branch is temporary.
This script produces the branch "ftt-devel-branch-149cb550-9322-46a2-a27d-06c05781102d"
in the LUCI tree. This branch can be modified and then re-uploaded.
while getopts ':hi:p:' opt; do
case "${opt}" in
h) printf '%s' "${usage}"; exit 0;;
i) local infra_dir="${OPTARG}";;
p) local patchset="${OPTARG}";;
1>&2 printf '%s' "${usage}"; exit 1;;
1>&2 printf '%s' "${usage}"; exit 1;;
checkdep 'realpath'
checkdep 'git'
checkdep 'mktemp'
checkdep 'cp'
checkdep 'unlink'
[[ -n ${infra_dir} ]] || die "no directory given"
[[ -e ${infra_dir} ]] || die "path \`${infra_dir}' does not exist"
[[ -d ${infra_dir} ]] || die "path \`${infra_dir}' is not directory"
[[ -n "${patchset}" ]] || die 'no patchset given'
local -r selfpath="$(realpath -- "$0")"
local -r infra_dir="$(realpath -- "${infra_dir}")" || die "failed to get realpath to \`$1'"
# cd to a defensive dir so we catch inadvertent uses of relative paths rather
# than computed absolute paths.
local -r defensive_dir="$(mktemp -d)" || die 'failed to make defensive dir'
cd -- "${defensive_dir}" || die 'failed to cd to defensive dir'
[[ -f ${infra_dir}/.gclient ]] || die 'failed heuristic: no gclient file: is the file path correct?'
local -r luci_dir="${infra_dir}"/infra/go/src/
[[ -d $luci_dir ]] || die "luci directory \`${luci_dir}' does not exist or is not directory"
[[ -f $luci_dir/AUTHORS ]] || die "failed heuristic: derived directory \`${luci_dir}' has no AUTHORS file"
local -r infra_go_root="${infra_dir}/infra/go/src/infra"
[[ -d "${infra_dir}" ]] || die "infra go root directory ${infra_go_root} does not exist"
[[ -d "${infra_go_root}/unifiedfleet" ]] || die "failed heuristic: derived directory '${infra_go_root}/unifiedfleet' does not exist."
must_check_git_clean "${infra_go_root}"
must_check_git_clean "${luci_dir}"
# Back ourselves up, after this point all subsequent commands can change the git state.
die 'not yet implemented'
main "$@"