Search code examples
yamlgithub-actions

How to use GitHub Actions to pull specfic files from someone else's repository when they get updates?


I'd like to utilize Github Actions to pull specific files from another repo whenever they get updated.

What I tried to do is:

  1. Pull specific files from someone else's repo (and use a token if it's a private repo).
  2. Rename some of those files.
  3. Create a PR with them in my repo.
  4. Allow to control whether to do manually or also automatically (when the source repo updates itself).

If I somehow missed older questions about it, remember it needs to use the latest Node version due to Github's blockage of older Node versions.

Sample code (trying to pull from a public repo) is below (with v3 in actions/checkout@v3 in an attempt to use the latest Node), but how to make it trigger when someone else's repo updates its files?

Sample code (Updated):

name: Pull File from Another Repository on Push
env:
  SOURCE_REPO: https://github.com/some/repo
  AUTOMATIC_MONITOR: true
  FILES: "*.txt,LICENSE" # seperate multiple entries with ,
  FILES_NEW: "*.txt,LICENSE*" # seperate multiple entries with ,
  EXTRA: mv LICENSE LICENSE_some_repo # do an extra command like renaming
  USERNAME: ${{ github.actor }}
  ADDRESS_SUFFIX: users.noreply.github.com
  # TOKEN_NAME: ACCESS_TOKEN # uncomment to use a secret with that name
  # SOURCE_BRANCH: source_alternate # uncomment to not monitor the default branch
  # TARGET_BRANCH: target_alternate # uncomment to not push to default branch

on: # Remove # below for non default branches
  workflow_dispatch:
#    inputs:
#      source_branch:
#        description: '${{ env.SOURCE_BRANCH }}'
#        required: false
  push:
#    branches:
#      - ${{ env.SOURCE_BRANCH }}
    paths:
      - ./source-repo/**

jobs:
  pull-file:
    runs-on: ubuntu-latest
    steps:
      - name: Check whether to automatically monitor
        if: ${{ github.event_name != 'workflow_dispatch' && env.AUTOMATIC_MONITOR == false }}
        run: |
          exit 1

      - name: Checkout
        uses: actions/checkout@v3

      - name: Pull File
        env:
          # THE_TOKEN: ${{ secrets.$TOKEN_NAME }}
          EVENT_NAME: ${{ github.event_name }}
          SOURCE_BRANCH: ${{ github.event.inputs.source_branch }}
          REF: ${{ github.ref }}
        run: |
          #!/bin/sh
          
          if [ -n "$TOKEN_NAME" ]; then
            REPO_URL=https://$THE_TOKEN@$SOURCE_REPO.git
          else
            REPO_URL=$SOURCE_REPO.git
          fi
          
          if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
            if [ -n "$SOURCE_BRANCH" ]; then
              git clone -b $SOURCE_BRANCH $REPO_URL source-repo
            else
              git clone $REPO_URL source-repo
            fi
          else
            git clone -b $REF $REPO_URL source-repo
          fi
          cd source-repo
          $EXTRA
          cp -u $FILES_NEW ../
          cd ..

      - name: Commit
        run: |
          git config user.name "$USERNAME"
          git config user.email "$USERNAME@$ADDRESS_SUFFIX"
          git add $FILES_NEW
          git commit -m "Pulled files from $SOURCE_REPO."

      - name: Push
        run: |
          if [ -n "$TARGET_BRANCH" ]; then
            git push origin $TARGET_BRANCH
          else
            git push
          fi

Solution

  • So since it seems repositories can't be tracked by other repositories' GitHub Actions, I've come up with the following code that:

    1. Runs manually if needed.
    2. Automatically (can be turned off) monitors your own pushes, only specific branches and folders if needed.
    3. Upon a push grabs another repository's files - it can use tokens for private repos and/or if needed grab specific branches.
    4. It renames the files you want and - only if they're updated - copies them to your own repo.
    5. Only if they're updated - re-commits and re-pushes them to your repo (thankfully GitHub has loop protection).

    The only thing I would hope is to find a way to only define branches and paths for the push monitoring if they're needed instead of commenting them out if they're not needed.

    The code:

    name: Pull Files from Another Repository on Push
    env:
      SOURCE_REPO: owner/repo
      AUTOMATIC_MONITOR: true
      FILES: "*.txt,LICENSE" # seperate multiple entries with ,
      FILES_NEW: "*.txt,LICENSE*" # seperate multiple entries with ,
      EXTRA: mv LICENSE LICENSE_some_repo # do an extra command like renaming
      USERNAME: ${{ github.actor }}
      ADDRESS_SUFFIX: users.noreply.github.com
      TOKEN_NAME: ACCESS_TOKEN # name of token defined in the target repo's settings, needed for private repos
      # SOURCE_BRANCH: source_alternate_branch # uncomment to takes files from a non default source branch
      # TARGET_BRANCH: target_alternate_branch # uncomment to monitor a non default target branch
      # TARGET_PATH: target_alternate_path # uncomment to monitor a non default target branch
      THE_SERVER: ${{ github.server_url }}
      PATH_SOURCE_CHECKOUT: temp_folder
      THE_SECRET: ${{ secrets.TOKEN_NAME || 'default_value' }}
    
    on: # Remove # below for non default branches
      workflow_dispatch:
      push:
    #    branches:
    #      - ${{ env.TARGET_BRANCH }}
    #    paths:
    #      - ${{ env.TARGET_PATH }}
    
    jobs:
      pull-file:
        runs-on: ubuntu-latest
        steps:
          - name: Check whether to automatically monitor
            if: ${{ github.event_name != 'workflow_dispatch' && env.AUTOMATIC_MONITOR == false }}
            run: |
              echo "Set not to run automatically. Exiting."
              echo "exiting1=true" >> $GITHUB_ENV
    
          - name: Checkout
            if: env.exiting1 != 'true'
            uses: actions/checkout@v3
    
          - name: Checkout source with token and branch
            if: env.exiting1 != 'true' && env.THE_SECRET != 'default_value' && env.SOURCE_BRANCH
            uses: actions/checkout@v3
            with:
              repository: ${{ env.SOURCE_REPO }}
              ref: ${{ env.SOURCE_BRANCH }}
              token: ${{ secrets[env.TOKEN_NAME] }}
              path: ${{ env.PATH_SOURCE_CHECKOUT }}
    
          - name: Checkout source with token but without branch
            if: env.exiting1 != 'true' && env.THE_SECRET != 'default_value' && !env.SOURCE_BRANCH
            uses: actions/checkout@v3
            with:
              repository: ${{ env.SOURCE_REPO }}
              token: ${{ secrets[env.TOKEN_NAME] }}
              path: ${{ env.PATH_SOURCE_CHECKOUT }}
    
          - name: Checkout source without token but with branch
            if: env.exiting1 != 'true' && env.THE_SECRET == 'default_value' && env.SOURCE_BRANCH
            uses: actions/checkout@v3
            with:
              repository: ${{ env.SOURCE_REPO }}
              ref: ${{ env.SOURCE_BRANCH }}
              path: ${{ env.PATH_SOURCE_CHECKOUT }}
    
          - name: Checkout source without token and without branch
            if: env.exiting1 != 'true' && env.THE_SECRET == 'default_value' && !env.SOURCE_BRANCH
            uses: actions/checkout@v3
            with:
              repository: ${{ env.SOURCE_REPO }}
              path: ${{ env.PATH_SOURCE_CHECKOUT }}
    
          - name: Update
            if: env.exiting1 != 'true'
            run: |
              cd $PATH_SOURCE_CHECKOUT
              $EXTRA
              cp -u $FILES_NEW ../
              cd ..
    
          - name: Check for changes
            if: env.exiting1 != 'true'
            run: |
              if git diff --quiet; then
                echo "No changes detected. Exiting."
                echo "exiting2=true" >> $GITHUB_ENV
              fi
              
          - name: Commit
            if: env.exiting1 != 'true' && env.exiting2 != 'true'
            run: |
              git config user.name "$USERNAME"
              git config user.email "$USERNAME@$ADDRESS_SUFFIX"
              git add $FILES_NEW
              git commit -m "Pulled files from $THE_SERVER/$SOURCE_REPO."
    
          - name: Push
            if: env.exiting1 != 'true' && env.exiting2 != 'true'
            run: |
              if [ -n "$TARGET_BRANCH" ]; then
                git push origin $TARGET_BRANCH
              else
                git push
              fi