toolkit icon indicating copy to clipboard operation
toolkit copied to clipboard

Add a event to trigger a workflow if a Template Repository is instantiated

Open gprossliner opened this issue 3 years ago • 12 comments

Describe the enhancement

Provide a new event like these https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows that is triggered if a Repository is created from a Template Repository.

This would allow a Template author to automate initialization of a Repository. The workflow should run in the newly create Repository, not in the Template Repository.

Example when this would be useful

  • I have a Template named "standard-nuget-package". Within this repository, there are files and folders named like "standard-nuget-package.csproj". This Template includes a workflow triggered on instantiation (maybe template_instantiated), that renames files, folders and replaces file contents to replace "standard-nuget-package" with the name of the newly created Repository, and commits the changes.
  • Another user creates a new Repository named "MyCoolPackage"
  • The workflow triggers and performs rename / replace operations, and commits these changes
  • The new Repository is ready to go

I can image more of such initialization workflows that would benefit from this event.

gprossliner avatar Apr 15 '22 10:04 gprossliner

I think this would be a really big deal—it would supercharge GitHub's "template repository" concept, and use GitHub Actions to make it easier for people to "consume" a template repository, lowering the friction to use them.

jlumbroso avatar May 02 '22 02:05 jlumbroso

I used a workflow like this in my use case.

# this file should only be editted from (insert your template repo name here)
name: Cookiecutter format

on:
  # I have found this event triggers on initial creation of new repository from github template
  push:
    branches:
      - '**'

jobs:
  cookiecutter:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      # This is my application specific use case,
      # I am formatting the code here using Cookiecutter
      # In the reader's case, they should modify the code however they want to do it.
      - name: Cookiecutter format
        uses: ./.github/actions/self-initialize-cookiecutter
        with:
          repo_name: ${{ github.event.repository.name }}
      - name: Create Pull Request
        # My repository that is a template repository includes the string "cookiecutter"
        if: ${{ ! contains(github.event.repository.name, 'cookiecutter') }}
        uses: peter-evans/create-pull-request@v3
        with:
          commit-message: "Cookiecutter format with repo_name as ${{ github.event.repository.name }}"
          title: Cookiecutter format
          body: |
            # Cookiecutter format PR
            Cookiecutter format with repo_name as ${{ github.event.repository.name }}
          branch: cookiecutter-format

If you happen to want the action.yaml I'm using for cookiecutter, here it is.

name: "self-initialize-cookiecutter"
description: "Replace the code in this repository by formatting a cookiecutter template"
author: Steven Miller

inputs:
  repo_name:
    description: "What to use in the cookiecutter template for repository name?"
    required: true

runs:
  using: composite
  steps:
  - name: Check repo_name
    shell: bash
    run: |
      REGEX_REPO_NAME='^[a-z][a-z0-9-]{0,38}[a-z0-9]$'
      if [[ ! ${{ inputs.repo_name }} =~ ${REGEX_REPO_NAME} ]]; then
        echo "'repo_name' must match regex ${REGEX_REPO_NAME}"
        exit 1
      fi
  - name: Install tree
    shell: bash
    run: |
      sudo apt-get install -y tree
  - name: Install Cookiecutter and other pip modules
    shell: bash
    run: |
      pip3 install -r requirements.txt
  - name: Format with cookiecutter
    shell: bash
    run: |
      set -xe
      printf '${{ inputs.repo_name }}\n' | cookiecutter .
      ls -ltrah
  - name: Replace content with subdirectory's content
    shell: bash
    run: |
      set -xe
      # Delete everything except the rendered content
      find . -mindepth 1 ! -regex '\.\/${{ inputs.repo_name }}\/.*' ! -regex '^\./\.git\/.*' ! -name .git ! -name ${{ inputs.repo_name }} -delete
      ls -ltrah
  - name: Copy the rendered content to the top level of this repository
    shell: bash
    run: |
      set -xe
      cp -R ./${{ inputs.repo_name }}/* .
      ls -ltrah
  - name: Delete subdirectory
    shell: bash
    run: |
      set -xe
      rm -rf ./${{ inputs.repo_name }}
      ls -ltrah
  - name: Show results
    shell: bash
    run: |
      set -xe
      echo "===================="
      echo "===================="
      echo "===================="
      tree -a .

So in our organization the workflow is like a developer will click "use template" then as a result a formatted cookiecutter PR will open on the new repository they have created.

sjmiller609 avatar May 31 '22 20:05 sjmiller609

@sjmiller609 this looks quite interesting! Thank you

gprossliner avatar May 31 '22 21:05 gprossliner

@sjmiller609 Yes, that's exactly the use case, man, you're AWESOME!!! 🙌🏻 🤪

That's a really terrific trick...

Do you have a public example of this in action?

jlumbroso avatar May 31 '22 22:05 jlumbroso

@sjmiller609 will this github action be triggered on pushes from all branches? Or only once upon repository instantiation.

svenvanderburg avatar Sep 07 '22 13:09 svenvanderburg

@svenvanderburg Look here for an example of what you are trying to do (I think):

https://github.com/jlumbroso/hugo-theme-bootstrap-skeleton

jlumbroso avatar Sep 09 '22 18:09 jlumbroso

@jlumbroso this is the same solution as @sjmiller609 proposed right? By specifying:

on:
  push:
    branches:
      - '**'

I tested this, and it does trigger on initialization. But it also triggers on all following commits... This last behavior is not what I want.

svenvanderburg avatar Sep 13 '22 09:09 svenvanderburg

Here is a workaround. Basically, you disable the workflow after it has run.

A fully working, but untested solution would be:

name: Execute workflow only upon repository initialisation

on:
  push:
    branches:
      - '**'
 
jobs:
    - name: Disable this workflow
      shell: bash
      run: |
        gh workflow disable -R $GITHUB_REPOSITORY "${{ github.workflow }}"
      env:
        GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

svenvanderburg avatar Sep 13 '22 10:09 svenvanderburg

I stumbled upon the following github action that setup everything once the template is cloned https://github.com/laucia/cookiecutter-pypackage/blob/main/.github/workflows/template_baking.yaml

kishaningithub avatar Feb 08 '23 12:02 kishaningithub

This would allow a Template author to automate initialization of a Repository. The workflow should run in the newly create Repository, not in the Template Repository.

The following's my approach to triggering a workflow if a repository is created using my template repository. The workflow runs upon branch/tag creation as well, but it gets canceled because of the conditional expression.

I've already tested it a lot with a scrapped project. Hope it helps!

name: Setup repository

on:
  create

jobs:
  create_issue:
    if: github.event.ref == github.event.master_branch
    name: Create issue

    runs-on: ubuntu-latest

    permissions:
      issues: write

    steps:

      - uses: imjohnbo/issue-bot@v3
        with:
          title: "Test issue"

nizarmah avatar May 29 '23 02:05 nizarmah

The workflow should run in the newly create Repository, not in the Template Repository.

It would actually be great if the event fired in both locations, so if for example the "source" repo wanted to update a README.md w/ a list of repos that use this template (mainly useful for internal template repos in orgs).

ryanschneider avatar Jul 24 '23 22:07 ryanschneider

would be nice to have a template-create event to make things cleaner

Martin-Gonzalez90 avatar Apr 18 '24 14:04 Martin-Gonzalez90