Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/release-drafter-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,39 @@ categories:
- title: '🚀 Features'
labels:
- ':star2: feature'
collapse-after: 5
- title: '🛠️ Bug Fixes'
labels:
- ':adhesive_bandage: bug fix'
collapse-after: 5
- title: '✨ Improvements'
labels:
- ':wrench: enhancement'
collapse-after: 5
- title: '📚 Documentation'
labels:
- ':books: docs'
collapse-after: 5
- title: '🧰 Maintenance'
labels:
- ':hammer_and_wrench: refactor'
collapse-after: 5
- title: '📦 Dependencies'
labels:
- ':dagger: dependencies'
collapse-after: 5
- title: '🧪 Testing'
labels:
- ':test_tube: testing'
collapse-after: 5
- title: '🚧 CI/CD'
labels:
- ':construction_worker: ci'
collapse-after: 5
- title: '⏪ Reverts'
labels:
- ':rewind: revert'
collapse-after: 5
autolabeler:
- label: ':star2: feature'
branch:
Expand All @@ -47,6 +56,7 @@ autolabeler:
- label: ':dagger: dependencies'
branch:
- '/build\/.+/'
- '/dependencies\/.+/'
- label: ':test_tube: testing'
branch:
- '/test\/.+/'
Expand All @@ -58,7 +68,7 @@ autolabeler:
- '/revert\/.+/'
- label: ':books: docs'
files:
- '*.md'
- '**/*.md'
change-template: '- $TITLE by @$AUTHOR in #$NUMBER'
change-title-escapes: '\<*_&'
version-resolver:
Expand Down
24 changes: 24 additions & 0 deletions .github/workflows/auto-approve.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Auto Approve

on:
pull_request_target:
types:
- opened
- synchronize
workflow_dispatch:
inputs:
pullRequestNumber:
description: Pull request number to auto-approve
required: true

jobs:
auto-approve:
runs-on: ubuntu-latest
permissions:
pull-requests: write
if: github.actor == 'renovate[bot]' || github.event_name == 'workflow_dispatch'
steps:
- uses: hmarr/auto-approve-action@v4
with:
review-message: "Auto approved automated PR"
pull-request-number: ${{ github.event.inputs.pullRequestNumber }}
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CI

on:
push:
branches: [main, dev]
branches: [main]
pull_request:
branches: [main, dev]
branches: [main]

env:
DENO_VERSION: "2.x"
Expand Down Expand Up @@ -42,7 +42,7 @@ jobs:
build:
runs-on: ubuntu-latest
needs: check
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev'
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/release-drafter-autolabeler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Release Drafter Autolabeler

on:
pull_request_target:
types: [opened, reopened, synchronize]

permissions:
contents: read

jobs:
autolabel-pr:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter/autolabeler@v7
with:
config-name: release-drafter-config.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 0 additions & 2 deletions .github/workflows/release-drafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ on:
push:
branches:
- main
pull_request:
types: [opened, reopened, synchronize]

permissions:
contents: read
Expand Down
26 changes: 23 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,6 @@ jobs:
working-directory: dist
run: shasum -a 256 stackctl-*.tar.gz > checksums.txt

# NOTE: Homebrew tap auto-update is a follow-up task.
# The release workflow currently does not trigger a Homebrew tap PR.

- name: Create Release
uses: softprops/action-gh-release@v2
with:
Expand All @@ -88,3 +85,26 @@ jobs:
generate_release_notes: false
draft: false
prerelease: false

- name: Generate App token
id: app-token
if: vars.ENABLE_HOMEBREW_DISPATCH == 'true'
uses: actions/create-github-app-token@v3
with:
client-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
owner: AniTrend
repositories: homebrew-tap

- name: Dispatch homebrew-tap formula update
if: vars.ENABLE_HOMEBREW_DISPATCH == 'true'
continue-on-error: true
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
/repos/AniTrend/homebrew-tap/dispatches \
-f event_type='stackctl-release' \
-f client_payload="{\"version\":\"${{ github.ref_name }}\"}"
71 changes: 54 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,37 @@

A Deno-powered CLI for managing local Docker Compose stacks across multi-service repositories, with config-driven profiles, overrides, secrets, and render pipelines.

Status: **Early development** -- all 15 feature issues are planned and tracked on the [issue tracker](https://github.com/AniTrend/stackctl/issues).
Status: **Active development** -- 14 of 15 commands implemented (see table below).

---

## Commands

| Command | Status | Description |
|---|---|---|
| `stackctl init` | Planned | Generate commented `.stackctl` config |
| `stackctl generate` | Planned | Generate `stacks/*.yml` from per-service sources |
| `stackctl render` | Planned | Resolve `${VAR}` placeholders in stack files |
| `stackctl overrides` | Planned | Profile and explicit override merging |
| `stackctl up` | Planned | Deploy stacks to Docker Swarm |
| `stackctl down` | Planned | Tear down stacks |
| `stackctl status` | Planned | Show service status |
| `stackctl logs` | Planned | Follow container logs |
| `stackctl sync` | Planned | Sync images and volumes |
| `stackctl doctor` | Planned | Validate environment |
| `stackctl reload` | Planned | Re-render and reconcile without teardown |
| `stackctl secrets` | Planned | Encrypt/decrypt/deploy/clean/check with SOPS+age |
| `stackctl env` | Planned | Scaffold `.env` files from examples |
| `stackctl plan` | Planned | Dry-run summary of all operations |
| `stackctl completions` | Planned | Generate shell completions (bash/zsh/fish) |
| `stackctl init` | Implemented | Generate commented `.stackctl` config |
| `stackctl generate` | Implemented | Generate `stacks/*.yml` from per-service sources |
| `stackctl render` | Implemented | Resolve `${VAR}` placeholders in stack files |
| `stackctl up` | Implemented | Deploy stacks to Docker Swarm |
| `stackctl down` | Implemented | Tear down stacks |
| `stackctl status` | Implemented | Show service status |
| `stackctl logs` | Implemented | Follow service logs |
| `stackctl sync` | Implemented | Validate generated stacks match committed files (CI drift detection) |
| `stackctl doctor` | Implemented | Check system and project health |
| `stackctl reload` | Implemented | Re-render and reconcile without teardown |
| `stackctl secrets` | Implemented | Encrypt/decrypt/deploy/clean/check with SOPS+age |
| `stackctl env` | Implemented | Scaffold `.env` files from examples |
| `stackctl plan` | Implemented | Dry-run summary of all operations |
| `stackctl completions` | Implemented | Generate shell completions (bash/zsh/fish) |

Override merging is integrated into `generate`, `render`, and `up` via the `--override` flag.

---

## Quick Start

```bash
# Install (once released)
# Install
deno install -f --allow-run --allow-env --allow-read --allow-write \
-n stackctl jsr:@anitrend/stackctl

Expand All @@ -49,6 +50,42 @@ stackctl plan

---

## Features

- Config-driven profiles with layered overrides (`.stackctl`, `.stackctl.<profile>`, `.stackctl.local`)
- SOPS + age encrypted secrets management
- `${VAR}` render pipeline with service-local env resolution
- Docker Swarm deploy with dry-run planning
- CI drift detection via `sync` command
- Shell completions (bash/zsh/fish)

### Secrets Subcommands

| Subcommand | Description |
|---|---|
| `encrypt` | Encrypt `.env` files using SOPS + age |
| `decrypt` | Decrypt `.env.enc` files back to plaintext |
| `deploy` | Decrypt env files and deploy stacks |
| `clean` | Remove decrypted `.env` files securely (shred + rm) |
| `check` | Check secrets tooling availability (sops, age) |

### Env Subcommands

| Subcommand | Description |
|---|---|
| `list` | List `.env` files with status (present/missing/outdated) |
| `create` | Create `.env` from `.env.example` |
| `diff` | Compare `.env` against `.env.example` |
| `materialize` | Copy profile-specific env to `.env` |
| `audit` | Check for plaintext `.env` files with encrypted counterparts |

## GitHub Actions

A composite action for installing stackctl in GitHub Actions is available at
`.github/actions/setup-stackctl/`. See [docs/migration.md](docs/migration.md) for details.

---

## Development

### Prerequisites
Expand Down
17 changes: 17 additions & 0 deletions renovate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"addLabels": [":dagger: dependencies"],
"branchPrefix": "dependencies/",
"reviewers": ["wax911"],
"baseBranches": ["main"],
"automerge": false,
"automergeType": "pr",
"automergeStrategy": "rebase",
"packageRules": [
{
"matchUpdateTypes": ["major"],
"automerge": false
}
]
}
Loading