Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 74 additions & 65 deletions .github/workflows/keep-alive.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,119 +6,128 @@ on:
- cron: "0 0 1 * *"
workflow_dispatch:

concurrency:
group: keep-alive
cancel-in-progress: true

permissions:
contents: write
pull-requests: write
issues: read
actions: write

jobs:
keep-alive:
name: Keep repository GitHub Actions active
runs-on: ubuntu-latest
timeout-minutes: 5
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
BRANCH_NAME: "keep-workflows-alive"

steps:
- name: Git checkout
uses: actions/checkout@v6

- name: Check for recent activity
id: check_activity
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
default_branch="${{ github.event.repository.default_branch }}"
set -euo pipefail
default_branch=$(gh api "repos/$GH_REPO" --jq '.default_branch')
if [ -z "$default_branch" ]; then
default_branch="main"
echo "Error: could not determine default branch" >&2
exit 1
fi
echo "default_branch=$default_branch" >> "$GITHUB_OUTPUT"

if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "Manual trigger - running keep-alive unconditionally."
echo "run_keep_alive=true" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "Checking activity on branch: $default_branch"
last_commit_date=$(gh api "repos/${{ github.repository }}/commits/$default_branch" --jq '.commit.committer.date')
last_commit_date=$(gh api "repos/$GH_REPO/commits/$default_branch" --jq '.commit.committer.date')
echo "Last commit date: $last_commit_date"

last_commit_seconds=$(date -d "$last_commit_date" +%s)
current_seconds=$(date +%s)
days_diff=$(( (current_seconds - last_commit_seconds) / 86400 ))
echo "Days since last activity: $days_diff"
echo "Days since last commit on $default_branch: $days_diff"

if [ "$days_diff" -lt 30 ]; then
echo "Active (< 30 days). No keep-alive needed."
echo "run_keep_alive=false" >> $GITHUB_OUTPUT
echo "run_keep_alive=false" >> "$GITHUB_OUTPUT"
else
echo "Inactive ($days_diff days). Running keep-alive."
echo "run_keep_alive=true" >> $GITHUB_OUTPUT
echo "run_keep_alive=true" >> "$GITHUB_OUTPUT"
fi

- name: Ensure keep-alive branch and PR exist
- name: Enable scheduled workflows via API
if: ${{ steps.check_activity.outputs.run_keep_alive == 'true' }}
env:
GH_TOKEN: ${{ github.token }}
COMMIT_MSG: |
chore: keep scheduled workflows alive
PR_BODY: |
Draft PR maintained by the keep-alive workflow. Do not merge or delete.
shell: bash
run: |
branch_name="keep-alive-workflow"
default_branch="${{ github.event.repository.default_branch }}"
if [ -z "$default_branch" ]; then
default_branch="main"
fi

git config --local user.name "github-actions[bot]"
git config --local user.email "github-actions[bot]@users.noreply.github.com"

if git ls-remote --heads origin "$branch_name" | grep -q "$branch_name"; then
echo "Branch exists"
git fetch origin "$branch_name"
git checkout "$branch_name"
git pull origin "$branch_name"
else
echo "Creating branch"
git checkout -b "$branch_name"
fi

git commit --allow-empty -m "$COMMIT_MSG"
git push origin "$branch_name"
set -euo pipefail

pr_number=$(gh pr list --head "$branch_name" --state all --json number --jq '.[0].number' 2>/dev/null || echo "")
workflow_ids_raw=$(gh api --paginate "repos/$GH_REPO/actions/workflows" \
--jq '.workflows[] | select(.state == "active" or .state == "disabled_inactivity") | "\(.id)\t\(.name)"')

if [ -z "$pr_number" ]; then
echo "Creating draft PR"
gh pr create --draft --head "$branch_name" --base "$default_branch" \
--title "chore: keep scheduled workflows alive" --body "$PR_BODY"
mapfile -t workflow_entries <<< "$workflow_ids_raw"

pr_number=$(gh pr list --head "$branch_name" --state all --json number --jq '.[0].number')
echo "Created PR #$pr_number"
else
echo "PR #$pr_number exists"
fi
for entry in "${workflow_entries[@]}"; do
workflow_id="${entry%%$'\t'*}"
workflow_name="${entry#*$'\t'}"
echo "Enabling: $workflow_name (id: $workflow_id)"
gh api -X PUT "repos/$GH_REPO/actions/workflows/$workflow_id/enable"
done

echo "pr_number=$pr_number" >> $GITHUB_OUTPUT
id: setup
echo "Enabled ${#workflow_entries[@]} workflow(s)"

- name: Reopen and close PR to maintain activity
- name: Push keep-alive branch
if: ${{ steps.check_activity.outputs.run_keep_alive == 'true' }}
env:
GH_TOKEN: ${{ github.token }}
COMMIT_MSG: "Empty commit to keep workflows alive"
shell: bash
run: |
pr_number="${{ steps.setup.outputs.pr_number }}"
set -euo pipefail
default_branch="${{ steps.check_activity.outputs.default_branch }}"

if [ -z "$pr_number" ]; then
echo "Error: PR number not found"
exit 1
fi
git config --local user.name "github-actions[bot]"
git config --local user.email "github-actions[bot]@users.noreply.github.com"

pr_state=$(gh pr view "$pr_number" --json state --jq '.state')
echo "PR #$pr_number is $pr_state"
git fetch origin "$default_branch"
git checkout -b "$BRANCH_NAME" "origin/$default_branch"

if [[ "$pr_state" == "CLOSED" ]]; then
echo "Reopening PR #$pr_number"
gh pr reopen "$pr_number"
fi
git commit --allow-empty -m "$COMMIT_MSG"
git push --force origin "$BRANCH_NAME"

echo "Closing PR #$pr_number"
gh pr close "$pr_number" --comment "Keep-alive: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
- name: Open PR if none exists
if: ${{ steps.check_activity.outputs.run_keep_alive == 'true' }}
env:
PR_TITLE: "[DO-NOT-CLOSE] Keep scheduled workflows alive"
PR_BODY: |
Draft PR maintained by the keep-alive workflow.

> [!IMPORTANT]
> Do not merge or close.

[![Build Status](https://github.com/SteeltoeOSS/NetCoreToolTemplates/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/SteeltoeOSS/NetCoreToolTemplates/actions/workflows/build.yml?query=branch%3Amain)
shell: bash
run: |
set -euo pipefail
default_branch="${{ steps.check_activity.outputs.default_branch }}"

echo "Keep-alive completed"
existing_pr_number=$(gh pr list --head "$BRANCH_NAME" --state open --json number --jq '.[0].number // empty' || echo "")
if [ -n "$existing_pr_number" ]; then
echo "PR #$existing_pr_number already open"
else
new_pr_url=$(gh pr create --draft --head "$BRANCH_NAME" --base "$default_branch" \
--title "$PR_TITLE" --body "$PR_BODY")
new_pr_number="${new_pr_url##*/}"
if ! [[ "$new_pr_number" =~ ^[0-9]+$ ]]; then
echo "Error: could not parse PR number from: $new_pr_url"
exit 1
fi
echo "Created PR #$new_pr_number"
fi
Loading