Skip to content

Workflow file for this run

name: Update Workflow Files Across Repos
on:
push:
branches: [main]
workflow_dispatch:
env:
IMAGE_NAME: template-files
jobs:
changesets:
name: Changesets
runs-on: ubuntu-latest
outputs:
hasChangesets: ${{ steps.changesets.outputs.hasChangesets }}
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup PNPM
uses: pnpm/action-setup@v3
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"
- name: Install Dependencies
run: pnpm i
- name: Create Release Pull Request
id: changesets
uses: changesets/action@v1
with:
commit: "[ci] release"
title: "[ci] release"
env:
GITHUB_TOKEN: ${{ secrets.PUBLIC_GITHUB_TOKEN }}
prepare-matrix:
name: Prepare Matrix
runs-on: ubuntu-latest
outputs:
repo-matrix: ${{ env.REPO_MATRIX }}
steps:
- name: Checkout current repository
uses: actions/checkout@v4
- name: Install jq
run: sudo apt-get install -y jq
- name: Read Repositories from JSON
id: set-matrix
run: |
repos=$(jq -c '.repositories[] | {name: .name, files: .files}' repos.json | jq -s .)
{
echo "REPO_MATRIX<<EOF"
echo ${repos}
echo EOF
} >> $GITHUB_ENV
- name: Print Matrix
run: echo "${{ env.REPO_MATRIX }}"
sync-workflows:
runs-on: ubuntu-latest
needs: [changesets, prepare-matrix]
strategy:
matrix:
repo: ${{ fromJson(needs.prepare-matrix.outputs.repo-matrix) }}
if: >
(
needs.changesets.outputs.hasChangesets == 'false' &&
(
contains(github.event.head_commit.message, 'deploy') ||
contains(github.event.head_commit.message, '[ci] release')
)
) ||
github.event_name == 'workflow_dispatch'
steps:
- name: Checkout current repository
uses: actions/checkout@v4
- name: Install jq
run: sudo apt-get install -y jq
- name: Update workflows in target repository
env:
GH_TOKEN: ${{ secrets.PUBLIC_GITHUB_TOKEN }}
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
repo_name="${{ matrix.repo.name }}"
files='${{ toJson(matrix.repo.files) }}'
echo "Processing repository: $repo_name"
# Clone the target repository
echo "Cloning repository $repo_name..."
git clone --depth 1 "https://x-access-token:${GH_TOKEN}@github.com/${repo_name}.git" target-repo
cd target-repo
# Create or switch to the branch
branch_name="update-workflows"
echo "Creating branch $branch_name..."
git checkout -b "$branch_name" || git checkout "$branch_name"
# Sync specified workflow files
for file_config in $(echo "$files" | jq -c '.[]'); do
src_file=$(echo "$file_config" | jq -r '.path')
dest_file=$(echo "$file_config" | jq -r '.targetPath')
special=$(echo "$file_config" | jq -r '.special // empty')
echo "Processing file: $src_file as $processing"
# Check if the file exists in the template-files directory
if [ ! -f "../$src_file" ]; then
echo "Warning: File $src_file not found in /template-files."
continue
fi
if [ "$special" == "true" ]; then
if [[ "$dest_file" == "README.md" ]]; then
echo "Special handling for README.md"
# Extract the License section dynamically from the template README.md
license_section=$(awk '/## License/,0' "../$src_file")
if [ -z "$license_section" ]; then
echo "Error: License section not found in template README.md"
continue
fi
# Combine existing README.md with the License section
if [ -f "$dest_file" ]; then
# Append the License section to the existing README.md
cat "$dest_file" > temp_readme.md
echo -e "\n$license_section" >> temp_readme.md
# Deduplicate and ensure the License section is at the end
awk '!seen[$0]++' temp_readme.md > "$dest_file"
rm temp_readme.md
else
# If no existing README.md, copy the template and add the License section
cp "../$src_file" "$dest_file"
echo -e "\n$license_section" >> "$dest_file"
fi
elif [[ "$dest_file" == "package.json" ]]; then
echo "Special handling for package.json"
temp_file=$(mktemp)
jq -s 'reduce .[] as $item ({}; . * $item)' "../$src_file" "$dest_file" > "$temp_file"
mv "$temp_file" "$dest_file"
fi
else
# Prepare the destination directory
mkdir -p "$(dirname "$dest_file")"
# Handle dynamic content replacement if "props" is specified
props=$(echo "$file_config" | jq -c '.props // empty')
if [ -n "$props" ]; then
echo "Applying dynamic replacements for $src_file..."
temp_file=$(mktemp)
cp "../$src_file" "$temp_file"
# Replace placeholders with their respective values from props
for key in $(echo "$props" | jq -r 'keys[]'); do
value=$(echo "$props" | jq -r --arg key "$key" '.[$key]')
placeholder="<%= $key %>"
echo "Replacing $placeholder with $value in $src_file..."
sed -i "s|$placeholder|$value|g" "$temp_file"
done
# Move the processed file to the target location
mv "$temp_file" "$dest_file"
else
# If no props, copy the file directly
cp "../$src_file" "$dest_file"
fi
fi
done
# Post-processing: Run pnpm install only if package.json was modified
if git diff --name-only --cached | grep -q "package.json"; then
echo "package.json was modified. Running pnpm install..."
pnpm install
else
echo "No changes to package.json detected. Skipping pnpm install."
fi
# Commit and push changes if any
echo "Checking for changes..."
git add .
if git diff --cached --quiet; then
echo "No changes detected for $repo_name."
else
# Run Prettier before committing (TODO)
# echo "Formatting code with Prettier..."
# pnpm prettier --write .
echo "Committing and pushing changes for $repo_name..."
git commit -m "Update GitHub workflow files"
git push --force origin "$branch_name"
cd ..
latest_commit_hash=$(git rev-parse HEAD)
latest_commit_url="https://github.com/$GITHUB_REPOSITORY/commit/$latest_commit_hash"
latest_commit_message=$(git log -1 --pretty=%s)
latest_commit_entry="- $latest_commit_message - ([$(git rev-parse --short HEAD)]($latest_commit_url))"
cd target-repo
# Check for existing pull request
echo "Checking for an open PR for branch $branch_name..."
existing_pr=$(gh pr list --base main --head "$branch_name" --json number --jq '.[0].number')
if [ -n "$existing_pr" ]; then
echo "Found existing PR #$existing_pr. Updating it..."
current_body=$(gh pr view "$existing_pr" --json body --jq '.body')
updated_body=$(printf "%s\n%s" "$current_body" "$latest_commit_entry")
gh pr edit "$existing_pr" --body "$updated_body"
gh pr comment "$existing_pr" --body "The branch has been updated with the [latest changes]($latest_commit_url)."
else
echo "No existing PR found. Creating a new one..."
description=$(printf "%s\n\n%s\n%s" "This PR syncs the specified GitHub workflow files from the [central repository](https://github.com/trueberryless-org/template-files)." "### Changes:" "$latest_commit_entry")
gh pr create \
--base main \
--head "$branch_name" \
--title "Sync workflow files" \
--body "$description"
fi
fi
# Cleanup
cd ..
echo "Cleaning up repository clone for $repo_name..."
rm -rf target-repo
image-tag:
name: Image Tag
runs-on: ubuntu-latest
outputs:
IMAGE_TAG: ${{ env.IMAGE_TAG }}
steps:
- name: Check out the repo
uses: actions/checkout@v4
- name: Read version from package.json
id: get_version
run: |
VERSION=$(jq -r '.version' package.json)
echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV
release:
name: Release
needs: [sync-workflows, image-tag]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Check out the repo
uses: actions/checkout@v4
- id: extract-changelog
uses: sean0x42/[email protected]
with:
file: CHANGELOG.md
pattern: ${{ needs.image-tag.outputs.IMAGE_TAG }}
- uses: ncipollo/release-action@v1
id: create_release
with:
tag: ${{ env.IMAGE_NAME }}@${{ needs.image-tag.outputs.IMAGE_TAG }}
makeLatest: true
body: ${{ steps.extract-changelog.outputs.markdown }}
skipIfReleaseExists: true
- name: Check if release was created
id: check_release
run: |
if [ -z "${{ steps.create_release.outputs.html_url }}" ]; then
echo "RELEASE_SKIPPED=true" >> $GITHUB_ENV
else
echo "RELEASE_SKIPPED=false" >> $GITHUB_ENV
fi
- name: Discord notification
if: env.RELEASE_SKIPPED == 'false'
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL }}
uses: Ilshidur/[email protected]
with:
args: |
# ${{ env.IMAGE_NAME }}@${{ needs.image-tag.outputs.IMAGE_TAG }}
${{ steps.extract-changelog.outputs.markdown }}