From 3f649546eedf4cc7a20baf269a987661efea298a Mon Sep 17 00:00:00 2001 From: mindsers Date: Thu, 8 Oct 2026 23:29:10 +0200 Subject: [PATCH] docs: add guides for new machines, scripts and CI - Set up a new machine: install, access to a private repository, init, deploy with a dry run first, the setup script, local files per project, a bootstrap script that needs no answers, and keeping the machine in sync. - Use configfile in scripts and CI: the option that replaces each question without a terminal, exit codes, output, and a GitHub Actions workflow that checks a dotfiles repository on every push by deploying it into a throwaway home folder with --dry-run. The commands, messages and exit codes shown were run for real without a terminal, including a dry run on a repository with invalid modules and an init from a checkout in detached HEAD, as in CI. The example workflow passes actionlint. --- docs/src/content/docs/guides/new-machine.md | 94 +++++++++++++++++++ .../src/content/docs/guides/scripts-and-ci.md | 94 +++++++++++++++++++ .../content/docs/guides/upgrading-from-0-3.md | 2 + docs/src/content/docs/index.md | 2 +- 4 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 docs/src/content/docs/guides/new-machine.md create mode 100644 docs/src/content/docs/guides/scripts-and-ci.md diff --git a/docs/src/content/docs/guides/new-machine.md b/docs/src/content/docs/guides/new-machine.md new file mode 100644 index 0000000..089259a --- /dev/null +++ b/docs/src/content/docs/guides/new-machine.md @@ -0,0 +1,94 @@ +--- +title: Set up a new machine +description: Bring your configuration to a new computer, by hand or with a bootstrap script. +sidebar: + order: 1 +--- + +This guide takes a machine from nothing to your configuration, using a dotfiles repository you already have. If you don't have one yet, start with [Your first dotfiles repository](/getting-started/tutorial/). + +## 1. Install configfile + +On macOS, install [Homebrew](https://brew.sh) first if it isn't there yet, then: + +```sh +brew install mindsers/tap/configfile +``` + +Homebrew also installs Node.js and git. [Installation](/getting-started/installation/) lists the other ways. + +## 2. Give the machine access to your repository + +For a private repository, the machine needs your git credentials before *configfile* can clone it: add an SSH key to your git host, or sign in with its command line tool (`gh auth login` for GitHub). A public repository can be cloned with its `https://` URL without credentials. + +Avoid putting a token in the repository URL: *configfile* saves the URL in `~/.configfilerc`, and warns when it contains credentials. + +## 3. Connect configfile to the repository + +```sh +configfile init +``` + +*configfile* asks for the repository's URL and clones it into `~/.configfile/dotfiles`. + +## 4. Deploy your modules + +See what would be deployed, and what is in the way: + +```sh +configfile modules status +configfile modules deploy --all --dry-run +``` + +Then deploy every module: + +```sh +configfile modules deploy --all +``` + +Files that already exist where yours go, such as the default `~/.zshrc` of a new machine, are moved aside to `.old`, so you can compare them or bring them back with `configfile modules undeploy`. + +## 5. Run your setup script + +If your repository has a setup script, for example to install your tools, run it: + +```sh +configfile scripts run setup +``` + +With a version per system (`setup.macos.sh`, `setup.linux.sh`), *configfile* picks the one for this machine. See [Scripts](/reference/scripts/). + +## 6. Copy local files into your projects + +Local files, such as an `.editorconfig`, are copied into the current folder rather than linked. In each project that needs them: + +```sh +cd ~/projects/my-project +configfile modules deploy --all --local +``` + +## Do it all with one script + +To set up machines regularly, put the steps in a script. Without a terminal to ask questions in, *configfile* needs everything as options: `--repo` for `init`, and module names or `--all` for `modules deploy`. [Use configfile in scripts and CI](/guides/scripts-and-ci/) lists them. + +```sh title="bootstrap.sh" +#!/bin/sh +set -e + +brew install mindsers/tap/configfile +configfile init --repo git@github.com:me/dotfiles.git +configfile modules deploy --all +configfile scripts run setup +``` + +`set -e` stops the script at the first step that fails: *configfile* exits with a non-zero code when a command fails. On a machine that already has a configuration, `init` refuses to replace it without `--force`. + +## Keep the machine in sync + +When you push changes to your repository, bring them to the machine with: + +```sh +configfile update +``` + +Linked files are up to date right away. Run `configfile modules deploy --all` again when you add files or modules, as `update` reminds you, and `configfile modules undeploy --removed` to remove what the repository no longer deploys, which `update` warns about. diff --git a/docs/src/content/docs/guides/scripts-and-ci.md b/docs/src/content/docs/guides/scripts-and-ci.md new file mode 100644 index 0000000..5aee4dc --- /dev/null +++ b/docs/src/content/docs/guides/scripts-and-ci.md @@ -0,0 +1,94 @@ +--- +title: Use configfile in scripts and CI +description: Run configfile without a terminal, rely on its exit codes, and check a dotfiles repository on every push. +sidebar: + order: 2 +--- + +Every *configfile* command can run without anyone at the keyboard: in a bootstrap script, a cron job, or a CI workflow. This guide covers what changes without a terminal, and how to check your dotfiles repository automatically. + +## Answering questions with options + +When it runs in a terminal, *configfile* asks for what it needs. When its input is not a terminal, it can't ask: a command that would need an answer stops with an error that names the option to pass instead. + +```txt +$ configfile modules deploy < /dev/null + Error No module given. Pass module names, or --all to deploy every module. +``` + +| Command | Question in a terminal | Option to pass instead | +| --- | --- | --- | +| `configfile init` | the repository's URL | `--repo ` | +| `configfile init` | whether to replace an existing configuration | `--force` | +| `configfile modules deploy` and `undeploy` | whether to use every module | module names, or `--all` | +| `configfile modules deploy --local` | whether to replace an existing file that differs | `--force` (without it, the file is skipped and the command fails) | + +`configfile init --folder ` also lets a script choose where the repository is cloned. The [commands reference](/reference/commands/) lists every option. + +## Exit codes + +*configfile* exits with: + +- `0` when the command succeeded; +- another code when it failed, with an error message saying why: usually `1`, or git's own code when a git command fails (for example `128` when the repository can't be fetched); +- the script's own exit code with `configfile scripts run`, so a failing setup script fails the step that runs it; +- `130` when you press Ctrl+C at a question. + +In a shell script, `set -e` therefore stops at the first *configfile* command that fails. + +## Output + +With `configfile scripts run`, *configfile*'s own messages go to stderr and the script's output to stdout, unchanged: you can pipe or redirect the script's output as if you had run it directly. + +`configfile history --json` prints the [history](/reference/history/) as JSON Lines, one run per line, for scripts that need to know what *configfile* did. + +## Check your dotfiles repository on every push + +A mistake in a `settings.json`, such as invalid JSON, a missing `target_path`, or a target *configfile* refuses, is usually found on the next machine you set up. A CI workflow can find it when you push, by deploying the repository into a throwaway home folder with `--dry-run`: *configfile* reads every module and entry, checks every target, and exits with `1` if anything can't be deployed. + +With GitHub Actions, add this workflow to your dotfiles repository: + +```yaml title=".github/workflows/check.yml" +name: Check dotfiles + +on: [push, pull_request] + +permissions: + contents: read + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-node@v7 + with: + node-version: 24 + - run: npm install --global https://github.com/mindsers/configfile/releases/download/1.0.0/configfile-1.0.0.tgz + # The following steps use a throwaway home folder, not the runner's. + - run: | + mkdir -p "$RUNNER_TEMP/home" + echo "HOME=$RUNNER_TEMP/home" >> "$GITHUB_ENV" + - run: configfile init --repo "$GITHUB_WORKSPACE" + - run: configfile modules deploy --all --dry-run +``` + +`init` accepts a local folder as the repository, here the checkout of the commit being tested. Nothing is deployed for real, and the runner's home folder isn't touched. The dry run fails if any module or entry is invalid, even when the others are fine, local files included. A file whose entry has no `deploy` strategy only produces a warning, as it does on your machines. + +To also test your setup script, add a step that runs it, on the systems it supports: + +```yaml + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + # … the steps above, then: + - run: configfile scripts run setup +``` + +Run it only if the script is safe to run on a fresh CI machine: it installs and changes things for real, as on your own computer. + +:::tip +In your editor, the [JSON Schema of `settings.json`](/reference/modules/#completion-and-validation-in-your-editor) catches most of these mistakes before you even commit. +::: diff --git a/docs/src/content/docs/guides/upgrading-from-0-3.md b/docs/src/content/docs/guides/upgrading-from-0-3.md index c613787..7adb3ce 100644 --- a/docs/src/content/docs/guides/upgrading-from-0-3.md +++ b/docs/src/content/docs/guides/upgrading-from-0-3.md @@ -1,6 +1,8 @@ --- title: Upgrading from 0.3 description: What changes for users of configfile 0.3. +sidebar: + order: 3 --- - Node.js 24.11 or later is required, on macOS or Linux. Install again as described in [Installation](/getting-started/installation/). To switch to Homebrew, remove the npm version first (`npm uninstall --global configfile`). diff --git a/docs/src/content/docs/index.md b/docs/src/content/docs/index.md index 8c45d06..e099060 100644 --- a/docs/src/content/docs/index.md +++ b/docs/src/content/docs/index.md @@ -9,7 +9,7 @@ description: Manage your dotfiles and setup scripts from a git repository, on ma - [How it works](/concepts/how-it-works/): your repository, the mirror configfile keeps, and what it deploys. - [Safety and trust](/concepts/safety/): what configfile protects, and what it refuses to touch. - Reference: [commands](/reference/commands/), [modules and `settings.json`](/reference/modules/), [scripts](/reference/scripts/), [configuration](/reference/configuration/), [history](/reference/history/). -- [Upgrading from 0.3](/guides/upgrading-from-0-3/). +- Guides: [set up a new machine](/guides/new-machine/), [use configfile in scripts and CI](/guides/scripts-and-ci/), [upgrade from 0.3](/guides/upgrading-from-0-3/). - [Changelog](https://github.com/mindsers/configfile/blob/develop/CHANGELOG.md): what changed in each version. ## Contribution