diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..ebc242b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @Monynha-Softwares diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 94ce7d4..aa979ad 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,3 @@ -default_install_hook_types: [pre-commit, pre-push] -default_stages: [commit, push] repos: - repo: local hooks: @@ -13,14 +11,8 @@ repos: entry: shellcheck -x language: system files: \.sh$ - - id: editorconfig-checker - name: editorconfig-checker - entry: ec - language: system - pass_filenames: false - id: bats name: bats entry: make test language: system pass_filenames: false - stages: [push] diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..78797d7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,4 @@ +# Code of Conduct + +This project follows the [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct/). All contributors are expected to uphold these standards. + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..7f8096f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Contributing + +Thank you for helping improve MonaRepo. + +- Run `make install-dev` once to set up tools. +- Use `make fmt` and `make lint` before committing. +- Validate with `make test`. + +See [docs/contributing.md](docs/contributing.md) for full guidelines. diff --git a/Makefile b/Makefile index f8c4ea8..b6833b8 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,12 @@ SHELL := /bin/bash -.PHONY: install-dev fmt lint test ci +.PHONY: install-dev fmt lint test install-dev: sudo apt-get update -y sudo apt-get install -y shellcheck shfmt bats curl - pip install --upgrade pre-commit editorconfig-checker + pip install --upgrade pre-commit pre-commit install --install-hooks - pre-commit install --hook-type pre-push --install-hooks fmt: shfmt -w bin modules recipes tests @@ -18,5 +17,3 @@ lint: test: bats -r tests - -ci: lint test diff --git a/README.md b/README.md index 09bb365..68632b9 100644 --- a/README.md +++ b/README.md @@ -1,100 +1,59 @@ -# MonaRepo — Monynha Softwares +# MonaRepo TUI -**Version:** v0.1.0 +[![CI](https://github.com/Monynha-Softwares/MonaRepoTui/actions/workflows/lint_test.yml/badge.svg)](https://github.com/Monynha-Softwares/MonaRepoTui/actions/workflows/lint_test.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) -A base monorepo (Bash-first) to automate VM/server bootstrap with an optional TUI powered by [`bashsimplecurses`](https://github.com/metal3d/bashsimplecurses). -Use this as the starting point for Codex/agents to extend modules and recipes. +TL;DR: Bash-based toolkit with optional TUI to bootstrap servers the Monynha Way. ## Features -- Single entrypoint: `bin/mona` — interactive TUI (↑/↓, Enter, Q) with a heart header ❤ -- Flows: Quick Start, Distro Upgrade, Network (Netplan), Users & SSH, Hostname/hosts, Run Recipe -- Dry-run mode (`--dry-run`) to preview actions -- CI ready (ShellCheck + BATS), Makefile targets -- Cloud-init template for first-boot provisioning - -## Getting Started +- Single entrypoint `bin/mona` +- Dry-run support +- Modules & recipes for common tasks +## Install ```bash -# clone -git clone monarepo && cd monarepo - -# install development dependencies and git hooks +git clone https://github.com/Monynha-Softwares/MonaRepoTui.git +cd MonaRepoTui make install-dev - -# run full test suite -make test - -# run TUI (recommended with sudo/root) -sudo ./bin/mona ``` -### Local hooks - -This repository uses [pre-commit](https://pre-commit.com/) hooks. Formatting -(`shfmt`) and linting (`shellcheck`, `editorconfig-checker`) run on every -commit. The BATS tests run automatically on `git push`. Hooks are installed by -`make install-dev`. You can manually trigger them for all files with: - +## Quickstart ```bash -pre-commit run --all-files +bin/mona --help ``` -### Run CI tasks locally +## Usage +```bash +$ bin/mona --help +MonaRepo v0.4.0 -The same checks used in GitHub Actions can be executed locally: +Usage: mona [--dry-run] [--help] [--version] -```bash -make lint -make test +Flags: + --dry-run Show actions without applying + --help Print help and exit + --version Print version and exit +Env: + MONA_NONINTERACTIVE=1 Single-shot non-interactive mode for CI ``` -### Non-interactive/CI flags -- `--version` : prints version and exits -- `--help` : prints help and exits -- `--dry-run` : prints actions instead of applying -- `MONA_NONINTERACTIVE=1` : single-shot non-interactive mode (no curses, no actions) +## Development +- `make fmt` +- `make lint` +- `make test` -### Directory Layout - -``` -bin/ # entrypoints -lib/ # shared helpers (future work for agents) -modules/ # idempotent modules (base, docker, ...) -recipes/ # orchestration of modules per "role" -templates/ # cloud-init and systemd -tests/ # bats tests -ui/ # optional bashsimplecurses submodule (or runtime fetch) -.github/workflows/ci.yml +## Testing +Run the full suite: +```bash +make test ``` -## Cloud-init quick start -Use `templates/cloud-init/user-data.yaml` as user-data for new VMs. It clones your repo into `/opt/monarepo` and runs a recipe. - ## Contributing -- Lint Shell: `make lint` (ShellCheck) -- Tests: `make test` (BATS) -- Keep modules idempotent: **probe → apply → verify** -- Prefer `apply` helper (respects `--dry-run`). +See [CONTRIBUTING.md](CONTRIBUTING.md). -## License -MIT — see [LICENSE](LICENSE). - - -## Included Recipes (examples) -- `recipes/coolify-node.sh` — base + docker + coolify bootstrap (network/dirs) -- `recipes/monitoring-node.sh` — base + docker + node_exporter + cAdvisor -- `recipes/supabase-node.sh` — base + docker (hook para Supabase) +## Security +See [SECURITY.md](SECURITY.md). -## Project Installer (Wizard) -Use the TUI option **“Instalar/Configurar Projeto (GitHub/Docker)”** to: -- List or select a GitHub repo (Monynha-Softwares by default) and clone it -- Or pull/run a Docker image quickly -- Then MonaRepo detects common post‑clone actions (e.g., copy `.env.example`, `docker compose up -d`, `npm/pnpm/yarn install`, `make setup`, `supabase start`) and lets you run them step‑by‑step while logging output. - -Logs are stored in `~/.mona/logs` (or `$MONA_LOG_DIR`). `--dry-run` prints commands without executing. +## License +MIT © Monynha Softwares -### Installer extras (v0.4.0) -- **GitHub PAT**: set `GITHUB_TOKEN` to avoid rate limits and access private repos. -- **Interactive `.env`**: when a project has `.env.example`, choose “Criar .env interativo” to fill values key-by-key. -- **Docker Compose advanced**: auto-detects `docker compose` (plugin) or `docker-compose`; offers `pull`, `up -d --remove-orphans`, `ps`, `logs -f`. -- **TUI README viewer** (experimental): set `MONA_USE_TUI_READER=1` to view README inside the TUI; otherwise falls back to `less`. +> The Monynha Way: inclusive, accessible, DX-first. diff --git a/README.pt-BR.md b/README.pt-BR.md new file mode 100644 index 0000000..8677fd8 --- /dev/null +++ b/README.pt-BR.md @@ -0,0 +1,59 @@ +# MonaRepo TUI + +[![CI](https://github.com/Monynha-Softwares/MonaRepoTui/actions/workflows/lint_test.yml/badge.svg)](https://github.com/Monynha-Softwares/MonaRepoTui/actions/workflows/lint_test.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) + +TL;DR: toolkit em Bash com TUI opcional para iniciar servidores no estilo Monynha. + +## Funcionalidades +- Ponto de entrada único `bin/mona` +- Suporte a dry-run +- Módulos e receitas para tarefas comuns + +## Instalação +```bash +git clone https://github.com/Monynha-Softwares/MonaRepoTui.git +cd MonaRepoTui +make install-dev +``` + +## Início Rápido +```bash +bin/mona --help +``` + +## Uso +```bash +$ bin/mona --help +MonaRepo v0.4.0 + +Uso: mona [--dry-run] [--help] [--version] + +Flags: + --dry-run Mostra ações sem aplicar + --help Exibe ajuda e sai + --version Exibe versão e sai +Env: + MONA_NONINTERACTIVE=1 Modo não interativo (CI) +``` + +## Desenvolvimento +- `make fmt` +- `make lint` +- `make test` + +## Testes +Execute toda a suíte: +```bash +make test +``` + +## Contribuindo +Veja [CONTRIBUTING.md](CONTRIBUTING.md). + +## Segurança +Veja [SECURITY.md](SECURITY.md). + +## Licença +MIT © Monynha Softwares + +> O Jeito Monynha: inclusivo, acessível e focado em DX. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..a3c68d2 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,7 @@ +# Security Policy + +If you discover a security issue, please report it responsibly. + +- Email: security@monynha-softwares.example +- Do not disclose publicly until we provide a fix. + diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..1d0ba9e --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.4.0 diff --git a/bin/mona b/bin/mona index 7b6312a..9391fa8 100755 --- a/bin/mona +++ b/bin/mona @@ -1,6 +1,7 @@ #!/usr/bin/env bash # MonaRepo — Interactive TUI bootstrapper -set -euo pipefail +set -Eeuo pipefail +IFS=$'\n\t' # Determine repo root early so other scripts can source helpers safely export MONA_BIN_PATH="$(readlink -f "$0")" @@ -9,14 +10,14 @@ export MONA_DIR="$(cd "$(dirname "$MONA_BIN_PATH")/.." && pwd)" # shellcheck source=../lib/common.sh . "$MONA_DIR/lib/common.sh" -VERSION="0.4.0" +VERSION="$(cat "$MONA_DIR/VERSION")" # ------------------------------ Globals ------------------------------------ export MONA_DRY_RUN="${MONA_DRY_RUN:-false}" export MONA_NONINTERACTIVE="${MONA_NONINTERACTIVE:-0}" # Arg parsing -show_help() { +usage() { cat <&2 + exit 1 + ;; + esac + ;; + \?) + log_error "Unknown option -$OPTARG" + usage >&2 + exit 1 + ;; esac done +shift $((OPTIND - 1)) MONA_TMP_DIR="${TMPDIR:-/tmp}/mona" mkdir -p "$MONA_TMP_DIR" diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..2a6b4f6 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,7 @@ +# Architecture + +``` +bin/ # entrypoints +modules/ # bash modules +tests/ # bats tests +``` diff --git a/docs/cli-usage.md b/docs/cli-usage.md new file mode 100644 index 0000000..f179c0b --- /dev/null +++ b/docs/cli-usage.md @@ -0,0 +1,9 @@ +# CLI Usage + +Common commands: + +```bash +bin/mona --help +bin/mona --version +bin/mona --dry-run +``` diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..f36d982 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,8 @@ +# Contributing Guide + +1. Run `make install-dev` to set up tools. +2. Use `make fmt` to format scripts. +3. Run `make lint` and `make test` before pushing. +4. Follow Conventional Commits. + +See [../CONTRIBUTING.md](../CONTRIBUTING.md) for summary. diff --git a/lib/common.sh b/lib/common.sh index 48a3a84..f21c72b 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -1,14 +1,22 @@ #!/usr/bin/env bash # Common helpers for MonaRepo -set -euo pipefail +set -Eeuo pipefail +IFS=$'\n\t' -log() { printf "[mona] %s\n" "$*"; } -warn() { printf "[mona:warn] %s\n" "$*"; } >&2 -err() { printf "[mona:err] %s\n" "$*"; } >&2 -needs_root(){ [[ $EUID -eq 0 ]] || { err "Execute como root (sudo)."; exit 1; }; } -color(){ local c="$1"; shift; printf "\e[%sm%s\e[0m" "$c" "$*"; } +# shellcheck source=lib/log.sh +. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/log.sh" -pm_detect(){ +needs_root() { + [[ $EUID -eq 0 ]] || { log_error "Execute como root (sudo)."; exit 1; } +} + +color() { + local c="$1" + shift + printf '\e[%sm%s\e[0m' "$c" "$*" +} + +pm_detect() { if command -v apt-get >/dev/null 2>&1; then echo apt; return; fi if command -v dnf >/dev/null 2>&1; then echo dnf; return; fi if command -v yum >/dev/null 2>&1; then echo yum; return; fi @@ -17,27 +25,27 @@ pm_detect(){ echo unknown } -pkg_install(){ +pkg_install() { local pkgs=("$@") pm pm=$(pm_detect) - log "Instalando pacotes via $pm: ${pkgs[*]}" + log_info "Instalando pacotes via $pm: ${pkgs[*]}" [[ "${MONA_DRY_RUN:-false}" == "true" ]] && return 0 case "$pm" in - apt) apt-get update -y && DEBIAN_FRONTEND=noninteractive apt-get install -y "${pkgs[@]}";; - dnf) dnf install -y "${pkgs[@]}";; - yum) yum install -y "${pkgs[@]}";; - pacman) pacman -Sy --noconfirm "${pkgs[@]}";; - zypper) zypper --non-interactive install --no-recommends "${pkgs[@]}";; - *) err "Gerenciador de pacotes não suportado"; return 1;; + apt) apt-get update -y && DEBIAN_FRONTEND=noninteractive apt-get install -y "${pkgs[@]}" ;; + dnf) dnf install -y "${pkgs[@]}" ;; + yum) yum install -y "${pkgs[@]}" ;; + pacman) pacman -Sy --noconfirm "${pkgs[@]}" ;; + zypper) zypper --non-interactive install --no-recommends "${pkgs[@]}" ;; + *) log_error "Gerenciador de pacotes não suportado"; return 1 ;; esac } -apply(){ - if [[ "${MONA_DRY_RUN:-false}" == "true" ]]; then - log "(dry-run) $*" - else +apply() { + if [[ "${MONA_DRY_RUN:-false}" == "true" ]]; then + log_info "(dry-run) $*" + else eval "$*" - fi + fi } -pause_any(){ read -r -p $'Pressione Enter para voltar ao menu…\n' _ || true; } +pause_any() { read -r -p $'Pressione Enter para voltar ao menu…\n' _ || true; } diff --git a/lib/log.sh b/lib/log.sh new file mode 100755 index 0000000..1ceb9cc --- /dev/null +++ b/lib/log.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -Eeuo pipefail +IFS=$'\n\t' + +_color() { + local code="$1" msg="$2" + if [[ -n "${NO_COLOR:-}" || "${MONA_NONINTERACTIVE:-0}" == "1" ]]; then + printf '%s' "$msg" + return + fi + printf '\e[%sm%s\e[0m' "$code" "$msg" +} + +_log() { + local level="$1" color_code="$2"; shift 2 + local prefix="[mona:${level}]" + local text="$*" + local colored_prefix + colored_prefix=$(_color "$color_code" "$prefix") + printf '%s %s\n' "$colored_prefix" "$text" +} + +log_info() { _log info 34 "$*"; } +log_warn() { _log warn 33 "$*" >&2; } +log_error() { _log error 31 "$*" >&2; } +log_success() { _log success 32 "$*"; } + +# Backwards compatibility +log() { log_info "$@"; } +warn() { log_warn "$@"; } +err() { log_error "$@"; } diff --git a/modules/coolify/bootstrap.sh b/modules/coolify/bootstrap.sh index f73dd4f..d7f1202 100755 --- a/modules/coolify/bootstrap.sh +++ b/modules/coolify/bootstrap.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -set -euo pipefail +set -Eeuo pipefail +IFS=$'\n\t' # shellcheck source=../../lib/common.sh . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/lib/common.sh" diff --git a/modules/installer/wizard.sh b/modules/installer/wizard.sh index b649ad7..6efaf35 100755 --- a/modules/installer/wizard.sh +++ b/modules/installer/wizard.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -set -euo pipefail +set -Eeuo pipefail +IFS=$'\n\t' # shellcheck source=../../lib/common.sh . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/lib/common.sh" # shellcheck source=github.sh diff --git a/modules/network/nmcli.sh b/modules/network/nmcli.sh index cab87d1..7a37db5 100755 --- a/modules/network/nmcli.sh +++ b/modules/network/nmcli.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -set -euo pipefail +set -Eeuo pipefail +IFS=$'\n\t' # shellcheck source=../../lib/common.sh . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/lib/common.sh" diff --git a/modules/observability/node_exporter.sh b/modules/observability/node_exporter.sh index 0e14e1e..df0fc58 100755 --- a/modules/observability/node_exporter.sh +++ b/modules/observability/node_exporter.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -set -euo pipefail +set -Eeuo pipefail +IFS=$'\n\t' # shellcheck source=../../lib/common.sh . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/lib/common.sh"