Saltar a contenido

14 - Anatomy of a Small Linux-Adjacent Project

What this session is

About 45 minutes. Walk through the file structure of typical Linux-adjacent OSS projects - dotfiles repos, shell-script tools, infrastructure-as-code repos, doc projects.

These look different from programming-language projects. There's no pom.xml, no Cargo.toml, no package.json. Files are mostly configs and scripts.

Typical dotfiles repo

my-dotfiles/
├── README.md
├── LICENSE
├── install.sh
├── .bashrc
├── .vimrc
├── .gitconfig
├── .config/
│   ├── nvim/
│   │   └── init.vim
│   └── tmux/
│       └── tmux.conf
├── scripts/
│   ├── setup-mac.sh
│   ├── setup-linux.sh
│   └── helpers/
└── .gitignore

Roles: - README.md - what this is, how to use it, what platforms it supports. - install.sh - the entry point. Usually creates symlinks from ~/.bashrc etc. to the files in the repo. - Top-level dotfiles (.bashrc, .vimrc) - the configs themselves. - .config/ - for tools that follow XDG (Linux convention for per-user config under ~/.config/). - scripts/ - helpers for setup / system administration.

How they're "installed":

# Symlink approach (common)
ln -sf ~/code/my-dotfiles/.bashrc ~/.bashrc

When you edit ~/.bashrc, you're actually editing the file in the repo. Commit. Push. Sync to other machines by cloning + running install.sh.

Tools like stow automate the symlinking. Many dotfile repos use chezmoi or yadm for fancier sync.

Typical shell-script tool

For something like tj/git-extras:

git-extras/
├── README.md
├── LICENSE
├── CONTRIBUTING.md
├── Makefile                  (install / uninstall / lint)
├── bin/
│   ├── git-back
│   ├── git-changelog
│   ├── git-effort
│   └── ... (each a shell script)
├── etc/
│   └── git-extras-completion.zsh
├── man/                      (man-page sources)
│   ├── git-back.1.ronn
│   └── ...
├── test/
│   └── tests.bats
└── .github/workflows/

Roles: - bin/ - the actual scripts. Each is an executable file named git-<subcommand>. When installed (usually to /usr/local/bin/), git finds them and runs them as git back, git changelog, etc. - man/ - man-page source (in markdown-like ronn format here; compiled to nroff for man to display). - etc/ - extra files (shell completions, sample configs). - test/tests.bats - bats is a bash testing framework. Yes, you can unit-test bash. - Makefile - install/uninstall targets.

A first PR might be: fix a typo in bin/git-back, add a new option to git-changelog, improve the man page for one of them.

Typical Ansible role

ansible-role-nginx/
├── README.md
├── LICENSE
├── meta/
│   └── main.yml              (role metadata, dependencies)
├── defaults/
│   └── main.yml              (default variable values)
├── vars/
│   └── main.yml              (role-internal variables)
├── tasks/
│   ├── main.yml              (entry point - runs the tasks)
│   └── install.yml
├── handlers/
│   └── main.yml              (notifications, e.g., "restart nginx")
├── templates/
│   ├── nginx.conf.j2         (Jinja2 templates)
│   └── site.conf.j2
├── files/
│   └── ...                   (static files)
├── molecule/                 (testing infrastructure)
│   └── default/
│       └── molecule.yml
└── .github/workflows/

Ansible roles automate configuration of remote systems. Mostly YAML and templates; no compiled code. Very approachable for terminal-fluent beginners.

A first contribution: improve a default value, add a missing variable, fix a template that doesn't work on a specific OS, improve the README.

Typical docs project (e.g., kubernetes/website)

kubernetes-website/
├── README.md
├── LICENSE
├── content/                  (the actual docs)
│   ├── en/
│   │   ├── docs/
│   │   │   ├── concepts/
│   │   │   ├── tasks/
│   │   │   └── tutorials/
│   │   └── ...
│   ├── de/                   (German)
│   ├── es/                   (Spanish)
│   └── ja/                   (Japanese)
├── layouts/                  (templates)
├── static/                   (CSS, JS, images)
├── hugo.toml                 (Hugo static-site config)
└── .github/workflows/

Docs sites typically use a static-site generator (Hugo, MkDocs, Sphinx, Docusaurus). The content is Markdown; the generator turns it into HTML.

Contributing: edit a Markdown file under content/en/docs/.... PR. The CI builds the site to preview your changes.

Typical tldr-pages contribution

The tldr-pages repo is laid out as:

tldr/
├── README.md
├── CONTRIBUTING.md
├── pages/                    (English)
│   ├── common/
│   │   ├── git.md
│   │   ├── ls.md
│   │   └── ...
│   ├── linux/
│   ├── osx/
│   └── windows/
├── pages.fr/                 (French translations)
├── pages.es/                 (Spanish)
├── pages.de/                 (German)
└── ...

Each .md file is one command's tldr page, with example-driven entries. The format is strict but simple. Adding a missing command or example is a 5-minute PR.

CI: what your PR will be measured against

Open .github/workflows/. For these projects, CI typically runs:

  • For dotfiles: shellcheck (lints shell scripts).
  • For shell-script tools: shellcheck + bats tests.
  • For Ansible: ansible-lint + molecule tests.
  • For docs: the static-site builder (Hugo / MkDocs) builds without errors; link checker.

Install shellcheck (sudo apt install shellcheck / brew install shellcheck) and use it locally:

shellcheck install.sh

Catches common bash bugs. Use before submitting.

Exercise

Pick your candidate project from page 13:

  1. Clone it locally.
  2. Walk the file structure. Map each file/folder to a category.
  3. Read CONTRIBUTING.md end to end.
  4. Find the CI workflow YAML. Identify the commands it runs.
  5. Run those commands locally:
  6. For shell projects: shellcheck path/to/scripts/*.sh.
  7. For Ansible: ansible-lint ..
  8. For docs: read the build instructions; build locally with their tool.
  9. Look at the issue you tentatively picked. Identify which file(s) it touches.

You're ready for the actual contribution.

What you might wonder

"How do I know if a project is using Hugo, MkDocs, or something else?" Look at the root. hugo.toml / config.toml = Hugo. mkdocs.yml = MkDocs. docusaurus.config.js = Docusaurus. conf.py in a docs/ dir = Sphinx.

"What's .bats? Is that really a thing?" Yes. bats-core is a TAP-compliant testing framework for bash. Common in shell-tool projects (git-extras, bashly, etc.). Read a .bats file once; the format is intuitive.

"What if I want to contribute code, not docs/scripts?" Pick up a programming language. The "Go from scratch", "Python from scratch", "Java from scratch", "Rust from scratch" paths on this site are sized for that.

Done

  • Recognize the layouts of dotfiles, shell-tool, Ansible, and docs projects.
  • Find and read CI workflows.
  • Run the same checks locally before pushing.

Next: Your first contribution →

Comments