28

Title says it all. I tried using a bunch of different git commands like git submodule update --remote --merge and git submodule foreach git pull origin master which work fine on my computer, but not when it's run on GitHub actions. I tried adding git status to the workflow and the status just shows "Up to date with origin/master, nothing to commit" or something like that.

ma1234
  • 445
  • 1
  • 4
  • 9

8 Answers8

29

If you need to auto update references to your submodules via GitHub actions:

Create a new workflow in your parent repository that will synchronize references:

name: 'Submodules Sync'

on:
  # Allows you to run this workflow manually from the Actions tab or through HTTP API
  workflow_dispatch:

jobs:
  sync:
    name: 'Submodules Sync'
    runs-on: ubuntu-latest

    # Use the Bash shell regardless whether the GitHub Actions runner is ubuntu-latest, macos-latest, or windows-latest
    defaults:
      run:
        shell: bash

    steps:
    # Checkout the repository to the GitHub Actions runner
    - name: Checkout
      uses: actions/checkout@v2
      with:
        token: ${{ secrets.CI_TOKEN }}
        submodules: true

    # Update references
    - name: Git Sumbodule Update
      run: |
        git pull --recurse-submodules
        git submodule update --remote --recursive

    - name: Commit update
      run: |
        git config --global user.name 'Git bot'
        git config --global user.email 'bot@noreply.github.com'
        git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
        git commit -am "Auto updated submodule references" && git push || echo "No changes to commit"

where

  • CI_TOKEN is a security token variable in GitHub that have 'Read-Write' access to the parent repository, and 'Read' access to submodule repositories.

In the child (submodule) GitHub action notify the parent about changes.

name: 'Submodule Notify Parent'

on:
  push:
    branches:
      - main    

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:
  notify:
    name: 'Submodule Notify Parent'
    runs-on: ubuntu-latest

    # Use the Bash shell regardless whether the GitHub Actions runner is ubuntu-latest, macos-latest, or windows-latest
    defaults:
      run:
        shell: bash

    steps:
    - name: Github REST API Call
      env:
        CI_TOKEN: ${{ secrets.CI_TOKEN }}
        PARENT_REPO: <my_organization/my-app>
        PARENT_BRANCH: develop
        WORKFLOW_ID: <9999999>
      run: |
        curl -fL --retry 3 -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token ${{ env.CI_TOKEN }}" https://api.github.com/repos/${{ env.PARENT_REPO }}/actions/workflows/${{ env.WORKFLOW_ID }}/dispatches -d '{"ref":"${{ env.PARENT_BRANCH }}"}'

where

  • PARENT_REPO - name of the parent repository as it is in Github (my_org/my_app or just my_app if there is no organization).
  • WORKFLOW_ID - parent Wofklow ID to call via rest API. To find it run curl using your CI_TOKEN:
    curl -X GET -H "Authorization: token $CI_TOKEN" https://api.github.com/repos/$PARENT_REPO/actions/workflows
    

Repeat the workflow creation for every submodule.


P.S. For me it works very stable. Please add information about existing github actions with the above logic if there is any.

Artur A
  • 7,115
  • 57
  • 60
  • If you had no way to run workflows on the submodule, could you just run the first workflow on a schedule? – ma1234 Apr 12 '21 at 21:50
  • 2
    Hi @ma1234, yes, it is possible to set up a schedule for workflow run, please refer to https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events Though in this case there will be time intervals when the parent branch is out of sync with submodule references. – Artur A Apr 13 '21 at 01:42
15

A much better option today is to utilize Dependabot to auto create PRs for submodules.

https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem

A sample that checks daily if a submodule has been updated: In .github/dependabot.yml

version: 2

updates:
  - package-ecosystem: gitsubmodule
    schedule:
        interval: "daily"
    directory: /
aknosis
  • 3,602
  • 20
  • 33
14

You can achieve this with a single action in the submodule repository:

name: Send submodule updates to parent repo

on:
  push:
    branches: 
      - main

jobs:
  update:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
        with: 
          repository: org/parent_repository
          token: ${{ secrets.PRIVATE_TOKEN_GITHUB }}
          submodules: true

      - name: Pull & update submodules recursively
        run: |
          git submodule update --init --recursive
          git submodule update --recursive --remote

      - name: Commit
        run: |
          git config user.email "actions@github.com"
          git config user.name "GitHub Actions - update submodules"
          git add --all
          git commit -m "Update submodules" || echo "No changes to commit"
          git push

You need to:

With this action, every push on the main branch in the submodule repository will result in a commit pulling the update in the parent repository.

Droplet
  • 935
  • 9
  • 12
  • 2
    Remember to add submodules: 'true' below repository: in with: – GILO Apr 19 '22 at 10:51
  • Doesn't it kind of suck to have this global personal access token in this workflow @Droplet? – Eric Carmichael Sep 11 '22 at 22:01
  • @EricCarmichael, it's a tough question, especially when framed so generally. Depends on your threat model. I can give two general answers, which may or may not apply well to your specific case: 1. It is generally considered safer/better practice to use the built-in GITHUB_TOKEN PAT **when possible** because it has restricted permissions & scope (but we don't have this option here). 2. It would be ideal if GitHub allowed us to create PAT with permissions linked to a specific repo, instead of all your repos. – Droplet Sep 12 '22 at 09:40
  • Regarding my second point, this answer https://stackoverflow.com/a/63296569/4439357 seems to propose an interesting alternative: use a deploy key instead of a PAT. I'll have a look and update my answer if it works. Thanks! – Droplet Sep 12 '22 at 09:41
  • Another possible answer: I didn't mention it but in my organisation, we have a dedicated machine user (https://docs.github.com/en/developers/overview/managing-deploy-keys#machine-users) and we use its PAT for automation. In the worst case scenario, where someone steals the PAT, the damage is more limited – Droplet Sep 12 '22 at 10:25
  • 1
    @Droplet thanks for all of the info! So a "Deploy key" can make commits and such? – Eric Carmichael Sep 13 '22 at 17:18
  • Action runs successfully but the submodule is not updated. Shouldn't the step `git submodule update --recursive --remote` run on the parent repo? when i run this directly in the parent repo it updated the submodule. Should the PRIVATE_TOKEN be present in both repos? Thanks! – Ilir Jun 16 '23 at 12:28
  • Yes, the `git submodule update` step has to run in the parent repo. But this is already the case if you set the "repository" option value correctly in the `actions/checkout` step, as documented in the answer. The `PRIVATE_TOKEN` needs write access to the parent repo but should be in the secrets of the submodule repo, where this workflow lives. – Droplet Jun 19 '23 at 15:13
7

Simple solution

You pull and update the submodules recursively and then commit to the repo.

name: Update submodules

# Controls when the action will run.
on:
  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:
  # This workflow contains a single job called "update"
  update:
    runs-on: ubuntu-latest

    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      - name: Pull & update submodules recursively
        run: |
          git submodule update --init --recursive
          git submodule update --recursive --remote

      - name: Commit & push changes
        run: |
          git config --global user.name ${{ secrets.USER_NAME }}
          git config --global user.email ${{ secrets.USER_EMAIL }}
          git commit -am "Update submodules"
          git push

Instead of using Github secrets like ${{ secrets.USER_NAME }} I just hard code my git credentials since I'm lazy, but I figured you might care about security.

Nermin
  • 749
  • 7
  • 17
1

i try this it working for me

- uses: actions/checkout@v3
      with:
        repository: {owner}/repo
        token: ${{ secrets.PRIVATE_TOKEN_GITHUB }}
        submodules: recursive

    - name: submodules recursively
      run: git submodule update --init --recursive
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 22 '22 at 08:03
0

You can compare your GitHub Action source with one like submodule-branch-check, which does make at least a git submodule update.

Check if the update --remote is enough to pull from its own remote origin.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
0

it working for me, read acticle in here https://zenn.dev/ymmmtym/articles/dc741561759a49

name: Update submodules
on:
  push:
    branches:
      - dev
  pull_request:
    branches:
      - dev
jobs:
  update_submodules:
    name: Update submodules
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
      with:
        token : ${{secrets.OOG_TOKEN}}
        submodules : true
    - name: Update submodules
      id: update
      run: git submodule update --remote --recursive 
    - name: Run git status
      id: status
      run: echo "::set-output name=status::$(git status -s)"
    - name: Add and commit files
      run: |
        git add .
        git config --local user.email "action@github.com"
        git config --local user.name "GitHub Action"
        git commit -m "Update submodules at $(date "+DATE: %Y-%m-%d TIME: %H:%M:%S")"
      if: ${{ steps.status.outputs.status }}
    - name: Push changes
      uses: ad-m/github-push-action@master
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        branch: dev
      if: ${{ steps.status.outputs.status && github.event_name == 'push' }}
ChuongHo
  • 33
  • 5
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 22 '22 at 10:08
0

I was able to implement @Droplet's solution! I extended it to update multiple parent repos that are using the submodule using a matrix like so:

on:
  push:
    branches: 
      - master

jobs:
  update_parent_repos:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        parent_repo: [parent_repo_1, parent_repo_2]

    steps:
      - uses: actions/checkout@v3
        with: 
          repository: myriadgenetics/${{ matrix.parent_repo }}
          token: ${{ secrets.ACTIONS_TOKEN }}
          submodules: 'recursive'
      - name: Pull & update submodules recursively
        run: |
          git submodule update --init --recursive
          git submodule update --recursive --remote
      - name: Commit
        run: |
          git config user.email "actions@github.com"
          git config user.name "GitHub Actions - update submodules"
          git add --all
          git commit -m "Update submodules" || echo "No changes to commit"
          git push

You will have to use the correct label for the action runner for your use case if it isn't ubuntu-latest, update parent_repo_1 and parent_repo_2 to the names of the parent repos you want to update the submodule in, and use the correct token name for your use case. I for some reason had to include submodules: 'recursive' otherwise was running into issues when running the commands within "Pull & update submodules recursively".

Yash Patel
  • 31
  • 1
  • 2