Skip to content

Commit 81e6ab2

Browse files
committed
git worktree switcher
1 parent b3163fb commit 81e6ab2

4 files changed

Lines changed: 191 additions & 7 deletions

File tree

main.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ func getMemberClusters(ctx context.Context, cfg *rest.Config, currentNamespace s
451451
}
452452

453453
func isInLocalMode() bool {
454-
return operatorEnvironments[1] == env.ReadOrPanic(util.OmOperatorEnv)
454+
return util.OperatorEnvironmentLocal == util.OperatorEnvironment(env.ReadOrDefault(util.OmOperatorEnv, util.OperatorEnvironmentProd.String()))
455455
}
456456

457457
// setupWebhook sets up the validation webhook for MongoDB resources in order
@@ -494,6 +494,16 @@ func setupWebhook(ctx context.Context, cfg *rest.Config, log *zap.SugaredLogger,
494494
}
495495

496496
func initializeEnvironment() {
497+
// loading environment variables from env file, for development only
498+
envFile := ".generated/context.operator.env"
499+
if _, err := os.Stat(envFile); err == nil {
500+
if err := godotenv.Load(envFile); err != nil {
501+
log.Warnf("Failed to load environment variables from file %s: %v", envFile, err)
502+
} else {
503+
log.Infof("Loaded environment variables from %s", envFile)
504+
}
505+
}
506+
497507
omOperatorEnv := getOperatorEnv()
498508

499509
initEnvVariables()

scripts/aliases/mck_aliases

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
function mck() {
2+
local command=$1
3+
4+
if [[ -z "${command}" ]]; then
5+
command="help"
6+
else
7+
shift
8+
fi
9+
10+
mck_${command} "$@"
11+
}
12+
13+
function mck_source() {
14+
mck_source_context
15+
}
16+
17+
function mck_source_context() {
18+
test -f .generated/context.export.env && source .generated/context.export.env && echo "Current context: $(cat .generated/.current_context)"
19+
test -f venv/bin/activate && source venv/bin/activate && echo "Activated venv ($(python --version)): $(which python)"
20+
test -f scripts/aliases/aliases && source scripts/aliases/aliases && echo "Sourced aliases from scripts/aliases/aliases"
21+
}
22+
23+
function mck_switch() {
24+
scripts/dev/switch_context.sh "$@"
25+
mck_source_context
26+
}
27+
28+
function _mck_fzf_git_status() {
29+
cd $(awk "{print \$1}" <<< "$1")
30+
git status
31+
}
32+
33+
function mck_switch_worktree() {
34+
local worktree
35+
36+
worktree=$(git worktree list | sed "s|$HOME/||g" \
37+
| fzf \
38+
--ansi \
39+
--preview "
40+
worktree=\"\$(awk '{print \$1}' <<< {})\"
41+
dir=\"\$HOME/\${worktree}\"
42+
git -c color.status=always -C \"\${dir}\" status
43+
" \
44+
--border \
45+
--border-label 'Switch git worktree' \
46+
--header 'CTRL-X (remove worktree)' \
47+
--no-separator \
48+
--header-border horizontal \
49+
--border-label-pos 2 \
50+
--color 'label:blue' \
51+
--min-height 20+ \
52+
--header-border horizontal \
53+
--preview-border line \
54+
--bind "ctrl-x:reload(git worktree remove \"\$HOME/\$(awk '{print \$1}' <<< {})\" > /dev/null; git worktree list | sed \"s|\$HOME/||g\")" \
55+
| awk "{print \$1}" \
56+
)
57+
58+
if [[ -n "${worktree}" ]]; then
59+
cd $HOME/${worktree}
60+
mck_source_context
61+
echo "Switched to worktree: $(pwd)"
62+
fi
63+
}
64+
65+
function mck_cd() {
66+
if [[ ! -f ".git" && ! -d ".git" || ! -f "release.json" ]]; then
67+
test -n "${mck_repo_dir}" && cd "${mck_repo_dir}"
68+
fi
69+
70+
mck_switch_worktree "$@"
71+
}
72+
73+
function mck_help() {
74+
echo "Available mck commands:"
75+
echo " mck switch - switch context (make switch) + mck source_context"
76+
echo " mck source_context, source - sources context env files, python venv and aliases"
77+
echo " mck switch_worktree, cd - switches git worktree + source_context"
78+
}
79+
80+

scripts/dev/setup_git_worktree.sh

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#!/usr/bin/env bash
2+
3+
set -Eeou pipefail
4+
test "${MDB_BASH_DEBUG:-0}" -eq 1 && set -x
5+
6+
usage() {
7+
echo "Initialize git worktree for the given branch."
8+
echo "It will create worktree and initialize it to be ready to use."
9+
echo "Usage: $0 [-f] <branch>"
10+
echo " -f - force creation/initialization even if worktree already exists or branch is checked out"
11+
echo ""
12+
echo "Example: $0 -f user/feature-branch"
13+
echo " This will create a worktree at ../user/feature-branch"
14+
}
15+
16+
force=0
17+
while getopts 'f' opt; do
18+
case ${opt} in
19+
(f) force=1 ;;
20+
(*) usage; exit 1;;
21+
esac
22+
done
23+
shift "$((OPTIND-1))"
24+
25+
branch=$1
26+
27+
if [[ -z ${branch} ]]; then
28+
echo "Error: missing branch parameter"
29+
usage
30+
exit 1
31+
fi
32+
33+
# Convert slashes to underscores for directory name
34+
branch_dir="${branch//\//_}"
35+
worktree_path="${PROJECT_DIR}/../${branch_dir}"
36+
37+
if ! git worktree list | grep "${worktree_path}" >/dev/null; then
38+
echo "Creating git worktree for branch '${branch}' at ${worktree_path}..."
39+
40+
# Check if branch exists (locally or remotely)
41+
branch_exists=0
42+
if git show-ref --verify --quiet "refs/heads/${branch}" || git show-ref --verify --quiet "refs/remotes/origin/${branch}"; then
43+
branch_exists=1
44+
fi
45+
46+
if [[ ${branch_exists} == 1 ]]; then
47+
# Branch exists, use it
48+
if [[ ${force} == 1 ]]; then
49+
git worktree add -f "${worktree_path}" "${branch}" || true
50+
else
51+
git worktree add "${worktree_path}" "${branch}"
52+
fi
53+
else
54+
# Branch doesn't exist, create it from current branch
55+
echo "Branch '${branch}' does not exist. Creating it from current branch..."
56+
if [[ ${force} == 1 ]]; then
57+
git worktree add -f -b "${branch}" "${worktree_path}" || true
58+
else
59+
git worktree add -b "${branch}" "${worktree_path}"
60+
fi
61+
fi
62+
fi
63+
64+
if [[ ! -f "${worktree_path}/scripts/dev/contexts/private-context" || ${force} == 1 ]]; then
65+
echo "Initializing worktree in ${worktree_path}..."
66+
time (
67+
mkdir -p "${worktree_path}/.generated"
68+
cp "${PROJECT_DIR}/.generated/.current_context" "${worktree_path}/.generated/"
69+
cp "${PROJECT_DIR}/scripts/dev/contexts/private-context" "${worktree_path}/scripts/dev/contexts/private-context"
70+
cp -r "${PROJECT_DIR}/bin" "${worktree_path}/bin"
71+
(
72+
cd "${worktree_path}"
73+
make switch context="$(cat ".generated/.current_context")"
74+
scripts/dev/recreate_python_venv.sh
75+
)
76+
)
77+
fi
78+
79+
(
80+
cd "${worktree_path}"
81+
make switch context="$(cat ".generated/.current_context")"
82+
source venv/bin/activate
83+
source .generated/context.export.env
84+
)
85+
86+
# temporarily copying the files as those are not committed to master yet and won't be available in new git workspace
87+
cp -r "${PROJECT_DIR}/.run" "${worktree_path}/"
88+
cp -r "${PROJECT_DIR}/.idea" "${worktree_path}/"
89+
rm "${worktree_path}/.idea/workspace.xml"
90+
cp -r ${PROJECT_DIR}/scripts/aliases ${worktree_path}/scripts/aliases
91+
92+
echo "Worktree $(realpath "${worktree_path}") has been prepared"

scripts/dev/switch_context.sh

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ if [[ ! -f "${context_file}" ]]; then
4242
fatal "Cannot switch context: File ${context_file} does not exist."
4343
fi
4444

45-
echo "Switching context to: ${context}"
45+
echo "Generating context files from: ${context}"
4646

4747

4848
# This means we are running on evergreen, in this case we need the environment variables from evg expansions.
@@ -75,9 +75,9 @@ else
7575
eval "${current_envs}"
7676
fi
7777

78-
# convert declare -x key=value into key=value
78+
# convert declare -x key=value or export key=value into key=value
7979
# filter out variables that don't have value (missing '=')
80-
current_envs=$(echo "${current_envs[@]}" | grep '=' | sed 's/^declare -x //g' | sed 's/=/=/'| sort | uniq)
80+
current_envs=$(echo "${current_envs[@]}" | grep '=' | sed 's/^declare -x //g' | sed 's/^export //g' | sed 's/=/=/'| sort | uniq)
8181

8282
echo -e "## This file is automatically generated by switch_context.sh\n## Do not edit it!" > "${destination_envs_file}.env"
8383
# shellcheck disable=SC2129
@@ -86,13 +86,15 @@ echo "${current_envs}" >> "${destination_envs_file}.env"
8686

8787
# Below is a list of special cases of variables that are called the same in EVG and local context.
8888
# This piece should probably be refactored as it's super easy to make a mistake and shadow the proper variable.
89-
echo "workdir=\"${workdir:-.}\"" >> "${destination_envs_file}.env"
89+
if ! echo "${current_envs}" | grep -q "^workdir="; then
90+
echo "workdir=\"${workdir:-.}\"" >> "${destination_envs_file}.env"
91+
fi
9092

9193
# We need to tail +5 lines due to above generated comment.
9294
awk '{print "export " $0}' < "${destination_envs_file}".env | tail -n +5 > "${destination_envs_file}".export.env
9395

9496
scripts/dev/print_operator_env.sh | sort | uniq >"${destination_envs_file}.operator.env"
95-
awk '{print "export " $0}' < "${destination_envs_file}".operator.env > "${destination_envs_file}".operator.export.env
97+
awk 'NF {print "export " $0}' < "${destination_envs_file}".operator.env > "${destination_envs_file}".operator.export.env
9698

9799
echo -n "${context}" > "${destination_envs_dir}/.current_context"
98100

@@ -119,7 +121,7 @@ if [[ "${KUBECTL_CMD}" != "kubectl" ]] || which kubectl > /dev/null; then
119121
"${KUBECTL_CMD}" config set-context "$("${KUBECTL_CMD}" config current-context)" "--namespace=${NAMESPACE}" &>/dev/null || true
120122

121123
# shellcheck disable=SC2153
122-
echo "Current context: ${context} (kubectl context: ${CLUSTER_NAME}), namespace=${NAMESPACE}"
124+
echo "Generated context: ${context}, set default kubectl context: ${CLUSTER_NAME}, namespace=${NAMESPACE}"
123125
fi
124126
else
125127
echo "Kubectl doesn't exist, skipping setting the context"

0 commit comments

Comments
 (0)