Skip to main content

GitHub Actions is a powerful tool for automating workflows directly within your GitHub repository. One common question is whether you can store multiple actions in a single repository. The answer is yes, and this article will guide you through the process of organizing and using multiple GitHub Actions, whether they are composite, Node.js, or container-driven actions.

# Organizing and Using Multiple GitHub Actions in a Single Repository

GitHub Actions is a powerful tool for automating workflows directly within your GitHub repository. One common question is whether you can store multiple actions in a single repository. The answer is yes, and this article will guide you through the process of organizing and using multiple GitHub Actions, whether they are composite, Node.js, or container-driven actions.

## Organizing Multiple Actions in a Single Repository

You can store multiple actions in a single repository by organizing them into separate directories. While the `.github/actions` directory is a common convention, you can use any directory structure that suits your needs.

### Example Directory Structure

Here's an example directory structure with annotations, including both the conventional `.github/actions` path, and a `custom-actions/` path:

```plaintext
your-repo/
├── .github/                     # GitHub-specific configurations
│   ├── workflows/               # Directory for GitHub workflow files
│   │   ├── main.yml             # Example workflow file

│   ├── actions/                 # Conventional directory for GitHub Actions
│   │   ├── node-action-one/     # Directory for the first Node.js action
│   │   │   ├── action.yml       # Metadata file for the Node.js action
│   │   │   ├── index.js         # Main script for the Node.js action
│   │   │   ├── package.json     # Dependencies for the Node.js action
│   │   ├── container-action-one/# Directory for the first container action
│   │   │   ├── action.yml       # Metadata file for the container action
│   │   │   ├── Dockerfile       # Dockerfile for the container action
│   │   │   ├── entrypoint.sh    # Entrypoint script for the container action

├── custom-actions/              # Custom directory for GitHub Actions
│   ├── node-action-two/         # Directory for the second Node.js action
│   │   ├── action.yml           # Metadata file for the Node.js action
│   │   ├── index.js             # Main script for the Node.js action
│   │   ├── package.json         # Dependencies for the Node.js action
│   ├── container-action-two/    # Directory for the second container action
│   │   ├── action.yml           # Metadata file for the container action
│   │   ├── Dockerfile           # Dockerfile for the container action
│   │   ├── entrypoint.sh        # Entrypoint script for the container action
```

### Node.js Actions

For Node.js actions, each action should have its own directory containing the necessary files such as `action.yml`, `index.js`, and `package.json`.

#### Example `action.yml` for `node-action-one`

```yaml
name: 'Node Action One'
description: 'Description for Node Action One'
runs:
  using: 'node20'
  main: 'index.js'
```

#### Example `index.js` for `node-action-one`

```javascript
const core = require('@actions/core');

try {
  const myInput = core.getInput('myInput');
  console.log(`Hello ${myInput}`);
} catch (error) {
  core.setFailed(error.message);
}
```

#### Example `package.json` for `node-action-one`

```json
{
  "name": "node-action-one",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": {
    "@actions/core": "@latest"
  }
}
```

### Container Actions

For container actions, each action should have its own directory containing the necessary files such as `action.yml`, `Dockerfile`, and any scripts.

#### Example `action.yml` for `container-action-one`

```yaml
name: 'Container Action One'
description: 'Description for Container Action One'
runs:
  using: 'docker'
  image: 'Dockerfile'
```

#### Example `Dockerfile` for `container-action-one`

```Dockerfile
FROM node:20-alpine

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
```

#### Example `entrypoint.sh` for `container-action-one`

```sh
#!/bin/sh -l

echo "Hello $1"
```

## Using Actions in Workflows

Once you have organized your actions, you can reference them in your workflow files.

### Example Workflow File (`main.yml`)

```yaml
name: CI

on: [push]

jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@main

      - name: Run Node Action One
        uses: ./custom-actions/node-action-one
        with:
          myInput: 'World'

      - name: Run Container Action One
        uses: ./custom-actions/container-action-one
        with:
          args: 'World'
```

## Calling Actions from Another Repository

You can also call these actions from another repository by referencing the repository and the specific path to the action.

### Example Workflow in Another Repository

```yaml
name: CI

on: [push]

jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@main

      - name: Run Node Action One from source-repo
        uses: owner/source-repo/custom-actions/node-action-one@main
        with:
          myInput: 'World'

      - name: Run Container Action One from source-repo
        uses: owner/source-repo/custom-actions/container-action-one@main
        with:
          args: 'World'
```

### Explanation

- `owner/source-repo`: Replace `owner` with the GitHub username or organization name and `source-repo` with the name of the repository where the actions are stored.
- `custom-actions/node-action-one@main`: This specifies the path to the action within the source repository and the branch (`main`) to use.
- `with`: This section is used to pass inputs to the actions.

## Conclusion

Organizing and using multiple GitHub Actions in a single repository is straightforward. By following the directory structure and referencing the actions correctly in your workflows, you can efficiently manage and utilize multiple actions. Whether you are using composite, Node.js, or container-driven actions, this approach provides flexibility and organization for your automation needs.