Skip to content

ci ​

pfy ci update writes a CI pipeline and a Dockerfile into your repository from templates embedded in the CLI. It reads project.yaml for the language, registry, and image name, so after pfy init it usually needs no flags. The flags and the jobs each generated pipeline contains are below.

Synopsis ​

bash
pfy ci <subcommand> [flags]

Description ​

The templates are embedded in the CLI binary. Which jobs you get depends on ci.type (github or gitlab) and ci.language (go or node); the two languages produce different pipelines, see Supported Platforms.

The command reads its defaults from project.yaml (created with pfy init), so you can run it without flags. Re-running it overwrites the generated files.

Subcommands ​

  • update - Generate CI/CD pipeline templates

ci update ​

Generate CI/CD pipeline templates for your project.

Usage ​

bash
pfy ci update [--type <platform>] [--language <lang>] [--output <directory>] [flags]

Configuration Priority ​

Values are resolved in this order:

  1. CLI flags (highest priority)
  2. project.yaml file
  3. Auto-detection (e.g., from go.mod)
  4. Defaults (lowest priority)

With project.yaml:

bash
# Run `pfy init` once
pfy init --name my-app

# Then just run
pfy ci update

Without project.yaml:

bash
pfy ci update --type github --language go --project-name my-app --output .github

Flags ​

FlagDefaultDescription
--type(varies)CI/CD platform type (github or gitlab) - resolved as flag > project.yaml > github
--language(detect)Project language (go or node) - auto-detected
--project-name(detect)Project name - auto-detected from directory
--registry(varies)Docker registry URL - resolved as flag > project.yaml > ghcr.io
--image-name(detect)Docker image name - defaults to project name
--output(varies)Output directory path for the CI templates
--with-dependabotfalseGenerate Dependabot/Renovate configuration

Default output paths:

  • GitHub: .github
  • GitLab: . (current directory)

Examples ​

Using project.yaml (recommended):

bash
# Initialize project once
pfy init --name my-service --language go

# Generate templates (reads from project.yaml)
pfy ci update

Generate GitHub Actions workflows (auto-detect language):

bash
pfy ci update
# or explicitly
pfy ci update --type github

Creates:

  • .github/workflows/ci.yml - Main CI pipeline
  • .github/workflows/release.yml - Release workflow
  • Dockerfile - Optimized Dockerfile for your language

Generate with dependency management:

bash
pfy ci update --with-dependabot

Additionally creates:

  • .github/dependabot.yml - Automated dependency updates

Generate for specific language:

bash
pfy ci update --language node --project-name my-api

Generate GitLab CI configuration:

bash
pfy ci update --type gitlab --with-dependabot

Creates:

  • .gitlab-ci.yml - GitLab CI pipeline
  • renovate.json - Renovate Bot configuration (if --with-dependabot)
  • Dockerfile - Optimized Dockerfile for your language

Custom registry and image name:

bash
pfy ci update --registry docker.io --image-name myorg/myapp

Output ​

Created CI workflow: .github/workflows/ci.yml
Created release workflow: .github/workflows/release.yml
Created Dockerfile: Dockerfile

CI/CD templates generated successfully!
Language: go
Project: my-project
Registry: ghcr.io
Image: ghcr.io/my-project

Supported Platforms ​

GitHub Actions ​

Generates workflow files in .github/workflows/ and optional configuration:

ci.yml - Main CI Pipeline (push to main and pull requests):

JobGoNode.jsWhat it does
gitleaksyesyesSecret scanning over the full git history (fetch-depth: 0)
lint-and-testyesyesgolangci-lint + go test -race with coverage, or npm run lint + npm test -- --coverage
deployment-driftyesyesRuns pfy deploy diff --env $PFY_ENV --exit-code --ci. Skipped until you set the PFY_ENV repository variable and the PFY_MANAGER_URL / PFY_MANAGER_TOKEN secrets
build-and-scannoyesDocker build tagged with the project.yaml version, scanned by Trivy (fails on CRITICAL/HIGH)
version-and-pushnoyesOn main only: pfy version bump --part patch, commit project.yaml with [skip ci], push a linux/amd64,linux/arm64 image tagged <version> and latest

Node.js version-and-push does not install pfy

The template's "Install pfy CLI" step sits inside a Go-only block, so the Node.js job calls pfy on a runner that does not have it. Add an install step yourself; see Auto-Versioning.

release.yml - Release Workflow (on v* tags):

  • Go: GoReleaser (goreleaser release --clean) builds and publishes the release, using the repository's .goreleaser.yml if there is one.
  • Node.js: builds and pushes a multi-arch image tagged with the git tag and latest, runs npm run build, and creates a GitHub release with dist/** attached.

GitLab CI/CD ​

Generates .gitlab-ci.yml with these stages:

StageGoNode.jsWhat it does
securityyesyesGitleaks (gitleaks detect --no-git, which scans the checked-out tree, not the history)
testyesyeslint and test jobs with coverage, plus the deployment-drift job (runs only when PFY_ENV is set)
buildnoyesdocker build tagged with the project.yaml version, saved as an artifact
scannoyesTrivy on the built image (fails on HIGH/CRITICAL)
deploynoyesOn main: bump patch version, commit with [skip ci], re-tag and push <version> and latest. On tags: push the tag. The job does not install pfy (only a comment marks where to)

Optional: renovate.json for automated dependency updates (with --with-dependabot)

Template Features ​

Multi-Language Support ​

Templates automatically adapt based on detected or specified language:

Go Projects:

  • golangci-lint for code quality
  • go test with race detection and coverage
  • GoReleaser for multi-platform binary releases
  • A single-stage Alpine Dockerfile that copies a pre-built binary from ${TARGETOS}/${TARGETARCH}/app (the layout GoReleaser produces) and runs it as a non-root user. It does not compile the code itself.

Node.js Projects:

  • npm-based linting and testing
  • Code coverage with standard npm test
  • npm build for production releases
  • Multi-stage Node.js Alpine Dockerfile: npm ci, npm run build, runs dist/index.js as a non-root user on port 3000 with an HTTP health check on /health

Security Features ​

Gitleaks Secret Scanning:

  • Runs on every push and pull request
  • GitHub: scans the whole git history (fetch-depth: 0); GitLab: scans the checked-out files only (--no-git)

Trivy Vulnerability Scanning (Node.js pipelines):

  • Scans the built Docker image
  • Fails the job on CRITICAL or HIGH severity findings

Build Features (Node.js pipelines) ​

  • Multi-platform image push: linux/amd64 and linux/arm64
  • GitHub Actions build cache (type=gha)
  • Automatic patch bump and image push on main

Dependency Management (Optional) ​

Dependabot (GitHub):

  • Weekly automated dependency updates
  • Separate tracking for language packages, Docker, and GitHub Actions
  • Configurable pull request limits
  • Custom commit message prefixes

Renovate (GitLab):

  • Automated dependency updates with automerge rules
  • Minor/patch updates auto-merged
  • Major updates require manual review
  • Security updates prioritized and auto-merged

Workflow Examples ​

Initial CI Setup for GitHub ​

bash
# Navigate to your project
cd my-project

# Generate CI/CD templates
pfy ci update

# Or with dependency management
pfy ci update --with-dependabot

# Review the generated files
ls -la .github/workflows/
cat .github/workflows/ci.yml

# Commit to repository
git add .github/ Dockerfile
git commit -m "Add CI/CD workflows"
git push

Initial CI Setup for GitLab ​

bash
# Navigate to your project
cd my-project

# Generate GitLab CI configuration
pfy ci update --type gitlab --with-dependabot

# Review the generated files
cat .gitlab-ci.yml
cat renovate.json

# Commit to repository
git add .gitlab-ci.yml renovate.json Dockerfile
git commit -m "Add GitLab CI/CD pipeline"
git push

Multi-Registry Setup ​

bash
# For Docker Hub
pfy ci update --registry docker.io --image-name myorg/myapp

# For AWS ECR
pfy ci update --registry 123456789.dkr.ecr.us-east-1.amazonaws.com --image-name myapp

# For custom registry
pfy ci update --registry registry.example.com --image-name company/project

Template Customization ​

The generated files are plain YAML; edit them as you like. Remember that pfy ci update overwrites them.

Common Customizations ​

There is no flag for the Go or Node.js version. The templates always write Go 1.25.5 and Node 20. Edit the generated file:

yaml
# .github/workflows/ci.yml
go-version: "1.25.5"   # Go
node-version: "20"     # Node.js

Add more Docker platforms:

yaml
# In .github/workflows/ci.yml, modify platforms:
platforms: linux/amd64,linux/arm64,linux/arm/v7

Use a different registry:

bash
# Regenerate with custom registry
pfy ci update --registry registry.example.com --image-name myapp

Customize the build context:

yaml
# Modify context path if Dockerfile is in subdirectory:
context: ./services/api

Best Practices ​

Security ​

  • Use the generated Gitleaks configuration to prevent secret leaks
  • Let Trivy fail builds on critical vulnerabilities
  • Store registry credentials as CI/CD secrets, never in code
  • Enable Dependabot/Renovate for automated security updates
  • Review dependency update PRs before merging

Docker Images ​

  • Keep base images minimal (Alpine-based images are generated)
  • Tag images with semantic versions
  • Use registry-specific credentials and access controls
  • Enable Docker layer caching for faster builds

CI/CD Workflows ​

  • Run tests before building Docker images
  • Use separate workflows for CI and releases
  • Only push images from main branch or tags
  • Enable branch protection requiring CI to pass
  • Review generated templates before committing

Dependency Management ​

  • Use --with-dependabot for automated updates
  • Configure automerge for minor/patch updates
  • Manually review major version updates
  • Keep CI/CD workflows and Docker base images updated
  • Monitor security advisories

Updating Existing CI ​

Re-running pfy ci update regenerates the template files, overwriting local changes. Node.js pipelines also bake the current project.yaml version into the build job, so regenerate after a manual pfy version set:

bash
# Update GitLab CI configuration
pfy ci update --type gitlab

# Review changes
git diff .gitlab-ci.yml

# Commit if satisfactory
git add .gitlab-ci.yml
git commit -m "Update CI/CD pipeline template"
git push

See Also ​