Commit 712953b3 authored by Miguel Angel Reina Ortega's avatar Miguel Angel Reina Ortega
Browse files

Job to delete old branches by a scheduled pipelines. Two steps:

- DRY-RUN mode: branches won't be actually deleted
- DELETE mode: after 15 days, branches will be deleted
parent b5010d80
Loading
Loading
Loading
Loading
+32 −4
Original line number Diff line number Diff line
@@ -13,17 +13,20 @@ workflow:
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
      when: never
    - if: $CI_COMMIT_BRANCH
    - if: $CI_PIPELINE_SOURCE == "schedule"
    
variables:
  GIT_SUBMODULE_STRATEGY: normal
  LOGFILE_YANG: "yang-validation.txt"
  LOGFILE_LINT: "yang-linting.txt"
  LOGFILE_OPENAPI: "openapi-validation.txt"
  DRY_RUN: "true"

stages:
  - checking
  - validation
  - generation
  - maintenance
  
Checking modified files:
  stage: checking
@@ -46,7 +49,8 @@ Checking modified files:
YANG Validation Strict:
  stage: validation
  rules:
    - changes:
    - if: $CI_PIPELINE_SOURCE != "schedule"
      changes:
        - yang-models/*
  before_script:
    - |
@@ -65,7 +69,8 @@ YANG Validation Strict:
YANG Additional 3GPP Checks:
  stage: validation
  rules:
    - changes:
    - if: $CI_PIPELINE_SOURCE != "schedule"
      changes:
        - yang-models/*
  allow_failure: true
  before_script:
@@ -85,7 +90,8 @@ YANG Additional 3GPP Checks:
Validate OpenAPI:
  stage: validation
  rules:
    - changes:
    - if: $CI_PIPELINE_SOURCE != "schedule"
      changes:
        - OpenAPI/*
  before_script:
    - |
@@ -104,7 +110,7 @@ Validate OpenAPI:
.Validate ASN.1 files:
  stage: validation
  rules:
    - if: $CI_COMMIT_BRANCH
    - if: $CI_COMMIT_BRANCH && $CI_PIPELINE_SOURCE != "schedule"
      changes:
        - ASN/*
  before_script:
@@ -148,3 +154,25 @@ Word CR text:
    paths:
      - docs/
    expose_as: 'Word CR text'

Delete old branches:
  stage: maintenance
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
  image: python:3.9.18-slim-bullseye
  tags:
    - docker
  before_script:
    # Installation of required software
    - apt-get update -qq && apt-get -qq install -y git curl jq > /dev/null
    - |
     curl "${CI_API_V4_URL}/projects/$TOOLS_3GPP_SCRIPTS_PROJECT_ID/repository/files/sa5%2Fdelete_old_branches%2Esh/raw?ref=oldBranches" >> delete_old_branches.sh
    - chmod +x delete_old_branches.sh
  script:
    - echo 'Delete old branches'
    - mkdir logs
    - ./delete_old_branches.sh ${CI_API_V4_URL} ${CI_PROJECT_ID} $DELETE_BRANCHES_TOKEN $DRY_RUN
  artifacts:
    paths:
      - logs/
    
 No newline at end of file
+87 −0
Original line number Diff line number Diff line
#
#	delete_old_branches.sh
#
#	Script to delete older than a year branches 
#
#	(c) 2025 by Miguel Angel Reina Ortega
#	License: BSD 3-Clause License. See the LICENSE file for further details.
#
#!/bin/bash

#Parameters

#${CI_API_V4_URL} -> 1
echo "CI_API_V4_URL:" $1
#${CI_PROJECT_ID} -> 2
echo "CI_PROJECT_ID:" $2

#!/bin/bash

PRIVATE_TOKEN=$3
ONE_YEAR_AGO=$(date -d '1 year ago' --iso-8601=seconds)
DRY_RUN=$4 # Set to false to actually delete
LOG_FILE="deleted_branches_$(date +%Y%m%d_%H%M%S).log"

# ==== Helper: URL encode ====
urlencode() {
  jq -nr --arg v "$1" '$v|@uri'
}

# ==== Initialize ====
page=1
deleted_branches=0
cd logs

echo "Dry-run mode: $DRY_RUN"
echo "Log file: $LOG_FILE"
echo "" > "$LOG_FILE" # Start fresh

# ==== Loop over paginated branch list ====
while true; do
  response=$(curl --silent --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" \
    "$1/projects/$2/repository/branches?page=$page")

  count=$(echo "$response" | jq length)
  if [ "$count" -eq 0 ]; then
    break
  fi

  jq -c '.[]' <<< "$response" > /tmp/branches.json
  while read -r branch; do
    branch_name=$(printf '%s' "$branch" | jq -r '.name')
    is_protected=$(printf '%s' "$branch" | jq -r '.protected')
    last_commit_date=$(printf '%s' "$branch" | jq -r '.commit.committed_date')

    if [ "$is_protected" = "true" ]; then
      echo "Skipping protected branch: $branch_name"
      continue
    fi

    if [[ "$last_commit_date" < "$ONE_YEAR_AGO" ]]; then
      ((deleted_branches++))
      echo "==> OLD branch: $branch_name (last commit: $last_commit_date)" | tee -a "$LOG_FILE"
      if [ "$DRY_RUN" = "true" ]; then
        echo "[DRY-RUN] Would delete: $branch_name (last commit: $last_commit_date)" | tee -a "$LOG_FILE"
      else
        encoded_branch=$(urlencode "$branch_name")
        delete_response=$(curl --silent --request DELETE \
          --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" \
          "$1/projects/$PROJECT_ID/repository/branches/$encoded_branch")

        echo "Deleted: $branch_name" | tee -a "$LOG_FILE"
      fi
    else
      echo "Keeping branch: $branch_name (last commit: $last_commit_date)" | tee -a "$LOG_FILE"
    fi
  done < /tmp/branches.json

  ((page++))
done

echo "Total deleted branches: $deleted_branches" | tee -a "$LOG_FILE"
if [ "$DRY_RUN" = "true" ]; then
  echo "[DRY-RUN] No branches actually deleted." | tee -a "$LOG_FILE"
fi

echo "Done. Deleted branches logged to: $LOG_FILE"