Skip to content

Commit 12f6f30

Browse files
[!] improve Docker-related GitHub Actions and jobs (#873)
- use official Docker actions (`docker/build-push-action@v5`, `docker/metadata-action@v5`, etc.) - automatic SemVer tagging with `docker/metadata-action` - test builds without registry authentication - add custom Docker Manual Multi-Registry Build action and reuse it - add the proper permissions blocks to workflows - implement shared base stages for faster builds and better caching - use common cache for the whole strategy matrix --------- Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
1 parent 0629352 commit 12f6f30

File tree

8 files changed

+704
-104
lines changed

8 files changed

+704
-104
lines changed

.dockerignore

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,75 @@
1+
# ================================================================
2+
# Docker Build Context Optimization
3+
# Exclude unnecessary files to reduce build context size and improve performance
4+
# ================================================================
5+
6+
# Git and version control
7+
.git
8+
.gitignore
9+
.gitattributes
10+
.gitmodules
11+
12+
# Documentation and markdown files (except essential ones)
13+
*.md
14+
!README.md
15+
docs/
16+
site/
17+
18+
# Development files
19+
.vscode/
20+
.idea/
21+
*.swp
22+
*.swo
23+
*~
24+
25+
# OS generated files
26+
.DS_Store
27+
.DS_Store?
28+
._*
29+
.Spotlight-V100
30+
.Trashes
31+
ehthumbs.db
32+
Thumbs.db
33+
34+
# Logs and temporary files
35+
*.log
36+
*.tmp
37+
*.temp
38+
mem_log.txt
39+
coverage.out
40+
41+
# Node.js (keep essential files, exclude build artifacts)
142
**/node_modules
243
**/build
3-
docs
4-
contrib
44+
internal/webui/.yarn/
45+
internal/webui/yarn-error.log
46+
internal/webui/npm-debug.log*
47+
internal/webui/lerna-debug.log*
48+
49+
# Go build artifacts (exclude from context, but keep source)
50+
pgwatch
51+
cmd/pgwatch/pgwatch
52+
*.exe
53+
54+
# Test files and test data
55+
*_test.go
56+
**/*_test.go
57+
testdata/
58+
59+
# Docker artifacts
60+
docker-compose*.yml
61+
compose*.yml
62+
63+
# CI/CD (GitHub Actions can access these separately)
64+
.github/
65+
66+
# Local development tools
67+
etcdctl.exe
68+
.env
69+
.env.local
70+
.env.*.local
71+
72+
# Other build artifacts
73+
dist/
74+
out/
75+
contrib/
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
# Build Docker Action
2+
3+
A reusable GitHub Action for building and pushing multi-architecture Docker images with advanced features like caching, SemVer tagging, and support for multiple registries.
4+
5+
## Features
6+
7+
-**Multi-platform builds** using Docker Buildx (linux/amd64, linux/arm64)
8+
- 🏷️ **Automatic SemVer tagging** based on Git tags
9+
- 🚀 **Build caching** for faster rebuilds using GitHub Actions cache
10+
- 🐳 **Multiple registry support** (Docker Hub, GHCR, custom registries)
11+
- 🔄 **Conditional pushing** (build-only mode for testing)
12+
- 📋 **Rich metadata** with OpenContainer labels
13+
- 🎯 **Matrix builds** for multiple Dockerfiles
14+
15+
## Usage
16+
17+
### Basic Usage
18+
19+
```yaml
20+
- name: Build and push Docker image
21+
uses: ./.github/actions/build-docker
22+
with:
23+
dockerfile: docker/Dockerfile
24+
image-name: myorg/myapp
25+
registry: docker.io
26+
username: ${{ secrets.DOCKER_USERNAME }}
27+
password: ${{ secrets.DOCKER_PASSWORD }}
28+
push: 'true'
29+
```
30+
31+
### Advanced Usage with Matrix Strategy
32+
33+
```yaml
34+
jobs:
35+
docker:
36+
strategy:
37+
matrix:
38+
image:
39+
- {file: 'docker/Dockerfile', name: 'myorg/myapp'}
40+
- {file: 'docker/demo/Dockerfile', name: 'myorg/myapp-demo'}
41+
steps:
42+
- uses: actions/checkout@v4
43+
44+
- name: Build and push
45+
uses: ./.github/actions/build-docker
46+
with:
47+
dockerfile: ${{ matrix.image.file }}
48+
image-name: ${{ matrix.image.name }}
49+
registry: docker.io
50+
username: ${{ secrets.DOCKER_USERNAME }}
51+
password: ${{ secrets.DOCKER_PASSWORD }}
52+
push: ${{ github.ref_type == 'tag' }}
53+
build-args: |
54+
VERSION=${{ github.ref_name }}
55+
BUILD_DATE=${{ steps.date.outputs.date }}
56+
```
57+
58+
## Inputs
59+
60+
| Input | Description | Required | Default |
61+
|-------|-------------|----------|---------|
62+
| `dockerfile` | Path to Dockerfile (relative to repo root) | ✅ | - |
63+
| `image-name` | Docker image name (without registry prefix) | ✅ | - |
64+
| `registry` | Docker registry (docker.io, ghcr.io, etc.) | ❌ | `docker.io` |
65+
| `username` | Docker registry username | ✅ | - |
66+
| `password` | Docker registry password/token | ✅ | - |
67+
| `platforms` | Target platforms for multi-arch build | ❌ | `linux/amd64,linux/arm64` |
68+
| `push` | Whether to push the image (true/false) | ❌ | `false` |
69+
| `build-args` | Build arguments (KEY=VALUE, one per line) | ❌ | - |
70+
| `cache-scope` | Cache scope for build cache | ❌ | `default` |
71+
72+
## Outputs
73+
74+
| Output | Description |
75+
|--------|-------------|
76+
| `image-id` | Image ID of the built image |
77+
| `digest` | Image digest of the built image |
78+
| `metadata` | Build result metadata |
79+
80+
## Tag Strategy
81+
82+
The action automatically applies tags based on the trigger:
83+
84+
### For Git Tags (Releases)
85+
86+
- `1.2.3` - Exact version
87+
- `1.2` - Minor version
88+
- `1` - Major version
89+
- `latest` - Latest stable release (excludes pre-releases)
90+
91+
**Note**: Pre-release versions (e.g., `1.2.3-beta.1`, `2.0.0-rc.1`) will only get the exact version tag, not `latest` or major/minor tags.
92+
93+
### For Branch Pushes
94+
95+
- `main` or `master` → branch name (no `latest` tag)
96+
- Other branches → branch name as tag
97+
98+
### For Pull Requests
99+
100+
- `pr-123` - PR number
101+
102+
### Always Applied
103+
104+
- `sha-abc1234` - Short commit SHA
105+
106+
## Registry Examples
107+
108+
### Docker Hub
109+
110+
```yaml
111+
with:
112+
registry: docker.io
113+
username: ${{ secrets.DOCKER_USERNAME }}
114+
password: ${{ secrets.DOCKER_PASSWORD }}
115+
```
116+
117+
### GitHub Container Registry (GHCR)
118+
119+
```yaml
120+
with:
121+
registry: ghcr.io
122+
image-name: myorg/myapp # Same name as Docker Hub
123+
username: ${{ github.actor }}
124+
password: ${{ secrets.GITHUB_TOKEN }}
125+
```
126+
127+
**Note**: Use consistent image names across registries for better user experience.
128+
129+
### Custom Registry
130+
131+
```yaml
132+
with:
133+
registry: my-registry.com
134+
username: ${{ secrets.CUSTOM_REGISTRY_USER }}
135+
password: ${{ secrets.CUSTOM_REGISTRY_TOKEN }}
136+
```
137+
138+
## Build-Only Mode
139+
140+
To test builds without pushing (useful in PR workflows):
141+
142+
```yaml
143+
- name: Test Docker build
144+
uses: ./.github/actions/build-docker
145+
with:
146+
dockerfile: docker/Dockerfile
147+
image-name: myorg/myapp
148+
registry: docker.io
149+
username: dummy # Not used when push=false
150+
password: dummy # Not used when push=false
151+
push: 'false'
152+
```
153+
154+
## Build Arguments
155+
156+
Pass build arguments to Docker:
157+
158+
```yaml
159+
with:
160+
build-args: |
161+
VERSION=${{ github.ref_name }}
162+
GIT_HASH=${{ github.sha }}
163+
BUILD_DATE=${{ steps.date.outputs.date }}
164+
ENVIRONMENT=production
165+
```
166+
167+
## Caching
168+
169+
The action uses GitHub Actions cache for Docker layer caching. Use different `cache-scope` values for different build contexts:
170+
171+
```yaml
172+
with:
173+
cache-scope: main-app # For main application
174+
# vs
175+
cache-scope: demo-app # For demo application
176+
```
177+
178+
## Security Notes
179+
180+
- Registry credentials are only used when `push: 'true'`
181+
- Build-only mode doesn't require valid credentials
182+
- Use repository secrets for sensitive data
183+
- GHCR automatically uses `GITHUB_TOKEN` which has appropriate permissions
184+
185+
## Conditional Pushing
186+
187+
Common patterns for when to push images:
188+
189+
```yaml
190+
# Push only on tags (releases)
191+
push: ${{ github.ref_type == 'tag' }}
192+
193+
# Push on tags or main branch
194+
push: ${{ github.ref_type == 'tag' || github.ref_name == 'main' }}
195+
196+
# Push only on releases (not pre-releases)
197+
push: ${{ github.ref_type == 'tag' && !contains(github.ref_name, 'beta') }}
198+
```
199+
200+
## Workflow Integration
201+
202+
### Avoiding Conflicts
203+
204+
When using this action in multiple workflows, be careful about triggers to avoid conflicts:
205+
206+
```yaml
207+
# ✅ Good: Release workflow (official releases)
208+
on:
209+
release:
210+
types: [created]
211+
# Uses: push: 'true' for Docker Hub
212+
213+
# ✅ Good: Build workflow (testing)
214+
on:
215+
pull_request:
216+
# Uses: push: 'false' (build-only)
217+
218+
# ❌ Bad: Both workflows triggering on same tag
219+
# Don't use both of these:
220+
on: { push: { tags: ['v*'] } } # Workflow 1
221+
on: { release: { types: [created] } } # Workflow 2 (GitHub creates tag automatically)
222+
```
223+
224+
### Recommended Setup
225+
226+
- **Release Workflow**: Handle official releases to Docker Hub
227+
- **Build Workflow**: Test builds on PRs (no push)
228+
- **Multi-Registry Workflow**: Manual builds for alternative registries

0 commit comments

Comments
 (0)