Problem Statement
How do you create custom GitHub Actions? Explain action types (JavaScript, Docker, Composite), inputs, outputs, and publishing to marketplace.
Explanation
GitHub Actions support three action types: JavaScript actions (run directly on runner), Docker container actions (run in container), and composite actions (combine multiple steps).
JavaScript actions execute directly on runner (fast, no container overhead). Create action:
1. Create action repository with action.yml:
```yaml
name: 'Hello World'
description: 'Greet someone and record time'
inputs:
who-to-greet:
description: 'Who to greet'
required: true
default: 'World'
outputs:
time:
description: 'The time we greeted you'
runs:
using: 'node16'
main: 'index.js'
```
2. Create index.js:
```javascript
const core = require('@actions/core');
const github = require('@actions/github');
try {
const nameToGreet = core.getInput('who-to-greet');
console.log(`Hello ${nameToGreet}!`);
const time = (new Date()).toTimeString();
core.setOutput('time', time);
core.setSecret('mySecret'); // Mask in logs
} catch (error) {
core.setFailed(error.message);
}
```
3. Package dependencies:
```bash
npm install @actions/core @actions/github
npm install @vercel/ncc -g
ncc build index.js -o dist
```
Usage:
```yaml
steps:
- uses: user/hello-world-action@v1
with:
who-to-greet: 'GitHub'
id: hello
- run: echo "Time was ${{ steps.hello.outputs.time }}"
```
Docker container actions run in container with custom environment:
1. Create action.yml:
```yaml
name: 'Container Action'
description: 'Runs in Docker container'
inputs:
myInput:
description: 'Input parameter'
required: true
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.myInput }}
```
2. Create Dockerfile:
```dockerfile
FROM alpine:3.15
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
```
3. Create entrypoint.sh:
```bash
#!/bin/sh -l
echo "Input was $1"
echo "::set-output name=result::Success"
```
Composite actions combine multiple steps (shell commands or other actions):
```yaml
name: 'Composite Action'
description: 'Runs multiple steps'
inputs:
node-version:
description: 'Node.js version'
required: true
runs:
using: 'composite'
steps:
- uses: actions/checkout@v3
shell: bash
- uses: actions/setup-node@v3
with:
node-version: ${{ inputs.node-version }}
shell: bash
- run: npm install
shell: bash
- run: npm test
shell: bash
```
Composite actions simplify workflow by grouping common steps.
Action inputs and outputs enable parameterization:
```yaml
inputs:
api-key:
description: 'API key'
required: true
environment:
description: 'Deployment environment'
required: false
default: 'staging'
outputs:
deployment-url:
description: 'Deployed application URL'
value: ${{ steps.deploy.outputs.url }}
```
Publishing to GitHub Marketplace:
1. Create release with tag (v1, v1.0.0)
2. Add action.yml metadata:
```yaml
name: 'My Action'
author: 'Your Name'
description: 'Detailed description'
branding:
icon: 'activity'
color: 'blue'
```
3. Publish to marketplace through GitHub UI
4. Users reference: uses: username/action-name@v1
Versioning best practices: use semantic versioning, maintain major version tags (v1, v2), update major tag on releases (git tag -fa v1 -m "Update v1"), users can pin to specific version (v1.0.0) or major version (v1).
Testing actions: create .github/workflows/test.yml:
```yaml
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./ # Test local action
with:
who-to-greet: 'Test'
```
Understanding custom actions enables creating reusable automation, sharing with community, and building organization-specific action libraries.