github-action-push-to-anoth.../README.md

18 KiB

github-action-push-to-another-repository

This GitHub Action will help to push files that exist in a GitHub repository, or that are generated by another GitHub action, into a new repository.

For example, on a git push in a source repository, you want certain files to be pushed into a destination repository. A couple of examples of this could be:

  • Specifying a directory in the source to be pushed to destination
  • Generating some files using another GitHub Action (e.g. MarkDown to PDF) and pushing the PDFs across

Please read the documentation to understand which files and commits are kept in the destination repository and target-directory.

source or destination can be private.

Table of contents

General flow

There are two examples:

In the above examples, the file build.sh is executed, which creates a new directory output/ and this directory is copied across to the destination repository

Before using the GitHub Action, either the Personal Access Token or the SSH Keys need to be set up as described below.

⚠️ Please bear in mind that the files in the specified directory of the target repository are deleted unless the option target-directory is used (in this case, only the files for this directory are deleted).

There are different variables to set up the behaviour:

Usage

source-directory (argument)

Directory that the GitHub Action will push files from. Note: it can be . to push all the repository, but read the FAQ!

destination-github-username (argument)

Username/Organization of the GitHub repository that will be used for the destination repository. To output to a repository such as https://github.com/cpina/push-to-another-repository-output this variable would be cpina.

destination-repository-name (argument)

Name of the destination repository. To output to a repository such as https://github.com/cpina/push-to-another-repository-output this variable would be push-to-another-repository-output

⚠️: the GitHub Action currently deletes all the files and directories in the destination repository. The idea is to copy from an output directory into the destination-repository-name, removing all pre-existing files.

user-email (argument)

The email that will be used for the commit to the destination-repository-name. Used for the "Author" of the generated commit.

user-name (argument) [optional]

The name that will be used for the commit to the destination-repository-name. If not specified, the destination-github-username will be used instead.

destination-repository-username (argument) [optional]

The Username/Organization for the destination repository, if different from destination-github-username. For the repository https://github.com/cpina/push-to-another-repository-output this variable would be cpina.

target-branch (argument) [optional]

The branch name for the destination repository. It defaults to main.

commit-message (argument) [optional]

The commit message to be used in the output repository. Optional and defaults to "Update from ORIGIN_COMMIT".

The string ORIGIN_COMMIT is replaced by $ORIGIN_REPOSITORY_URL@commit.

target-directory (argument) [optional]

The directory to wipe and replace in the target repository. Defaults to wiping the entire repository.

Setup

SSH_DEPLOY_KEY Vs. API_TOKEN_GITHUB

The action, entirely executed in your GitHub continuous integration environment, needs to be able to push to the destination repository.

There are two options to do this:

  • Create an SSH deploy key. This key is restricted to the destination repository only
  • Create a GitHub Personal Authentication Token. The token has access to all your repositories

Someone with write access to your repository or this action, could technically add code to leak the key. Thus, it is recommended to use the SSH deploy key method to minimise the impact if this were to happen.

This action supports both methods to keep backwards compatibility, because in the beginning it only supported the GitHub Personal Authentication token.

Setup using SSH deploy key

Recommended, but the setup has a few more steps compared with the Personal Access Token option.

Generate the key files

  • In your computer terminal, generate an ssh key using: ssh-keygen -t ed25519 -C "your_email@example.com" (the type ed25519 is recommended by GitHub documentation).
  • ssh will ask for a file path: Enter file in which to save the key: write a new file name. I suggest the default directory and as a filename: id_github_{name_of_your_destination_repository} to avoid overwriting a previous file. If you will be using this action for multiple repositories, you might want to generate different keys for each one. For the repository https://github.com/cpina/push-to-another-repository-example/, id_github_push-to-another-repository-example could be used.
  • Leave the passphrase empty (otherwise the GitHub Action cannot use it)

Example:

carles@pinux:~$ ssh-keygen -t ed25519 -C carles@pina.cat
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/carles/.ssh/id_ed25519): /home/carles/.ssh/id_ed255^C
carles@pinux:~$ ssh-keygen -t ed25519 -C carles@pina.cat
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/carles/.ssh/id_ed25519): /home/carles/.ssh/id_github_push-to-another-repository
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/carles/.ssh/id_github_push-to-another-repository
Your public key has been saved in /home/carles/.ssh/id_github_push-to-another-repository.pub
The key fingerprint is:
SHA256:qkWM49d0ecTh+d9/CoRIv/N05oYGYvu+wOreQH9PoQ4 carles@pina.cat
The key's randomart image is:
+--[ED25519 256]--+
|            .    |
|           o o   |
|        .   =    |
|     o . o + .   |
|    o + S = + .  |
|   . + *o..= . ..|
|    . =.Eo=.+.o o|
|     + +.= *o=. o|
|    .o+ .o=oo.o.o|
+----[SHA256]-----+
carles@pinux:~$ 

This has generated two files, the public and private ssh keys:

carles@pinux:~$ ls -l /home/carles/.ssh/id_github_push-to-another-repository*
-rw------- 1 carles carles 411 Jul 28 09:40 /home/carles/.ssh/id_github_push-to-another-repository
-rw-r--r-- 1 carles carles  97 Jul 28 09:40 /home/carles/.ssh/id_github_push-to-another-repository.pub
carles@pinux:~$ 

Set up the deployment key

Destination repository

In this section we will add the generated public key to the destination repository. This allows the Action to push there. Text instructions:

  • Go to the GitHub page of the destination repository (e.g. https://github.com/cpina/push-to-another-repository-output)

  • Click on "Settings" (settings for the repository, not the account settings)

    Screenshot-settings

  • On the left-hand side pane click on "Deploy keys"

    Screenshot-deploy-keys

  • Click on "Add deploy key"

    Screenshot-add-deploy-key

  • Title: "GitHub Action push to another repository"

  • Key: paste the contents of the file with the public key. This was generated in the "Generate the key files" step and the name is "id_github_name_of_your_repository.pub"

  • Enable "Allow write access"

    Screenshot-title-key-enable

Origin repository

  • Go to the GitHub page of the origin repository (e.g. https://github.com/cpina/push-to-another-repository-deploy-keys-example)

  • Click on the "Settings" (settings for the repository, not the account settings)

    Screenshot-settings

  • On the left-hand side pane click on "Secrets" and then on "Actions"

    Screenshot-secrets-actions

  • Click on "New repository secret"

    Screenshot-new-repository-secret

  • Name: "SSH_DEPLOY_KEY"

  • Value: paste the contents of the file with the private key. This was generated in the "Generate the key files" step and the name is "id_github_name_of_your_repository"

    Screenshot-ssh-deploy-key-private-key

The GitHub Action will detect the SSH_DEPLOY_KEY secret and use the private key to push to the destination directory.

Please read the Troubleshooting section if you encounter problems, to find how to debug possible problems.

Set up using personal access token

This does not need to be done if you chose to set up the deploy keys using the steps above. This method is here for compatibility with the initial approach of this GitHub Action. The personal access token would have access to all your repositories, so if it were to be leaked, the damage would be greater (it would allow pushes to the same repositories that the Personal Access Token owner has access and other possible associated permissions). On the other hand, the setup is a bit easier because it does not involve creating the deploy key.

Generate your personal token following the steps:

  • Go to the general GitHub Settings (on the right-hand side on the profile picture)

    Screenshot-settings

  • On the left-hand side pane, scroll to the bottom and click on "Developer Settings"

    Screenshot-developer-settings

  • Click on "Personal Access Tokens" (also available at https://github.com/settings/tokens)

    Screenshot-personal-access-token

  • Generate a new token entering a name, expiration date and choose "Repo". Click the bottom button "Generate token". If you choose an expiration date you will need to create a new token after this date. I've chosen in this example "No expiration"; this should be used carefully.

    Screenshot-personal-access-token-comment-expiration-scope

  • Copy the displayed token

    Screenshot-personal-access-token-comment-displayed

Then make the token available to the GitHub Action using the following steps:

  • Go to the GitHub page for the repository that you push from (origin repository). Click on "Settings" for the repository

    Screenshot-secrets-actions

  • Click on "New repository secret"

    Screenshot-new-repository-secret

  • Name: "API_TOKEN_GITHUB"

  • Value: paste the token that you copied earlier

  • Click on "Add secret"

    Screenshot-new-repository-secret

Example usage

      - name: Pushes to another repository
        uses: cpina/github-action-push-to-another-repository@main
        env:
          SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
          API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }}
        with:
          source-directory: 'output'
          destination-github-username: 'cpina'
          destination-repository-name: 'pandoc-test-output'
          user-email: carles3@pina.cat
          target-branch: main

(you only need SSH_DEPLOY_KEY or API_TOKEN_GITHUB depending on the method that you used)

Working example:

https://github.com/cpina/push-to-another-repository-deploy-keys-example/blob/main/.github/workflows/ci.yml

This generates files from: https://github.com/cpina/push-to-another-repository-deploy-keys-example

and pushes them to: https://github.com/cpina/push-to-another-repository-output

Troubleshooting

Cannot push to the destination repository

This is the most common problem. Carefully read the logs on the GitHub Action pages of the source repositories. The action tries to write the errors and gives possible solutions / hints. The first suggestion is to follow the steps above to create the ssh keys or Personal Access Token, and set it up again, but some problems that have occurred in the past are:

  • User was logged in to GitHub with an account that did not have permission to push into the destination repository. The action could not push (permission denied).

  • Token expired at some point

  • ssh generated key pair (public/private) was set in the wrong way.

  • Wrong copy-paste including spaces or other characters that did not belong to the key / token

How to test the Personal Access Token?

Test that the Personal Access Token has the correct permissions to push to the destination repository. This can be useful to check that the Personal Access Token has not expired or has the correct permissions.

In your terminal do:

$ git clone https://YOUR_USERNAME:YOUR_ACCESS_TOKEN@github.com/SOMETHING/REPO
# YOUR_ACCESS_TOKEN probably starts with ghp_
$ cd REPO
$ git checkout -b test
$ git push origin test

For example, if the token did not have permission to write (because repo was not enabled for this token), you might see the following:

$ git push origin test
remote: Permission to cpina/qdacco.git denied to cpina.
fatal: unable to access 'https://github.com/cpina/qdacco/': The requested URL returned error: 403

How to test the ssh keys?

Test connection to GitHub using the key pair

The public key should have been added into the repository (as an SSH deploy key following the documentation above).

Once done, on your computer:

$ ssh -o IdentitiesOnly=yes -i .ssh/id_push-to-another-repository-output_ed25519 git@github.com

Instead of .ssh/id_push-to-another-repository-output_ed25519, use the file as you created it. This is the private key (it does not end with .pub). If you used the correct private key for the correctly uploaded public key, it will print something along the lines of:

Hi cpina! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.

If you see:

git@github.com: Permission denied (publickey).

the public key for this private key is not available on GitHub.

Verify that the key is in the correct repository

$ ssh-keygen -lf .ssh/id_push-to-another-repository-output_ed25519

The output will be something like:

256 SHA256:SOME_STRING_OF_CHARACTERS carles@pina.cat (ED25519)

This should match what you see in the deploy key of the destination repository. If it does not match, the deploy key is not properly set (perhaps different public/private keys were used, for example).

Permission of the key

Visualise the key in the destination repository, and it should say:

Read/Write

FAQ

How can I copy the whole repository?

Use source_directory: .. This will copy all the source GitHub repository to the destination.

⚠️ this will also copy .github/workflows/! The destination repository will try to execute the action. It will probably fail because the Personal Acccess Token / ssh keys will not be available for the destination repository.

A suggestion if you are using source_directory: . is to disable the GitHub Actions in the destination repository. To disable Actions in the destination repository:

How can I copy only some files / only some directories / exclude some files / etc.?

If you need to filter files or directories (exclude files, include only some, etc.) use a step before the action to filter from a temporary directory to the directory that will be pushed. This can be done with "rsync" or any tool that you feel comfortable (could be "rclone" or "find + exec + rm", "find + exec + mv", etc. depending on your needs).

For example see the step: https://github.com/cpina/push-to-another-repository-deploy-keys-example/blob/main/.github/workflows/ci.yml#L21

In the step above it installs rsync (depending on your environment it will already be installed) and it copies everything from "output_temp" to "output" excluding "main.epub". Be careful with the usage of "/" in rsync directories or exclude parameter. Refer to the rsync documentation for other options such as filter using an extension, include only some files / directories, etc.

Error: URL using bad/illegal format or missing URL

It seems that GitHub created a Personal Token with a space character. This would happen if the Personal Token had a # or other characters.

Please check that no space was copied by mistake to the API_TOKEN_GITHUB. If GitHub created a token with # or a space inside, I suggest creating a new one.

The problem, for those that are curious, is that the Personal Access Token is used in the git URLs and the URLs don't support #. The error "URL using bad/illegal format" is coming from the curl library used by git.

Complete information: issue 70

Error: remote: Repository not found.

Bug report where the GitHub Action ended with:

remote: Repository not found.
fatal: repository 'https://github.com/ORGNAME/REPONAME.git/' not found

See the possible solution in the comments of the issue 75