Skip to content

Instantly share code, notes, and snippets.

@klutchell
Last active September 19, 2023 18:18
Show Gist options
  • Save klutchell/86e90621695b688bdb4c0ed971d6bc18 to your computer and use it in GitHub Desktop.
Save klutchell/86e90621695b688bdb4c0ed971d6bc18 to your computer and use it in GitHub Desktop.
balena-os bulk edit gitmodules
#!/bin/bash
set -euo pipefail
GH_TOKEN="$(<"${HOME}/.github_pat")"
github_org="balena-os"
repo_yaml_match="yocto-based OS image"
clone_root_path="src" # Set the root repository clone path here
# known_branches=("pyro" "rocko" "sumo" "thud" "warrior" "zeus" "dunfell" "honister" "kirkstone" "master" "main") # Add your list of known branches here
pr_branch="kyle/update-gitmodules" # Set the branch name for the PR
# Function to check if repo.yml contains the required property
check_repo_yml() {
local repo_url="$1"
local base64_repo_yml_content
local repo_yml_content
base64_repo_yml_content=$(gh api "$repo_url" --header "Authorization: token $GH_TOKEN" 2>/dev/null | jq -r '.content')
repo_yml_content=$(echo "$base64_repo_yml_content" | base64 --decode)
if [[ $repo_yml_content == *"$repo_yaml_match"* ]]; then
return 0
else
return 1
fi
}
# Function to get the submodule branch containing the commit
get_submodule_branch() {
local _repo_name="$1"
local _submodule_path="$2"
submodule_commit=$(git submodule status "$submodule_path" | awk '{print $1}')
(
cd "$_submodule_path" || exit
echo "$_repo_name: $_submodule_path: Fetching submodule..."
git fetch --all >/dev/null 2>&1
submodule_branch=""
if [ -z "$submodule_branch" ]; then
echo "$_repo_name: $_submodule_path: Getting branches containing commit $submodule_commit..."
submodule_branch="$(git branch -r --contains "$submodule_commit" | grep -v "origin/HEAD" | grep -v '-' | awk -F'/' '{print $2}' || true)"
fi
if [ "$(echo "$submodule_branch" | wc -l)" -gt 1 ]; then
echo "$_repo_name: $_submodule_path: Multiple matching branches found!"
git branch -r --contains "$submodule_commit" | grep -v "origin/HEAD" | grep -v '-'
submodule_branch=
fi
if [ -z "$submodule_branch" ] && [ "$_submodule_path" = "layers/meta-balena" ]; then
submodule_branch="master"
fi
if [ -z "$submodule_branch" ] && [ "$_submodule_path" = "balena-yocto-scripts" ]; then
submodule_branch="master"
fi
if [ -z "$submodule_branch" ] && [ "$_submodule_path" = "contracts" ]; then
submodule_branch="master"
fi
if [ -z "$submodule_branch" ] && [ "$_submodule_path" = "tests/autohat" ]; then
submodule_branch="master"
fi
# for branch in "${known_branches[@]}"; do
# if git branch -r --contains "$submodule_commit" | grep -v "origin/HEAD" | grep -v "-" | grep -q "origin/$branch"; then
# submodule_branch="$branch"
# break
# fi
# done
if [ -z "$submodule_branch" ]; then
echo "$_repo_name: $_submodule_path: Unable to determine branch!"
# git branch -r --contains "$submodule_commit" | cat
return
fi
echo "$_repo_name: $_submodule_path: Applying branch $submodule_branch..."
(
cd "${PWD/$_submodule_path//}" || exit
git config --file .gitmodules "submodule.$_submodule_path.branch" "$submodule_branch"
)
)
}
update_gitmodules() {
(
local _repo_name="$1"
local _repo_workdir="$2"
cd "$repo_workdir" || exit
# Update .gitmodules with branch information
if [ -f ".gitmodules" ]; then
while read -r submodule; do
submodule_path=$(echo "$submodule" | awk -F'[= ]' '{print $2}')
if [ "$(git config --file .gitmodules "submodule.$submodule_path.branch")" != "" ]; then
echo "$_repo_name: $submodule_path: Skipping submodule with branch information..."
continue
fi
if ! git submodule update --init --recursive "$submodule_path"; then
echo "$_repo_name: Unable to update submodule $submodule_path!"
continue
fi
get_submodule_branch "$_repo_name" "$submodule_path"
done < <(git config --file .gitmodules --get-regexp '^submodule\..*\.path$')
fi
)
}
# Function to create a PR with the changed files
create_pr() {
local _repo_name="$1"
local _repo_workdir="$2"
(
cd "$_repo_workdir" || exit
git checkout -B "$pr_branch" origin/master
git add .gitmodules
# bail out here if nothing has changed
if [ -z "$(git status --porcelain .gitmodules)" ]; then
echo "$_repo_name: No changes to commit!"
return
fi
git commit -s -m "Update .gitmodules with submodule branch information" -m "Changelog-entry: Update .gitmodules with submodule branch information"
# bail out here if nothing has changed
if [ -z "$(git diff $pr_branch remotes/origin/$pr_branch)" ]; then
echo "$_repo_name: No changes to push!"
return
fi
git push -f origin "$pr_branch"
gh label create no-review --description "Auto-approve via policy-bot" --color c2e0c6 --force
gh pr create --fill --label no-review || gh pr edit "$pr_branch" --add-label no-review
)
}
# Get the list of repositories
repos=$(gh api "orgs/$github_org/repos" --paginate --header "Authorization: token $GH_TOKEN")
# Create the clone root path directory if it doesn't exist
mkdir -p "$clone_root_path"
# Iterate through the repositories
while IFS= read -r repo_data; do
repo="$(echo "$repo_data" | jq -r '.clone_url')"
archived="$(echo "$repo_data" | jq -r '.archived')"
repo_name=$(basename "$repo" .git)
repo_workdir="$clone_root_path/$repo_name"
repo_yml_url="repos/$github_org/$repo_name/contents/repo.yml"
if [[ "$repo_name" != "balena-"* ]]; then
# echo "$repo_name: Skipping non-balena repository..."
rm -rf "${repo_workdir:?}/"
continue
fi
if [ "$archived" = "true" ]; then
# echo "$repo_name: Skipping archived repository..."
rm -rf "${repo_workdir:?}/"
continue
fi
# if ! check_repo_yml "$repo_yml_url"; then
# # echo "$repo_name: Skipping non-yocto repository..."
# rm -rf "${repo_workdir:?}/"
# continue
# fi
if [ -d "$repo_workdir" ]; then
echo "$repo_name: Resetting $repo_workdir..."
(
cd "$repo_workdir" || exit
git fetch --all
git reset --hard origin/master
git clean -fdx
) || continue
else
echo "$repo_name: Cloning to $repo_workdir..."
git clone "$repo" "$repo_workdir"
fi
if [ ! -f "$repo_workdir/repo.yml" ] || [[ "$(<"$repo_workdir/repo.yml")" != *"$repo_yaml_match"* ]]; then
continue
fi
if [ ! -f "$repo_workdir/.gitmodules" ]; then
continue
fi
update_gitmodules "$repo_name" "$repo_workdir"
create_pr "$repo_name" "$repo_workdir"
done < <(echo "$repos" | jq -c '.[]')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment