Goplicate


Why and how

In cases where we have many snippets that are repeated between different repositories in the same project or across projects, it becomes a real hassle to keep them up-to-date.

We want to stay DRY.

Goplicate achieves that by defining “blocks” around such shared snippets and automates their update via a shared source that contains the most up-to-date version of those snippets.

Design principles

  • Keep it simple – Treat snippets as text, not assuming anything about structure or correctness.

Example use case

Let’s say that we have a common configuration that we need to maintain for multiple projects. In this example, we’ll use an imaginary .pre-commit-config.yaml (https://pre-commit.com):

Project 1:

repos:
  - repo: https://github.com/some/repo
    rev: v1.2.3
    hooks:
      - id: my-common-pre-commit-hook
  - repo: local
    hooks:
      - id: my-project-1-pre-commit-hook

Project 2:

repos:
  - repo: https://github.com/some/repo
    rev: v1.2.3
    hooks:
      - id: my-common-pre-commit-hook
  - repo: local
    hooks:
      - id: my-project-2-pre-commit-hook

If we have many such projects that we have to maintain the common pre-commit hook for, it starts getting messy. Goplicate comes to the rescue!

Step 1

For each project, add a goplicate comment that will denote a section as managed by Goplicate:

repos:
  # goplicate(name=common,pos=start)
  - repo: https://github.com/some/repo
    rev: v{{.some_repo_version}} # optionally add params
    hooks:
      - id: my-common-pre-commit-hook
  # goplicate(name=common,pos=end)
  - repo: local
    hooks:
      - id: my-project-1-pre-commit-hook

Step 2

Initialize a new .goplicate.yaml file in each of the projects:

targets:
  - path: .pre-commit-hooks.yaml
    source: ../goplicate/pre-commit-common.yaml
    params: ../goplicate/params.yaml

Where targets is a list of configurations to apply to path from source templated with data from params

Step 3

Define the Goplicate repository in the source path (in our example, ../goplicate) with the following files inside:

.pre-commit-common.yaml:

  # goplicate(name=common,pos=start)
  - repo: https://github.com/some/repo
    rev: v1.3.0
    hooks:
      - id: my-common-pre-commit-hook
  # goplicate(name=common,pos=end)

.params.yaml:

some_repo_version: "1.3.0"

Now, if we run goplicate run from one of our defined projects, we’ll see that rev was changed from v1.2.4 to v1.3.0!

GitHub

View Github