-
Notifications
You must be signed in to change notification settings - Fork 6
feat: add update-refs skill #70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
juandspy
wants to merge
5
commits into
master
Choose a base branch
from
skill-update-refs
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+242
−0
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| --- | ||
| name: update-refs | ||
| description: >- | ||
| Update SaaS file refs in app-interface to the latest | ||
| commit SHAs. Use when the user says "update refs", | ||
| "bump refs", "promote", or asks to update | ||
| ccx-data-pipeline service references. | ||
| --- | ||
|
|
||
| # update-refs | ||
|
|
||
| Updates `ref:` fields in ccx-data-pipeline SaaS YAML files | ||
| (in app-interface) to the latest commit SHA from each repo's | ||
| default branch. Skips `ref: internal`, `main`, and `master`. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - Git access to `https://gitlab.cee.redhat.com/service/app-interface.git` | ||
| - Git access to the GitHub repos whose refs are being updated | ||
| - Bash 4+ (for associative arrays) | ||
|
|
||
| ## Usage | ||
|
|
||
| Run the script from the `skills/update-refs` directory: | ||
|
|
||
| ```bash | ||
| ./scripts/update_refs.sh [--dry-run] [--repo <name-or-url>]... [--local-folder <path>] | ||
| ``` | ||
|
|
||
| ### Options | ||
|
|
||
| | Flag | Description | | ||
| |------|-------------| | ||
| | `--dry-run` | Show what would change without modifying files | | ||
| | `--repo <value>` | Only update refs for this repo (repeatable). Accepts a full URL or just the repo name. Uses **exact match** — `insights-results-aggregator` will not match `insights-results-aggregator-cleaner`. | | ||
| | `--local-folder <path>` | Use an existing local app-interface checkout instead of cloning to `/tmp/app-interface`. | | ||
|
|
||
| ### Examples | ||
|
|
||
| ```bash | ||
| # Dry-run for all repos | ||
| ./scripts/update_refs.sh --dry-run | ||
|
|
||
| # Update a single repo | ||
| ./scripts/update_refs.sh --repo insights-results-aggregator | ||
|
|
||
| # Update two specific repos | ||
| ./scripts/update_refs.sh --repo insights-results-aggregator --repo ccx-notification-writer | ||
|
|
||
| # Full URL also works | ||
| ./scripts/update_refs.sh --repo https://github.com/RedHatInsights/insights-results-aggregator | ||
| ``` | ||
|
|
||
| ## Workflow | ||
|
|
||
| 1. **Ask the user** which repos to update, or whether to update all. | ||
| Always start with `--dry-run` so the user can review changes. | ||
| 2. **Ask the user** if you should clone the app-interface repository or use | ||
| the local one. If so, use `--local-folder` option. | ||
| 3. Run the script with `--dry-run` and present the output. | ||
| 4. After user confirmation, run without `--dry-run`. | ||
| 5. The script modifies files inside the local app-interface | ||
| clone at `/tmp/app-interface`. The user can then `cd` there | ||
| to review and submit a merge request. | ||
| 6. Checkout to a branch named `update-refs-<timestamp>` and push the changes. | ||
| If not using `--local-folder`, **ask the user** for the fork: | ||
| ```bash | ||
| BRANCH="update-refs-$(date +%Y%m%d)" | ||
| git checkout -b $BRANCH | ||
| git add data/services/insights/ccx-data-pipeline | ||
| git commit -m "chore: update refs" | ||
| git push -o merge_request.create \ | ||
| -o merge_request.remove_source_branch \ | ||
| -o merge_request.target=master \ | ||
| -o merge_request.title="chore: update refs" \ | ||
| fork ${BRANCH} --verbose | ||
| ``` | ||
| 1. Tell the user to follow the merge request CI in order | ||
| to ask the rest of the team to review the changes. | ||
|
|
||
| ## How it works | ||
|
|
||
| 1. Clones (or reuses) app-interface to `/tmp/app-interface`. But we always | ||
| clone in /tmp in order not to create conflicts with the user's local | ||
| app-interface clone. | ||
|
juandspy marked this conversation as resolved.
|
||
| 2. Scans all YAML files under `data/services/insights/ccx-data-pipeline`. | ||
| 3. For each `url:` + `ref:` pair, fetches the latest SHA from | ||
| the repo's default branch via `git ls-remote`. | ||
| 4. Replaces outdated SHA refs in-place (or reports them in dry-run). | ||
|
|
||
| ## Constraints | ||
|
|
||
| - **Always dry-run first** — never modify files without user review. | ||
| - **Do not touch branch refs** — `main`, `master`, and `internal` | ||
| are intentionally skipped. | ||
| - The script requires VPN network access to both GitLab (app-interface) | ||
| and GitHub (source repos). | ||
|
ikerreyes marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| #!/usr/bin/env bash | ||
| # Update all GitHub/GitLab refs in ccx-data-pipeline saas files to latest commit SHAs. | ||
| # Skips ref: internal (ephemeral/bonfire targets), main and master. | ||
| # Usage: update_refs.sh [--dry-run] [--repo <name-or-url>]... [--local-folder <path>] | ||
| # --repo filters by exact repo name or full URL (can be repeated). | ||
| # --local-folder uses an existing app-interface checkout instead of cloning. | ||
| set -uo pipefail | ||
|
juandspy marked this conversation as resolved.
|
||
|
|
||
| declare -A SHA_CACHE=() # repo_url -> latest_sha | ||
| declare -A BRANCH_CACHE=() # repo_url -> default_branch | ||
| declare -a REPO_FILTERS=() # exact repo URLs/names to update | ||
| DRY_RUN=false | ||
| PATH_TO_APP_INTERFACE="" | ||
|
|
||
| while [[ $# -gt 0 ]]; do | ||
| case "$1" in | ||
| --dry-run) DRY_RUN=true; echo "=== DRY RUN ===" ;; | ||
| --repo) | ||
| [[ -z "${2:-}" ]] && echo "ERROR: --repo requires a value" >&2 && exit 1 | ||
| REPO_FILTERS+=("$2"); shift ;; | ||
| --local-folder) | ||
| [[ -z "${2:-}" ]] && echo "ERROR: --local-folder requires a path" >&2 && exit 1 | ||
| PATH_TO_APP_INTERFACE="$2"; shift ;; | ||
| *) echo "Unknown option: $1" >&2; exit 1 ;; | ||
| esac | ||
| shift | ||
| done | ||
|
|
||
| if [[ -z "$PATH_TO_APP_INTERFACE" ]]; then | ||
| PATH_TO_APP_INTERFACE="/tmp/app-interface" | ||
| if [[ -d "$PATH_TO_APP_INTERFACE/.git" ]]; then | ||
| echo "App-interface repo already exists at $PATH_TO_APP_INTERFACE, skipping clone." | ||
| else | ||
| git clone --depth 1 git@gitlab.cee.redhat.com:service/app-interface.git "$PATH_TO_APP_INTERFACE" | ||
| fi | ||
| fi | ||
|
|
||
| cd "$PATH_TO_APP_INTERFACE" || exit 1 | ||
|
|
||
| git fetch origin master | ||
| git checkout master | ||
| git pull origin master | ||
|
|
||
|
juandspy marked this conversation as resolved.
|
||
| BASE_DIR="data/services/insights/ccx-data-pipeline" | ||
|
|
||
| repo_matches() { | ||
| local url="$1" | ||
| [[ ${#REPO_FILTERS[@]} -eq 0 ]] && return 0 | ||
| local repo_name="${url##*/}" | ||
| for filter in "${REPO_FILTERS[@]}"; do | ||
| [[ "$url" == "$filter" || "$repo_name" == "$filter" ]] && return 0 | ||
| done | ||
| return 1 | ||
| } | ||
|
|
||
| get_default_branch() { | ||
| local url="$1" | ||
| if [[ -n "${BRANCH_CACHE[$url]:-}" ]]; then | ||
| REPLY="${BRANCH_CACHE[$url]}" | ||
| return | ||
| fi | ||
| REPLY=$(git ls-remote --symref "$url" HEAD 2>/dev/null \ | ||
| | awk '/^ref:/{sub("ref: refs/heads/",""); print $1; exit}') | ||
| [[ -z "$REPLY" ]] && REPLY="main" | ||
| BRANCH_CACHE["$url"]="$REPLY" | ||
| } | ||
|
|
||
| get_latest_sha() { | ||
| local url="$1" | ||
| if [[ -n "${SHA_CACHE[$url]:-}" ]]; then | ||
| REPLY="${SHA_CACHE[$url]}" | ||
| return | ||
| fi | ||
| get_default_branch "$url" | ||
| local branch="$REPLY" | ||
| REPLY=$(git ls-remote "$url" "refs/heads/$branch" 2>/dev/null | awk '{print $1}') | ||
| if [[ -z "$REPLY" ]]; then | ||
| echo "WARNING: Could not fetch SHA for $url ($branch)" >&2 | ||
| return 1 | ||
| fi | ||
| SHA_CACHE["$url"]="$REPLY" | ||
| } | ||
|
|
||
| process_file() { | ||
| local file="$1" | ||
| local current_url="" changes=0 | ||
| local tmpfile | ||
| tmpfile=$(mktemp) | ||
|
|
||
| while IFS= read -r line; do | ||
|
ikerreyes marked this conversation as resolved.
|
||
| # Track current url context | ||
| if [[ "$line" =~ ^[[:space:]]+url:[[:space:]]+(https://[^[:space:]]+) ]]; then | ||
| current_url="${BASH_REMATCH[1]}" | ||
| fi | ||
|
|
||
| # Match ref lines, skip 'internal' | ||
| if [[ "$line" =~ ^([[:space:]]+ref:[[:space:]]+)([^[:space:]]+)$ ]]; then | ||
| local prefix="${BASH_REMATCH[1]}" | ||
| local old_ref="${BASH_REMATCH[2]}" | ||
|
|
||
| if [[ "$old_ref" != "internal" && "$old_ref" != "main" && "$old_ref" != "master" && -n "$current_url" ]] && repo_matches "$current_url"; then | ||
| if get_latest_sha "$current_url"; then | ||
| local new_sha="$REPLY" | ||
| if [[ "$old_ref" != "$new_sha" ]]; then | ||
| echo " $old_ref -> ${new_sha:0:7}... ($current_url)" >&2 | ||
| line="${prefix}${new_sha}" | ||
| ((changes++)) || true | ||
| fi | ||
| fi | ||
| fi | ||
| fi | ||
| printf '%s\n' "$line" | ||
| done < "$file" > "$tmpfile" | ||
|
|
||
| if (( changes > 0 )); then | ||
| echo "[$file] $changes ref(s) updated" | ||
| if [[ "$DRY_RUN" == false ]]; then | ||
| mv "$tmpfile" "$file" | ||
| else | ||
| rm "$tmpfile" | ||
| fi | ||
| else | ||
| rm "$tmpfile" | ||
| fi | ||
| } | ||
|
|
||
| if [[ ${#REPO_FILTERS[@]} -gt 0 ]]; then | ||
| echo "Filtering repos: ${REPO_FILTERS[*]}" | ||
| fi | ||
|
|
||
| echo "Collecting YAML files from $BASE_DIR ..." | ||
| mapfile -t files < <(find "$BASE_DIR" -type f \( -name '*.yml' -o -name '*.yaml' \) | sort) | ||
|
|
||
| echo "Found ${#files[@]} YAML files. Scanning for refs..." | ||
| echo | ||
|
|
||
| for f in "${files[@]}"; do | ||
| # Quick check: skip files without both url: and ref: | ||
| if grep -qE '^\s+url:\s+https://' "$f" && grep -qE '^\s+ref:\s' "$f"; then | ||
| process_file "$f" | ||
|
ikerreyes marked this conversation as resolved.
|
||
| fi | ||
| done | ||
|
|
||
| echo | ||
| echo "Done. ${#SHA_CACHE[@]} unique repo(s) processed." | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.