Fragment: Using Git Commit Messages as a Command Line?

Pondering the way in which the fastai/fastpages repo (as described here) generates a PR from the first commit after the repo is cloned, I started pondering this:

name: Setup
on: push

jobs:
  setup:
    if: (github.event.commits[0].message == 'Initial commit') && (github.run_number == 1)
    runs-on: ubuntu-latest
    steps:

    - name: Set up Python
      uses: actions/setup-python@v1
      with:
        python-version: 3.6

    - name: Copy Repository Contents
      uses: actions/checkout@v2
        
    - name: modify files
      run: |
        import re, os
        from pathlib import Path
        nwo = os.getenv('GITHUB_REPOSITORY')
        username, repo_name = nwo.split('/')
        readme_template_path = Path('README_TEMPLATE.md')
        readme_path = Path('README.md')
        config_path = Path('_config.yml')
        pr_msg_path = Path('_setup_pr_template.md')
        assert readme_template_path.exists(), 'Did not find README_TEMPLATE.md in the current directory!'
        assert readme_path.exists(), 'Did not find README.md in the current directory!'
        assert config_path.exists(), 'Did not find _config.yml in the current directory!'
        assert pr_msg_path.exists(), 'Did not find _setup_pr_template.md in the current directory!'
        # replace content of README with template
        readme = readme_template_path.read_text().replace('{_username_}', username).replace('{_repo_name_}', repo_name)
        readme_path.write_text(readme)
        
        # update _config.yml
        cfg = config_path.read_text()
        cfg = re.sub(r'^(github_username: )(fastai)', r'\1{}'.format(username), cfg, flags=re.MULTILINE)
        cfg = re.sub(r'^(baseurl: )("")', r'\1"/{}"'.format(repo_name), cfg, flags=re.MULTILINE)
        cfg = re.sub(r'^(github_repo: ")(fastpages)', r'\1{}'.format(repo_name), cfg, flags=re.MULTILINE)
        cfg = re.sub(r'^(url: "https://)(fastpages.fast.ai)(")', r'\1{}.github.io\3'.format(username), cfg, flags=re.MULTILINE)
        config_path.write_text(cfg)
        # prepare the pr message
        pr = pr_msg_path.read_text().replace('{_username_}', username).replace('{_repo_name_}', repo_name)
        pr_msg_path.write_text(pr)
      shell: python

    - name: commit changes
      run: |
        git config --global user.email "${GH_EMAIL}"
        git config --global user.name "${GH_USERNAME}"
        git checkout -B fastpages-automated-setup
        git rm README_TEMPLATE.md CONTRIBUTING.md CNAME action.yml _checkbox.png
        git rm _notebooks/2020-02-21-introducing-fastpages.ipynb
        git rm .github/workflows/chatops.yaml
        git rm -rf .github/ISSUE_TEMPLATE
        git add _config.yml README.md _setup_pr_template.md
        git commit -m'setup repo'
        git push -f --set-upstream origin fastpages-automated-setup
      env: 
        GH_EMAIL: ${{ github.event.commits[0].author.email }}
        GH_USERNAME: ${{ github.event.commits[0].author.username }}

    - name: Open a PR
      uses: actions/github-script@0.5.0
      with:
        github-token: ${{secrets.GITHUB_TOKEN}}
        script: |
          var fs = require('fs');
          var contents = fs.readFileSync('_setup_pr_template.md', 'utf8');
          github.pulls.create({
                        owner: context.repo.owner,
                        repo: context.repo.repo,
                        title: 'Initial Setup',
                        head: 'fastpages-automated-setup',
                        base: 'master',
                        body: `${contents}`
                        })

In particular, the line if: (github.event.commits[0].message == 'Initial commit') got me wondering: what if we use commit messages to perform some other actions?

For example, something I keep wondering about is how to generate Binder environment specifications that can be easily reused. I’ve pondered this before in the context of “Binder base boxes”, the most useful approach (I think) being to define a basebox repo that is prebuilt and then nbgitpull your own repo into it.

Another approach I’ve idly wondered about was a simple script that could generate binder/ setups for you. For example binder_base chemistry might generate you a binder/ directory with apt.txt, requirements.txt and postBuild files preconfigured with packages that are relevant to working with chemistry related content; binder_base astronomy might create you a binder/environment.yml that will pull in a load of astronomy packages. Other switches might let you automatically add-in config info around package installation and setup for various extensions, and so on.

Putting these two together, I can imagine a commit message that would call an action that could:

  • create a domain relevant set of binder/ files;
  • commit them to the repo (if permissions available), or create a PR.

Author: Tony Hirst

I'm a Senior Lecturer at The Open University, with an interest in #opendata policy and practice, as well as general web tinkering...

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.