diff --git a/.github/actions/workflow-housekeeper/.gitignore b/.github/actions/workflow-housekeeper/.gitignore new file mode 100644 index 00000000000..47b70ae9777 --- /dev/null +++ b/.github/actions/workflow-housekeeper/.gitignore @@ -0,0 +1,4 @@ +.git +_git +.github +_github diff --git a/.github/actions/workflow-housekeeper/README.md b/.github/actions/workflow-housekeeper/README.md new file mode 100644 index 00000000000..60abfd838a9 --- /dev/null +++ b/.github/actions/workflow-housekeeper/README.md @@ -0,0 +1,55 @@ +# Workflow Housekeeper + +Retain a time period or quantity of workflow runs. + +[![Test action](https://github.com/CDCgov/prime-reportstream/.github/workflows/workflow-housekeeper--test_action.yml/badge.svg)](https://github.com/CDCgov/prime-reportstream/.github/workflows/workflow-housekeeper--test_action.yml) + +### Dependencies: + +>Change in repo: `Settings -> Actions -> General -> Workflow Permissions to allow read and write` + +## Inputs +```yml + ignore-branch-workflows: + description: 'Ignore runs from workflows currently in ./github/workflow' + required: false + retention-time: + description: 'Period of time to maintain history. E.g. "2 weeks", "3 days", etc.' + required: false + retain-run-count: + description: 'Number of latest runs to keep' + required: false + dry-run: + description: 'Only list runs pending deletion' + required: false +``` + +## Usage +```yml + - name: Checkout + uses: actions/checkout@v3 + - name: Run workflow housekeeper + uses: josiahsiegel/workflow-housekeeper@ + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +``` +or +```yml + - name: Checkout + uses: actions/checkout@v3 + - name: Run workflow housekeeper + uses: josiahsiegel/workflow-housekeeper@ + id: scan + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + ignore-branch-workflows: true + retention-time: '1 days' + retain-run-count: 1 + dry-run: false +``` + +## Generated summary +### ✨ Workflow Housekeeper ✨ + * .github/workflows/test_action.yml 4618840926 + * .github/workflows/test_action.yml 4618827035 \ No newline at end of file diff --git a/.github/actions/workflow-housekeeper/action.yml b/.github/actions/workflow-housekeeper/action.yml new file mode 100644 index 00000000000..796910b771c --- /dev/null +++ b/.github/actions/workflow-housekeeper/action.yml @@ -0,0 +1,41 @@ +# action.yml +name: 'Workflow Housekeeper' +description: 'Retain a time period or quantity of workflow runs.' +branding: + icon: 'trash-2' + color: 'red' +inputs: + ignore-branch-workflows: + description: 'Ignore runs from workflows currently in ./github/workflow' + required: false + retention-time: + description: 'Period of time to maintain history. E.g. "2 weeks", "3 days", etc.' + required: false + retain-run-count: + description: 'Number of latest runs to keep' + required: false + dry-run: + description: 'Only list runs pending deletion' + required: false +outputs: + housekeeping_output: + description: 'Output of housekeeping steps' + value: ${{ steps.local-action.outputs.housekeeping_output }} +runs: + using: "composite" + steps: + - name: Run local action + id: local-action + run: | + ${{ github.action_path }}/lib/housekeeper.sh \ + "${{ github.repository }}" \ + "${{ inputs.ignore-branch-workflows }}" \ + "${{ inputs.retention-time }}" \ + "${{ inputs.retain-run-count }}" \ + "${{ inputs.dry-run }}" + shell: bash + - name: Create summary + run: | + echo "### :sparkles: Workflow Housekeeper :sparkles:" >> $GITHUB_STEP_SUMMARY + echo -e "${{ steps.local-action.outputs.housekeeping_output }}" >> $GITHUB_STEP_SUMMARY + shell: bash diff --git a/.github/actions/workflow-housekeeper/lib/housekeeper.sh b/.github/actions/workflow-housekeeper/lib/housekeeper.sh new file mode 100755 index 00000000000..ff4bd6e84cc --- /dev/null +++ b/.github/actions/workflow-housekeeper/lib/housekeeper.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +# Init +repo="$1" +ignore_branch_workflows=$2 +retention_time=$3 +retain_run_count=$4 +dry_run=$5 + +# ignore_branch_workflows +if [[ -z $ignore_branch_workflows ]]; then + ignore_branch_workflows=false +fi +echo "ignore_branch_workflows: $ignore_branch_workflows" + +if [[ $ignore_branch_workflows = true ]]; then + files=$(ls -1 .github/workflows/ | sed 's/^/and .path != \".github\/workflows\//;s/$/\"/') +else + files="" +fi + +# retention_time +if [[ -z $retention_time ]]; then + retention_time="" +else + keep_date=$(date -d "$date -$retention_time" +%s) + keep_stmt="| select (.run_started_at | . == null or fromdateiso8601 < $keep_date)" +fi +echo "time_threshold: $retention_time" + +# retain_run_count +if [[ -z $retain_run_count ]]; then + retain_run_count=0 +fi +let retain_run_count2=retain_run_count*2 +echo "retain_run_count: $retain_run_count2" + +# dry_run +if [[ -z $dry_run ]]; then + dry_run=false +fi +echo "dry_run: $dry_run" + +# Build jq query +runs="repos/$repo/actions/runs" +query=".workflow_runs[] \ +| select( \ +.path != \".github/workflows/placeholder.yaml\" \ +"$files" +) +$keep_stmt +| (.path,.id)" + +# Get run ids +output=$(gh api --paginate $runs --jq "$query") +output=($(echo $output | tr " " "\n")) +output=${output[@]:$retain_run_count2} + +# Delete or echo run ids +for id in $output; do + if [[ $dry_run = false ]]; then + [[ $id != ".git"* ]] && gh api --silent $runs/$id -X DELETE + else + [[ $id != ".git"* ]] && echo "gh api --silent $runs/$id -X DELETE" || echo "$id" + fi + [[ $id = ".git"* ]] && summary+=" * $id" || summary+=" $id\n" + + # Prevent rate limit + sleep 1; +done + +echo "housekeeping_output=$(echo "${summary}")" >>$GITHUB_OUTPUT