Sync from upstream #126
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
| name: Sync from upstream | |
| on: | |
| schedule: | |
| - cron: '0 * * * *' # Hourly at the top of every hour | |
| workflow_dispatch: # Manual trigger | |
| env: | |
| UPSTREAM_REPO: "garrytan/gstack" | |
| FILTER_SCRIPT: "scripts/filter_skills.py" | |
| CLEANUP_SCRIPT: "scripts/cleanup.py" | |
| jobs: | |
| sync: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install Fireworks AI SDK | |
| run: | | |
| pip install --pre fireworks-ai | |
| - name: Configure Git | |
| run: | | |
| git config user.name "Ambisphaeric" | |
| git config user.email "Ambisphaeric@users.noreply.github.com" | |
| - name: Add upstream remote | |
| run: | | |
| git remote add upstream https://github.com/${{ env.UPSTREAM_REPO }}.git | |
| git fetch upstream main --tags 2>/dev/null || git fetch upstream master --tags 2>/dev/null || true | |
| - name: Get upstream info | |
| id: upstream | |
| run: | | |
| UPSTREAM_BRANCH=$(git rev-parse --verify upstream/main 2>/dev/null || git rev-parse --verify upstream/master 2>/dev/null || echo "") | |
| echo "sha=$UPSTREAM_BRANCH" >> $GITHUB_OUTPUT | |
| if [ -n "$UPSTREAM_BRANCH" ]; then | |
| UPSTREAM_VERSION=$(git ls-remote upstream refs/tags/v* 2>/dev/null | sort -V | tail -1 | sed 's/.*v//' || echo "unknown") | |
| echo "version=$UPSTREAM_VERSION" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Check for updates | |
| id: check | |
| run: | | |
| CURRENT=$(git rev-parse HEAD 2>/dev/null || echo "") | |
| UPSTREAM=${{ steps.upstream.outputs.sha }} | |
| if [ -z "$UPSTREAM" ]; then | |
| echo "updating=false" >> $GITHUB_OUTPUT | |
| echo "No upstream found" | |
| exit 0 | |
| fi | |
| if [ "$CURRENT" = "$UPSTREAM" ]; then | |
| echo "updating=false" >> $GITHUB_OUTPUT | |
| echo "Already up to date with upstream" | |
| else | |
| echo "updating=true" >> $GITHUB_OUTPUT | |
| echo "Updates available from upstream" | |
| fi | |
| - name: Create sync branch | |
| if: steps.check.outputs.updating == 'true' | |
| run: | | |
| BRANCH_NAME="sync/upstream-$(date +%Y%m%d-%H%M%S)" | |
| git checkout -b "$BRANCH_NAME" | |
| echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT | |
| id: branch | |
| - name: Intelligent merge from upstream | |
| if: steps.check.outputs.updating == 'true' | |
| env: | |
| FIREWORKS_API_KEY: ${{ secrets.AI_KEY }} | |
| run: | | |
| # Attempt clean merge first | |
| if git merge upstream/main --no-edit -m "chore: merge from ${{ env.UPSTREAM_REPO }}" 2>/dev/null; then | |
| echo "Clean merge successful" | |
| else | |
| echo "Merge conflicts detected, using AI to resolve..." | |
| git merge --abort 2>/dev/null || true | |
| # Get list of conflicting files | |
| git merge upstream/main --no-commit || true | |
| CONFLICTS=$(git diff --name-only --diff-filter=U) | |
| if [ -n "$CONFLICTS" ]; then | |
| echo "Resolving conflicts with Fireworks AI for:" | |
| echo "$CONFLICTS" | |
| python3 << 'PYEOF' | |
| import os | |
| import sys | |
| import subprocess | |
| from fireworks.client import Fireworks | |
| client = Fireworks(api_key=os.environ['FIREWORKS_API_KEY']) | |
| # Get conflicted files | |
| result = subprocess.run(['git', 'diff', '--name-only', '--diff-filter=U'], | |
| capture_output=True, text=True) | |
| conflicts = result.stdout.strip().split('\n') | |
| for filepath in conflicts: | |
| if not filepath: | |
| continue | |
| try: | |
| with open(filepath, 'r') as f: | |
| content = f.read() | |
| # Use AI to resolve the conflict | |
| response = client.chat.completions.create( | |
| model="accounts/fireworks/models/llama-v3p1-70b-instruct", | |
| messages=[ | |
| {"role": "system", "content": "You are a code merge expert. Resolve git conflicts by keeping the best parts of both versions, preferring the incoming upstream changes while preserving OpenGStack's telemetry removal modifications."}, | |
| {"role": "user", "content": f"Resolve this git conflict in {filepath}:\n\n```\n{content}\n```\n\nReturn only the resolved file content without any explanation."} | |
| ] | |
| ) | |
| resolved = response.choices[0].message.content | |
| # Clean up code fence markers if present | |
| resolved = resolved.replace('```', '').strip() | |
| with open(filepath, 'w') as f: | |
| f.write(resolved + '\n') | |
| subprocess.run(['git', 'add', filepath]) | |
| print(f"Resolved: {filepath}") | |
| except Exception as e: | |
| print(f"Error resolving {filepath}: {e}") | |
| sys.exit(1) | |
| # Complete the merge | |
| subprocess.run(['git', 'commit', '-m', 'chore: merge from upstream with AI conflict resolution']) | |
| PYEOF | |
| fi | |
| fi | |
| - name: Apply opengstack filters | |
| if: steps.check.outputs.updating == 'true' | |
| run: | | |
| python3 ${{ env.FILTER_SCRIPT }} . | |
| python3 ${{ env.CLEANUP_SCRIPT }} . | |
| - name: Commit filtered changes | |
| if: steps.check.outputs.updating == 'true' | |
| run: | | |
| git add -A | |
| git diff --cached --quiet || git commit -m "chore: apply opengstack filters" | |
| - name: Push sync branch | |
| if: steps.check.outputs.updating == 'true' | |
| run: | | |
| git push origin ${{ steps.branch.outputs.branch_name }} | |
| - name: Create Pull Request | |
| if: steps.check.outputs.updating == 'true' | |
| uses: peter-evans/create-pull-request@v6 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| branch: ${{ steps.branch.outputs.branch_name }} | |
| base: main | |
| title: "chore: sync from garrytan/gstack v${{ steps.upstream.outputs.version }}" | |
| body: | | |
| ## Sync Report | |
| Merged latest changes from [garrytan/gstack](https://github.com/${{ env.UPSTREAM_REPO }}). | |
| **Upstream version:** v${{ steps.upstream.outputs.version }} | |
| Applied filters: | |
| - Removed telemetry/analytics | |
| - Removed YC references | |
| - Removed garrytan-specific content | |
| - Merged using Fireworks AI (FIREWORKS_API_KEY) | |
| **Note:** Merge this PR to complete the sync. Do not push directly to main. | |
| draft: false | |
| - name: Create version tag (after PR merge) | |
| if: steps.check.outputs.updating == 'true' | |
| run: | | |
| UPSTREAM_VERSION="${{ steps.upstream.outputs.version }}" | |
| if [ -n "$UPSTREAM_VERSION" ] && [ "$UPSTREAM_VERSION" != "unknown" ]; then | |
| TAG="v${UPSTREAM_VERSION}.0" | |
| echo "::notice::After merging the PR, create tag: $TAG" | |
| fi |