├── Dockerfile ├── README.md ├── entrypoint.sh └── license /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12-slim 2 | 3 | LABEL repository="https://github.com/johno/actions-push-subdirectories" 4 | LABEL homepage="https://github.com/johno/actions-push-subdirectories" 5 | LABEL maintainer="John Otander " 6 | 7 | LABEL com.github.actions.name="GitHub Action to Push Subdirectories to Another Repo" 8 | LABEL com.github.actions.description="Automatically push subdirectories in a monorepo to their own repositories" 9 | LABEL com.github.actions.icon="package" 10 | LABEL com.github.actions.color="purple" 11 | 12 | RUN apt-get update && \ 13 | apt-get upgrade -y && \ 14 | apt-get install -y git && \ 15 | apt-get install -y jq 16 | 17 | COPY "entrypoint.sh" "/entrypoint.sh" 18 | ENTRYPOINT ["/entrypoint.sh"] 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Push Subdirectories 2 | 3 | GitHub Action to push subdirectories to separate repositories. 4 | 5 | ### Why? 6 | 7 | When building Gatsby Themes with a monorepo it's common to need to 8 | be able to develop your corresponding starters in the same repo as 9 | well. This allows you to automatically push your starters to their 10 | own repo so they can be used with `gatsby new`. 11 | 12 | ## Usage 13 | 14 | ```yml 15 | name: Publish Starters 16 | on: push 17 | jobs: 18 | master: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@master 22 | - name: publish:starters 23 | uses: johno/actions-push-subdirectories@master 24 | env: 25 | API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }} 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | with: 28 | args: examples johno 29 | ``` 30 | 31 | The `GITHUB_TOKEN` will automatically be defined, the `API_TOKEN_GITHUB` needs to be set in the `Secrets` section of your repository options. You can retrieve the `API_TOKEN_GITHUB` [here](https://github.com/settings/tokens) (set the `repo` permission). 32 | 33 | The action accepts four arguments - the first two are mandatory, the third and fourth are optional. 34 | 35 | 1. Name of the folder that contains your examples. Even if you only have one example currently it also should be placed inside its own folder (e.g. `examples/foo-bar`) as the script will read all folders inside the examples. 36 | 2. GitHub username 37 | 3. Repository name of the respective example. By default the `name` key from the example's `package.json` is used, e.g. the `name` of your example is `gatsby-starter-foobar`, then the script will try to push to `github.com/USERNAME/gatsby-starter-foobar`. 38 | 4. The branch name that the changes should be pushed to. Defaults to `main`. 39 | 40 | ### Custom starter names 41 | 42 | You could define the key `starter-name` in your example's `package.json`, like: 43 | 44 | ```json 45 | { 46 | "starter-name": "gatsby-starter-custom-foobar", 47 | } 48 | ``` 49 | 50 | Use the action with the third argument now: 51 | 52 | ```yml 53 | args: examples johno starter-name 54 | ``` 55 | 56 | Using the action to push to `master` branch: 57 | 58 | ```yml 59 | args: examples johno starter-name master 60 | ``` 61 | 62 | ## Related 63 | 64 | This code is adapted and modified from [Gatsby core](https://github.com/gatsbyjs/gatsby/blob/8933ca9b3bf2c9b4fd580dd437d8695c3be705b7/scripts/clone-and-validate.sh). 65 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | FOLDER=$1 6 | GITHUB_USERNAME=$2 7 | STARTER_NAME="${3:-name}" 8 | BRANCH_NAME="${4:-main}" 9 | BASE=$(pwd) 10 | 11 | git config --global user.email "johno-actions-push-subdirectories@example.org" 12 | git config --global user.name "$GITHUB_USERNAME" 13 | 14 | echo "Cloning folders in $FOLDER and pushing to $GITHUB_USERNAME" 15 | echo "Using $STARTER_NAME as the package.json key" 16 | 17 | # sync to read-only clones 18 | for folder in $FOLDER/*; do 19 | [ -d "$folder" ] || continue # only directories 20 | cd $BASE 21 | 22 | echo "$folder" 23 | 24 | NAME=$(cat $folder/package.json | jq --arg name "$STARTER_NAME" -r '.[$name]') 25 | echo " Name: $NAME" 26 | IS_WORKSPACE=$(cat $folder/package.json | jq -r '.workspaces') 27 | CLONE_DIR="__${NAME}__clone__" 28 | echo " Clone dir: $CLONE_DIR" 29 | 30 | # clone, delete files in the clone, and copy (new) files over 31 | # this handles file deletions, additions, and changes seamlessly 32 | git clone --depth 1 https://$API_TOKEN_GITHUB@github.com/$GITHUB_USERNAME/$NAME.git $CLONE_DIR &> /dev/null 33 | cd $CLONE_DIR 34 | find . | grep -v ".git" | grep -v "^\.*$" | xargs rm -rf # delete all files (to handle deletions in monorepo) 35 | cp -r $BASE/$folder/. . 36 | 37 | # generate a new yarn.lock file based on package-lock.json unless you're in a workspace 38 | if [ "$IS_WORKSPACE" = null ]; then 39 | echo " Regenerating yarn.lock" 40 | rm -rf yarn.lock 41 | yarn 42 | fi 43 | 44 | # Commit if there is anything to 45 | if [ -n "$(git status --porcelain)" ]; then 46 | echo " Committing $NAME to $GITHUB_REPOSITORY" 47 | git add . 48 | git commit --message "Update $NAME from $GITHUB_REPOSITORY" 49 | git push origin $BRANCH_NAME 50 | echo " Completed $NAME" 51 | else 52 | echo " No changes, skipping $NAME" 53 | fi 54 | 55 | cd $BASE 56 | done 57 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 John Otander 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | --------------------------------------------------------------------------------