Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
dfefe8a
WIP
ryapric May 29, 2023
8f34b5a
Broken WIP for moving between computers
ryapric Jul 3, 2023
4fdd01f
WIP
ryapric Jul 4, 2023
947b9fd
Add pre-commit hook
ryapric Jul 4, 2023
7d965ef
Got spec_test working, now I just need to get remote/file working for…
ryapric Jul 4, 2023
bd5e8ac
Got tests passing by building a VDMMETA constructor
ryapric Jul 5, 2023
c714d43
lots, still need more tests
ryapric Jul 5, 2023
a36e6f8
Tweak some asserts to requires
ryapric Jul 6, 2023
975ccbf
Add WIP support for Debian packaging
ryapric Jul 6, 2023
fdf9043
Rename VDMSpec to Spec
ryapric Jul 10, 2023
c99f5c5
Tweaks
ryapric Jul 22, 2024
9d86985
Change files to YAML, rename Spec to Remote and add wrapper Spec
ryapric Jul 26, 2024
dc91c13
Replace logrus with a small custom message printer
ryapric Jul 26, 2024
e6b2e7c
Swap out staticcheck for revive because it catches missing docstrings
ryapric Jul 26, 2024
90726ea
Fix linter failures, add GHA workflow
ryapric Jul 28, 2024
c28d977
ugh GHA
ryapric Jul 28, 2024
2fc88b1
Use real checkout version
ryapric Jul 28, 2024
0c5b72c
Oops structure
ryapric Jul 28, 2024
0ce0284
Oops structure again
ryapric Jul 28, 2024
a144ec2
Add packaging check to CI suite
ryapric Jul 28, 2024
fa1f679
Add version specifier tooling, fix CI packaging check failure
ryapric Jul 28, 2024
a918b22
Realized debug flag setting wasn't working so fixed it, and some othe…
ryapric Jul 28, 2024
36b91b5
Adding errors.Join means I need to bump the Go version
ryapric Jul 28, 2024
5352eab
Add tagger script, other tweaks
ryapric Jul 28, 2024
5ca9d00
Update packaging, and add GHA for cutting a release
ryapric Jul 28, 2024
edff424
oops typo
ryapric Jul 29, 2024
f76d2b9
Catch some things that should have been consts
ryapric Jul 29, 2024
5dc3133
Add more to README, add Version field to rootCmd
ryapric Jul 29, 2024
d4bbe27
Fix for file types possibly not having parent directories
ryapric Jul 29, 2024
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
43 changes: 43 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: main

on:
push:
branches: [main]
pull_request:
types: [opened, reopened, synchronize]

jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.20'
- name: Run CI checks
run: 'make ci'
tag:
if: github.ref == 'refs/heads/main'
needs: ci
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Tag for release
run: 'make tag-release'
release:
if: github.ref == 'refs/heads/main'
needs: tag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.20'
- name: Package binaries
run: 'make package'
- name: Create GitHub Release
run: gh release create "v$(grep -v '#' ./VERSION)" --generate-notes --verify-tag --latest ./dist/zipped/*
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@
*cache*
build/
deps/
dist/
Empty file added CHANGELOG
Empty file.
14 changes: 14 additions & 0 deletions Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This Containerfile isn't mean for creating artifacts etc., it's just a way to
# perform portable, local CI checks in case there are workstation-specific
# issues a developer faces.
FROM docker.io/library/golang:1.20

RUN apt-get update && apt-get install -y \
ca-certificates \
make \
sudo

COPY . /go/app
WORKDIR /go/app

RUN make ci
68 changes: 35 additions & 33 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,60 @@ SHELL = /usr/bin/env bash -euo pipefail

BINNAME := vdm

all: test clean

.PHONY: %

test: clean
go vet ./...
go test -cover -coverprofile=./cover.out ./...
staticcheck ./...
make -s clean
all: ci package package-debian

ci: clean
@bash ./scripts/ci.sh

# test is just an alias for ci
test: ci

ci-container:
@docker build -f ./Containerfile -t vdm-test:latest .

test-coverage: test
go tool cover -html=./cover.out -o cover.html
xdg-open ./cover.html

# builds for the current platform only
build: clean
@mkdir -p build/$$(go env GOOS)-$$(go env GOARCH)
@go build -o build/$$(go env GOOS)-$$(go env GOARCH)/$(BINNAME)
@go build -buildmode=pie -o build/$$(go env GOOS)-$$(go env GOARCH)/$(BINNAME) -ldflags "-s -w"

xbuild: clean
@for target in \
darwin-amd64 \
linux-amd64 \
linux-arm \
linux-arm64 \
windows-amd64 \
; \
do \
GOOS=$$(echo "$${target}" | cut -d'-' -f1) ; \
GOARCH=$$(echo "$${target}" | cut -d'-' -f2) ; \
outdir=build/"$${GOOS}-$${GOARCH}" ; \
mkdir -p "$${outdir}" ; \
printf "Building for %s-%s into build/ ...\n" "$${GOOS}" "$${GOARCH}" ; \
GOOS="$${GOOS}" GOARCH="$${GOARCH}" go build -o "$${outdir}"/$(BINNAME) ; \
done
@bash ./scripts/xbuild.sh

package: xbuild
@mkdir -p dist
@cd build || exit 1; \
for built in * ; do \
printf 'Packaging for %s into dist/ ...\n' "$${built}" ; \
cd $${built} && tar -czf ../../dist/$(BINNAME)_$${built}.tar.gz * && cd - >/dev/null ; \
done
@bash ./scripts/package.sh

package-debian: build
@bash ./scripts/package-debian.sh

clean:
@rm -rf \
/tmp/$(BINNAME)-tests \
*cache* \
.*cache* \
./build/ \
./dist/ \
./deps/ \
./testdata/deps/
./dist/zipped/*.tar.gz \
./dist/zipped/*.zip \
./dist/debian/vdm.deb \
*.out
@sudo rm -rf ./dist/debian/vdm/usr
# TODO: until I sort out the tests to write test data consistently, these deps/
# directories etc. can kind of show up anywhere
@find . -type d -name '*deps*' -exec rm -rf {} +
@find . -type f -name '*VDMMETA*' -delete

bump-versions: clean
@bash ./scripts/bump-versions.sh "$${old_version:-}"

tag-release: clean
@bash ./scripts/tag-release.sh

pre-commit-hook:
cp ./scripts/ci.sh ./.git/hooks/pre-commit

# Some targets that help set up local workstations with rhad tooling. Assumes
# ~/.local/bin is on $PATH
Expand Down
130 changes: 101 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,116 @@
# vdm: Versioned Dependency Manager
# vdm: A General-Purpose Versioned-Dependency Manager

`vdm` is an alternative to git submodules for managing external dependencies for
the same reasons, in a more sane way.
`vdm` is an alternative to e.g. Git Submodules for managing arbitrary external
dependencies for the same reasons, in a more sane way. Unlike some other tools
that try to solve this problem, `vdm` is language-agnostic, and can be used for
any purpose that you would need remote development resources.

To get started, you'll need a `vdm` spec file, which is just a JSON array of all
your external dependencies along with their revisions & where you want them to
live in your repo:
`vdm` can be used for many different purposes, but most commonly as a way to
track external dependencies that your own code might need, but that you don't
have a language-native way to specify. Some examples might be:

[
{
"remote": "https://github.com/opensourcecorp/go-common",
"version": "v0.2.0", // tag; can also be a branch, short or long commit hash, or the word 'latest'
"local_path": "./deps/go-common"
}
]
- You have a shared CI repo from which you need to access common shell scripts,
hosted build tasks, etc.

You can have as many dependency specifications in that array as you want. By
default, this spec file is called `vdm.json` and lives at the calling location
(which is probably your repo's root), but you can call it whatever you want and
point to it using the `-spec-file` flag to `vdm`.
- You're building & testing a backend application and need to test serving
frontend code from it, and your team has that frontend code in another
repository.

- Your team uses protocol buffers and you need to be able to import other loose
`.proto` files to generate your own code.

`vdm` lets you clearly specify all those remote dependencies & more, and
retrieve them whenever you need them.

## Getting Started

### Installation

`vdm` can be installed from [its GitHub Releases
page](https://github.com/opensourcecorp/vdm/releases). There is a zipped binary
for major platforms & architectures, and those are indicated in the Asset file
name. For example, if you have an M2 macOS laptop, you would download the
`vdm_darwin-arm64.tar.gz` file, and extract it to somewhere on your `$PATH`.

If you have a recent version of the Go toolchain available, you can also install
or run `vdm` using `go`:

```sh
go install github.com/opensourcecorp/vdm@<vX.Y.Z|latest>
# or
go run github.com/opensourcecorp/vdm@<vX.Y.Z|latest> ...
```

### Usage

To get started, you'll need a `vdm` spec file, which is just a YAML (or JSON)
file specifying all your external dependencies along with (usually) their
revisions & where you want them to live on your filesystem:

```yaml
remotes:

- type: "git" # the default, and so can be omitted if desired
remote: "https://github.com/opensourcecorp/go-common" # can specify as 'git@...' to use SSH instead
local_path: "./deps/go-common"
version: "v0.2.0" # tag example; can also be a branch, commit hash, or the word 'latest'

- type: "file" # the 'file' type assumes the version is in the remote field itself somehow, so 'version' can be omitted
remote: "https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/http.proto"
local_path: "./deps/proto/http/http.proto"
```

You can have as many dependency specifications in that array as you want, and
they can be stored wherever you want. By default, this spec file is called
`vdm.yaml` and lives at the calling location (which is probably your repo's
root), but you can call it whatever you want and point to it using the
`--spec-file` flag to `vdm`.

Once you have a spec file, just run:

vdm sync
```sh
vdm sync
```

and `vdm` will process the spec file, retrieve your dependencies as specified,
and put them where you told them to go. By default, `vdm sync` also removes the
local `.git` directories for each `git` remote, so as to not upset your local
Git tree. If you want to change the version/revision of a remote, just update
your spec file and run `vdm sync` again.

After running `vdm sync` with the above example spec file, your directory tree
would look something like this:

and `vdm` will process the spec file, grab your dependencies, put them where
they belong, and check out the right versions. By default, `vdm sync` also
removes the local `.git` directories for each remote, so as to not upset your
local Git tree. If you want to change the version/revision of a remote, just
update your spec file and run `vdm sync` again.
```txt
./vdm.yaml
./deps/
go-common/
<stuff in that repo>
http.proto
```

If for any reason you want all the deps in the spec file to retain their `.git`
directories (such as if you're using `vdm` to initialize a new computer with
actual repos you'd be working in), you can pass the `-keep-git-dir` flag to `vdm
sync`.
## Dependencies

`vdm` is distributed as a statically-linked binary per platform that has no
language-specific dependencies. However, note that at the time of this writing,
`vdm` *does* depends on `git` being installed if you specify any `git` remote
types. `vdm` will fail with an informative error if it can't find `git` on your
`$PATH`.

## A note about auth

`vdm` has zero goals to be an authN/authZ manager. If a remote in your spec file
depends on a certain auth setup (an SSH key, something for HTTP basic auth like
a `.netrc` file, an `.npmrc` config file, etc.), that setup is out of `vdm`'s
scope. If required, you will need to ensure proper auth is configured before
running `vdm` commands.

## Future work

- Make the sync mechanism more robust, such that if your spec file changes to
remove remotes, they'll get cleaned up automatically.

- Support more than just Git -- but I really don't care that much about this
right now.
- Add `--keep-git-dir` flag so that `git` remote types don't wipe the `.git`
directory at clone-time.

- Support more than just `git` and `file` types, and make `file` better
3 changes: 3 additions & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Version number used as an anchor for listed versions in various files in the
# tree, orchestrated by scripts/bump-versions.sh
0.2.0
4 changes: 4 additions & 0 deletions cmd/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*
Package cmd calls the implementation logic for vdm.
*/
package cmd
19 changes: 19 additions & 0 deletions cmd/flagsupport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cmd

import (
"os"

"github.com/opensourcecorp/vdm/internal/message"
"github.com/spf13/viper"
)

// MaybeSetDebug sets the DEBUG environment variable if it was set as a flag by
// the caller.
func MaybeSetDebug() {
if viper.GetBool(debugFlagKey) {
err := os.Setenv("DEBUG", "true")
if err != nil {
message.Fatalf("internal error: unable to set environment variable DEBUG")
}
}
}
Loading