From 764e83e123ed5c6e946d262b8e0a914a6a980011 Mon Sep 17 00:00:00 2001 From: Dan Buchholz Date: Sun, 17 Dec 2023 12:01:32 -0800 Subject: [PATCH 01/12] feat: version flag & GH tag/version action --- .github/workflows/update-version.yml | 38 ++++++++++++++++++++++++++++ cmd/vaults/main.go | 6 +++-- cmd/vaults/utils.go | 23 +++++++++++++++++ version.json | 3 +++ 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/update-version.yml create mode 100644 cmd/vaults/utils.go create mode 100644 version.json diff --git a/.github/workflows/update-version.yml b/.github/workflows/update-version.yml new file mode 100644 index 0000000..292d82f --- /dev/null +++ b/.github/workflows/update-version.yml @@ -0,0 +1,38 @@ +name: Update Version + +on: + push: + branches: + - main + - dtb/cli-positionals # tmp + +jobs: + update-version: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Git + run: | + git config --global user.name 'GitHub Actions' + git config --global user.email 'actions@github.com' + + - name: Get latest tag + id: get-latest-tag + run: echo ::set-output name=TAG::$(git describe --tags --abbrev=0) + + - name: Update version.json + run: | + echo "{\"version\": \"${{ steps.get-latest-tag.outputs.TAG }}\"}" > version.json + + - name: Commit and push if changed + run: | + git diff + if [ -n "$(git diff --name-only)" ]; then + git add version.json + git commit -m "Update version to ${{ steps.get-latest-tag.outputs.TAG }}" + git push + else + echo "No changes in version.json" diff --git a/cmd/vaults/main.go b/cmd/vaults/main.go index 300bd4e..621e69d 100644 --- a/cmd/vaults/main.go +++ b/cmd/vaults/main.go @@ -10,10 +10,12 @@ import ( func main() { // migrate v1 config to v2 config migrateConfigV1ToV2() + var version = getVersion() cliApp := &cli.App{ - Name: "vaults", - Usage: "Continuously publish data from your database to the Textile Vaults network.", + Name: "vaults", + Usage: "Continuously publish data from your database to the Textile Vaults network.", + Version: version, Commands: []*cli.Command{ newVaultCreateCommand(), newStreamCommand(), diff --git a/cmd/vaults/utils.go b/cmd/vaults/utils.go new file mode 100644 index 0000000..b63c94e --- /dev/null +++ b/cmd/vaults/utils.go @@ -0,0 +1,23 @@ +package main + +import ( + "encoding/json" + "os" +) + +type version struct { + Version string `json:"version"` +} + +func getVersion() string { + var v version + data, err := os.ReadFile("version.json") + if err != nil { + return "unknown" + } + err = json.Unmarshal(data, &v) + if err != nil { + return "unknown" + } + return v.Version +} diff --git a/version.json b/version.json new file mode 100644 index 0000000..1be1b18 --- /dev/null +++ b/version.json @@ -0,0 +1,3 @@ +{ + "version": "0.0.0" +} From 945ea7dc392fdb2aeb47a67c55e03cbb823c9cac Mon Sep 17 00:00:00 2001 From: Dan Buchholz Date: Sun, 17 Dec 2023 14:10:22 -0800 Subject: [PATCH 02/12] feat: add cmd aliases, descriptive error strings, & docs improvements --- cmd/vaults/commands.go | 118 ++++++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 36 deletions(-) diff --git a/cmd/vaults/commands.go b/cmd/vaults/commands.go index bc87d2a..05f9b64 100644 --- a/cmd/vaults/commands.go +++ b/cmd/vaults/commands.go @@ -40,42 +40,53 @@ func newVaultCreateCommand() *cli.Command { var winSize, cache int64 return &cli.Command{ - Name: "create", - Usage: "create a new vault", + Name: "create", + Usage: "Create a new vault", + UsageText: "vaults create [command options]", + Description: "Create a vault for a given account's address as either database streaming or file uploading. Optionally, also set a cache duration for the data.", Flags: []cli.Flag{ &cli.StringFlag{ Name: "account", + Aliases: []string{"a"}, + Category: "REQUIRED", Usage: "Ethereum wallet address", Destination: &address, Required: true, }, - &cli.StringFlag{ - Name: "dburi", - Usage: "PostgreSQL connection string", - Destination: &dburi, - }, &cli.StringFlag{ Name: "provider", - Usage: "The provider's address and port (e.g. localhost:8080)", + Category: "OPTIONAL", + Aliases: []string{"p"}, + Usage: "The provider's address and port (e.g., localhost:8080)", + DefaultText: DefaultProviderHost, Destination: &provider, Value: DefaultProviderHost, }, - &cli.Int64Flag{ - Name: "window-size", - Usage: "Number of seconds for which WAL updates are buffered before being sent to the provider", - Destination: &winSize, - Value: DefaultWindowSize, - }, &cli.Int64Flag{ Name: "cache", + Category: "OPTIONAL", Usage: "Time duration (in minutes) that the data will be available in the cache", Destination: &cache, Value: 0, }, + &cli.StringFlag{ + Name: "dburi", + Category: "DATABASE", + Usage: "PostgreSQL connection string (e.g., postgresql://postgres:[PASSWORD]@[HOST]:[PORT]/postgres)", + Destination: &dburi, + }, + &cli.Int64Flag{ + Name: "window-size", + Category: "DATABASE", + Usage: "Number of seconds for which WAL updates are buffered before being sent to the provider", + DefaultText: fmt.Sprintf("%d", DefaultWindowSize), + Destination: &winSize, + Value: DefaultWindowSize, + }, }, Action: func(cCtx *cli.Context) error { if cCtx.NArg() != 1 { - return errors.New("one argument should be provided") + return errors.New("must provide a vault name") } pub := cCtx.Args().First() @@ -149,11 +160,14 @@ func newStreamCommand() *cli.Command { var privateKey string return &cli.Command{ - Name: "stream", - Usage: "starts a daemon process that streams Postgres changes to a vault", + Name: "stream", + Usage: "Starts a daemon process that streams Postgres changes to a vault", + UsageText: "vaults stream [command options]", Flags: []cli.Flag{ &cli.StringFlag{ Name: "private-key", + Aliases: []string{"k"}, + Category: "REQUIRED", Usage: "Ethereum wallet private key", Destination: &privateKey, Required: true, @@ -161,7 +175,7 @@ func newStreamCommand() *cli.Command { }, Action: func(cCtx *cli.Context) error { if cCtx.NArg() != 1 { - return errors.New("one argument should be provided") + return errors.New("must provide a vault name") } vault := cCtx.Args().First() @@ -249,30 +263,36 @@ func newWriteCommand() *cli.Command { var timestamp string return &cli.Command{ - Name: "write", - Usage: "write a Parquet file", + Name: "write", + Usage: "Write a Parquet file", + UsageText: "vaults write [command options]", Flags: []cli.Flag{ &cli.StringFlag{ Name: "private-key", + Aliases: []string{"k"}, + Category: "REQUIRED", Usage: "Ethereum wallet private key", Destination: &privateKey, Required: true, }, &cli.StringFlag{ Name: "vault", + Category: "REQUIRED", Usage: "Vault name", Destination: &vaultName, Required: true, }, &cli.StringFlag{ Name: "timestamp", - Usage: "The time the file was created (default: current epoch in UTC)", + Category: "OPTIONAL", + Usage: "The time the file was created", + DefaultText: "current epoch in UTC", Destination: ×tamp, }, }, Action: func(cCtx *cli.Context) error { if cCtx.NArg() != 1 { - return errors.New("one argument should be provided") + return errors.New("must provide a file path") } ns, rel, err := parseVaultName(vaultName) if err != nil { @@ -339,18 +359,24 @@ func newListCommand() *cli.Command { var address, provider string return &cli.Command{ - Name: "list", - Usage: "list vaults of a given account", + Name: "list", + Usage: "List vaults of a given account", + UsageText: "vaults list [command options]", Flags: []cli.Flag{ &cli.StringFlag{ Name: "account", + Aliases: []string{"a"}, + Category: "REQUIRED", Usage: "Ethereum wallet address", Destination: &address, Required: true, }, &cli.StringFlag{ Name: "provider", - Usage: "The provider's address and port (e.g. localhost:8080)", + Aliases: []string{"p"}, + Category: "OPTIONAL", + Usage: "The provider's address and port (e.g., localhost:8080)", + DefaultText: DefaultProviderHost, Destination: &provider, Value: DefaultProviderHost, }, @@ -381,59 +407,74 @@ func newListEventsCommand() *cli.Command { var limit, offset, latest int return &cli.Command{ - Name: "events", - Usage: "list events of a given vault", + Name: "events", + Usage: "List events of a given vault", + UsageText: "vaults events [command options]", Flags: []cli.Flag{ &cli.StringFlag{ Name: "vault", + Category: "REQUIRED", Usage: "vault name", Destination: &vault, Required: true, }, &cli.StringFlag{ Name: "provider", - Usage: "The provider's address and port (e.g. localhost:8080)", + Category: "OPTIONAL", + Aliases: []string{"p"}, + Usage: "The provider's address and port (e.g., localhost:8080)", + DefaultText: DefaultProviderHost, Destination: &provider, Value: DefaultProviderHost, }, &cli.IntFlag{ Name: "limit", + Category: "OPTIONAL", Usage: "The number of deals to fetch", + DefaultText: "10", Destination: &limit, Value: 10, }, &cli.IntFlag{ Name: "latest", + Category: "OPTIONAL", Usage: "The latest N deals to fetch", Destination: &latest, }, &cli.IntFlag{ Name: "offset", + Category: "OPTIONAL", Usage: "The epoch to start from", + DefaultText: "0", Destination: &offset, Value: 0, }, &cli.StringFlag{ Name: "before", + Category: "OPTIONAL", Usage: "Filter deals created before this timestamp", Destination: &before, Value: "", }, &cli.StringFlag{ Name: "after", + Category: "OPTIONAL", Usage: "Filter deals created after this timestamp", Destination: &after, Value: "", }, &cli.StringFlag{ Name: "at", + Category: "OPTIONAL", Usage: "Filter deals created at this timestamp", Destination: &at, Value: "", }, &cli.StringFlag{ Name: "format", + Category: "OPTIONAL", Usage: "The output format (table or json)", + DefaultText: "table", Destination: &format, Value: "table", }, @@ -517,8 +558,10 @@ func newListEventsCommand() *cli.Command { func newRetrieveCommand() *cli.Command { return &cli.Command{ - Name: "retrieve", - Usage: "Retrieve an event by CID", + Name: "retrieve", + Usage: "Retrieve an event by CID", + UsageText: "vaults retrieve ", + Description: "Retrieving an event will download the event's CAR file into the current directory.", Action: func(cCtx *cli.Context) error { arg := cCtx.Args().Get(0) if arg == "" { @@ -567,12 +610,14 @@ func newRetrieveCommand() *cli.Command { func newWalletCommand() *cli.Command { return &cli.Command{ - Name: "wallet", - Usage: "wallet commands", + Name: "account", + Usage: "Account management for an Ethereum-style wallet", Subcommands: []*cli.Command{ { - Name: "create", - Usage: "creates a new wallet", + Name: "create", + Usage: "Creates a new account", + UsageText: "vaults account create ", + Description: "Create an Ethereum-style wallet (secp256k1 key pair) at a provided file path.", Action: func(cCtx *cli.Context) error { filename := cCtx.Args().Get(0) if filename == "" { @@ -597,8 +642,9 @@ func newWalletCommand() *cli.Command { }, }, { - Name: "pubkey", - Usage: "print the public key for a private key", + Name: "address", + Usage: "Print the public key for an account's private key", + UsageText: "vaults account address ", Action: func(cCtx *cli.Context) error { filename := cCtx.Args().Get(0) if filename == "" { From a7b0ce6b5a3aa51a9679298f588235c32cfafe09 Mon Sep 17 00:00:00 2001 From: Dan Buchholz Date: Sun, 17 Dec 2023 14:15:04 -0800 Subject: [PATCH 03/12] chore: add install to makefile --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index f45d4ab..f3c09d6 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,11 @@ build: go build -o vaults cmd/vaults/* .PHONY: build +# Install +install: + go install ./cmd/vaults +.PHONY: install + # Test test: go test ./... -short -race -timeout 1m From a1cf149758368d022c2a220d8937959e9bfbb9b0 Mon Sep 17 00:00:00 2001 From: Dan Buchholz Date: Sun, 17 Dec 2023 20:04:06 -0800 Subject: [PATCH 04/12] feat: add version command, list cmd json format, more docs --- cmd/vaults/commands.go | 82 +++++++++++++++++++++++++++--------------- cmd/vaults/main.go | 10 +++++- 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/cmd/vaults/commands.go b/cmd/vaults/commands.go index 05f9b64..78f9d5a 100644 --- a/cmd/vaults/commands.go +++ b/cmd/vaults/commands.go @@ -42,8 +42,8 @@ func newVaultCreateCommand() *cli.Command { return &cli.Command{ Name: "create", Usage: "Create a new vault", - UsageText: "vaults create [command options]", - Description: "Create a vault for a given account's address as either database streaming or file uploading. Optionally, also set a cache duration for the data.", + ArgsUsage: "", + Description: "Create a vault for a given account's address as either database streaming or file uploading. Optionally, also set a cache duration for the data.\n\nExample:\n\nvaults create --account 0x1234abcd --cache 10 my.vault", Flags: []cli.Flag{ &cli.StringFlag{ Name: "account", @@ -55,8 +55,8 @@ func newVaultCreateCommand() *cli.Command { }, &cli.StringFlag{ Name: "provider", - Category: "OPTIONAL", Aliases: []string{"p"}, + Category: "OPTIONAL", Usage: "The provider's address and port (e.g., localhost:8080)", DefaultText: DefaultProviderHost, Destination: &provider, @@ -66,18 +66,19 @@ func newVaultCreateCommand() *cli.Command { Name: "cache", Category: "OPTIONAL", Usage: "Time duration (in minutes) that the data will be available in the cache", + DefaultText: "0", Destination: &cache, Value: 0, }, &cli.StringFlag{ Name: "dburi", - Category: "DATABASE", + Category: "OPTIONAL", Usage: "PostgreSQL connection string (e.g., postgresql://postgres:[PASSWORD]@[HOST]:[PORT]/postgres)", Destination: &dburi, }, &cli.Int64Flag{ Name: "window-size", - Category: "DATABASE", + Category: "OPTIONAL", Usage: "Number of seconds for which WAL updates are buffered before being sent to the provider", DefaultText: fmt.Sprintf("%d", DefaultWindowSize), Destination: &winSize, @@ -160,9 +161,10 @@ func newStreamCommand() *cli.Command { var privateKey string return &cli.Command{ - Name: "stream", - Usage: "Starts a daemon process that streams Postgres changes to a vault", - UsageText: "vaults stream [command options]", + Name: "stream", + Usage: "Starts a daemon process that streams Postgres changes to a vault", + ArgsUsage: "", + Description: "The daemon will continuously stream database changes (except deletions) to the vault, as long as the daemon is actively running.\n\nExample:\n\nvaults stream --vault my.vault --private-key 0x1234abcd", Flags: []cli.Flag{ &cli.StringFlag{ Name: "private-key", @@ -263,9 +265,10 @@ func newWriteCommand() *cli.Command { var timestamp string return &cli.Command{ - Name: "write", - Usage: "Write a Parquet file", - UsageText: "vaults write [command options]", + Name: "write", + Usage: "Write a Parquet file", + ArgsUsage: "", + Description: "A Parquet file can be pushed directly to the vault, as an alternative to continuous Postgres data streaming.\n\nExample:\n\nvaults write --vault my.vault --private-key 0x1234abcd /path/to/file.parquet", Flags: []cli.Flag{ &cli.StringFlag{ Name: "private-key", @@ -356,12 +359,12 @@ func newWriteCommand() *cli.Command { } func newListCommand() *cli.Command { - var address, provider string + var address, provider, format string return &cli.Command{ - Name: "list", - Usage: "List vaults of a given account", - UsageText: "vaults list [command options]", + Name: "list", + Usage: "List vaults of a given account", + Description: "Listing vaults will show all vaults that have been created by the provided account's address and logged as either line delimited text or a json array.\n\nExample:\n\nvaults list --account 0x1234abcd --format json", Flags: []cli.Flag{ &cli.StringFlag{ Name: "account", @@ -380,6 +383,14 @@ func newListCommand() *cli.Command { Destination: &provider, Value: DefaultProviderHost, }, + &cli.StringFlag{ + Name: "format", + Category: "OPTIONAL", + Usage: "The output format (text or json)", + DefaultText: "text", + Destination: &format, + Value: "text", + }, }, Action: func(cCtx *cli.Context) error { account, err := app.NewAccount(address) @@ -393,8 +404,18 @@ func newListCommand() *cli.Command { return fmt.Errorf("failed to list vaults: %s", err) } - for _, vault := range vaults { - fmt.Printf("%s\n", vault) + if format == "text" { + for _, vault := range vaults { + fmt.Printf("%s\n", vault) + } + } else if format == "json" { + jsonData, err := json.Marshal(vaults) + if err != nil { + return fmt.Errorf("error serializing events to JSON") + } + fmt.Println(string(jsonData)) + } else { + return fmt.Errorf("invalid format: %s", format) } return nil @@ -407,21 +428,22 @@ func newListEventsCommand() *cli.Command { var limit, offset, latest int return &cli.Command{ - Name: "events", - Usage: "List events of a given vault", - UsageText: "vaults events [command options]", + Name: "events", + Usage: "List events of a given vault", + UsageText: "vaults events [command options]", + Description: "Vault events can be filtered by date ranges (unix, ISO 8601 date, or ISO 8601 date & time), returning the event metadata and corresponding CID.\n\nExample:\n\nvaults events --vault my.vault \\\n--limit 10 --offset 3 \\\n--after 2023-09-01 --before 2023-12-01 \\\n--format json", Flags: []cli.Flag{ &cli.StringFlag{ Name: "vault", Category: "REQUIRED", - Usage: "vault name", + Usage: "Vault name", Destination: &vault, Required: true, }, &cli.StringFlag{ Name: "provider", - Category: "OPTIONAL", Aliases: []string{"p"}, + Category: "OPTIONAL", Usage: "The provider's address and port (e.g., localhost:8080)", DefaultText: DefaultProviderHost, Destination: &provider, @@ -610,14 +632,15 @@ func newRetrieveCommand() *cli.Command { func newWalletCommand() *cli.Command { return &cli.Command{ - Name: "account", - Usage: "Account management for an Ethereum-style wallet", + Name: "account", + Usage: "Account management for an Ethereum-style wallet", + UsageText: "vaults account [arguments...]", Subcommands: []*cli.Command{ { Name: "create", Usage: "Creates a new account", - UsageText: "vaults account create ", - Description: "Create an Ethereum-style wallet (secp256k1 key pair) at a provided file path.", + UsageText: "vaults account create ", + Description: "Create an Ethereum-style wallet (secp256k1 key pair) at a provided file path.\n\nExample:\n\nvaults account create /path/to/file", Action: func(cCtx *cli.Context) error { filename := cCtx.Args().Get(0) if filename == "" { @@ -642,9 +665,10 @@ func newWalletCommand() *cli.Command { }, }, { - Name: "address", - Usage: "Print the public key for an account's private key", - UsageText: "vaults account address ", + Name: "address", + Usage: "Print the public key for an account's private key", + UsageText: "vaults account address ", + Description: "The result of the `vaults account create` command will write a private key to a file, and this lets you retrieve that value for use in other commands.\n\nExample:\n\nvaults account address /path/to/file", Action: func(cCtx *cli.Context) error { filename := cCtx.Args().Get(0) if filename == "" { diff --git a/cmd/vaults/main.go b/cmd/vaults/main.go index 621e69d..0c6d0ca 100644 --- a/cmd/vaults/main.go +++ b/cmd/vaults/main.go @@ -1,12 +1,20 @@ package main import ( + "fmt" "os" "github.com/urfave/cli/v2" "golang.org/x/exp/slog" ) +func init() { + cli.VersionFlag = &cli.BoolFlag{Name: "version", Aliases: []string{"V"}, Usage: "show version"} // Enforce uppercase + cli.VersionPrinter = func(c *cli.Context) { + fmt.Printf("v%s\n", c.App.Version) + } +} + func main() { // migrate v1 config to v2 config migrateConfigV1ToV2() @@ -14,7 +22,7 @@ func main() { cliApp := &cli.App{ Name: "vaults", - Usage: "Continuously publish data from your database to the Textile Vaults network.", + Usage: "Continuously publish data from your database or file uploads to the Textile Vaults network.", Version: version, Commands: []*cli.Command{ newVaultCreateCommand(), From f02b0aba75dfd4f0c4443ca705c23039b3496d4c Mon Sep 17 00:00:00 2001 From: Dan Buchholz Date: Sun, 17 Dec 2023 20:23:10 -0800 Subject: [PATCH 05/12] docs: update readme --- README.md | 90 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index e35aeab..7d599fd 100644 --- a/README.md +++ b/README.md @@ -3,43 +3,54 @@ [![License](https://img.shields.io/github/license/tablelandnetwork/basin-cli.svg)](./LICENSE) [![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg)](https://github.com/RichardLitt/standard-readme) -> Continuously publish data from your database to the Tableland network. +> Continuously publish data from your database or file uploads to the Tableland Vaults network. -# Table of Contents +## Table of Contents -- [Install](#install) -- [Postgres Setup](#postgres-setup) - - [Self-hosted](#self-hosted) - - [Amazon RDS](#amazon-rds) +- [Background](#background) +- [Usage](#usage) + - [Install](#install) + - [Postgres Setup](#postgres-setup) - [Supabase](#supabase) -- [Create a vault](#create-a-vault) -- [Start replicating a database](#start-replicating-a-database) -- [Write a Parquet file](#write-a-parquet-file) -- [Listing Vaults](#listing-vaults) -- [Listing Events](#listing-events) -- [Running](#running) -- [Run tests](#run-tests) -- [Retrieving](#retrieving) + - [Create a vault](#create-a-vault) + - [Start replicating a database](#start-replicating-a-database) + - [Write a Parquet file](#write-a-parquet-file) + - [Listing Vaults](#listing-vaults) + - [Listing Events](#listing-events) + - [Retrieving](#retrieving) +- [Development](#development) + - [Running](#running) + - [Run tests](#run-tests) +- [Contributing](#contributing) +- [License](#license) + +## Background + +Textile Vaults is a secure and verifiable open data platform. The Vaults CLI is a tool that allows you to continuously replicate a table or view from your database to the network (currently, only PostgreSQL is supported). Or, you can directly upload files to the vault (currently, parquet is only supported) -# Background +> 🚧 Vaults is currently not in a production-ready state. Any data that is pushed to the network may be subject to deletion. 🚧 -Textile Vaults is a secure and verifiable open data platform. The Vaults CLI is a tool that allows you to continuously replicate a table or view from your database to the network. Currently, only PostgreSQL is supported. +## Usage -> 🚧 Vaults is currently not in a production-ready state. Any data that is pushed to the network may be subject to deletion. 🚧 +### Install + +You can either install the CLI from the remote source: -# Usage +```bash +go install github.com/tablelandnetwork/basin-cli/cmd/basin@latest +``` -## Install +Or clone from source and run the Makefile `install` command: ```bash git clone https://github.com/tablelandnetwork/basin-cli.git cd basin-cli -go install ./cmd/vaults +make install ``` -## Postgres Setup +### Postgres Setup -### Self-hosted +#### Self-hosted - Make sure you have access to a superuser role. For example, you can create a new role such as `CREATE ROLE vaults WITH PASSWORD NULL LOGIN SUPERUSER;`. - Check that your Postgres installation has the [wal2json](https://github.com/eulerto/wal2json) plugin installed. @@ -53,7 +64,7 @@ go install ./cmd/vaults - Restart the database in order for the new `wal_level` to take effect (be careful!). -### Amazon RDS +#### Amazon RDS - Make sure you have a user with the `rds_superuser` role, and use `psql` to connect to your database. @@ -88,14 +99,14 @@ go install ./cmd/vaults postgresql://postgres:[PASSWORD]@db.[PROJECT_ID].supabase.co:5432/postgres ``` -## Create a vault +### Create a vault _Vaults_ define the place you push data into. Vaults uses public key authentication, so you will need an Ethereum style (ECDSA, secp256k1) wallet to create a new vault. You can use an existing wallet or set up a new one with `vaults wallet create`. Your private key is only used locally for signing. ```bash -vaults wallet create [FILENAME] +vaults account create [FILENAME] ``` A new private key will be written to `FILENAME`. @@ -108,7 +119,7 @@ vaults create --dburi [DBURI] --account [WALLET_ADDRESS] namespace.relation_nam 🚧 Vaults currently only replicates `INSERT` statements, which means that it only replicates append-only data (e.g., log-style data). Row updates and deletes will be ignored. 🚧 -## Start replicating a database +### Start replicating a database Use `vaults stream` to start a daemon that will continuously push changes to the underlying table/view to the network. See `vaults stream --help` for more info. @@ -116,7 +127,7 @@ Use `vaults stream` to start a daemon that will continuously push changes to the vaults stream --private-key [PRIVATE_KEY] namespace.relation_name ``` -## Write a Parquet file +### Write a Parquet file Before writing a Parquet file, you need to [Create a vault](#create-a-vault), if not already created. You can omit the `--dburi` flag, in this case. @@ -126,7 +137,7 @@ Then, use `vaults write` to write a Parquet file. vaults write --vault [namespace.relation_name] --private-key [PRIVATE_KEY] filepath ``` -You can attach a timestamp to that file write, e.g. +You can attach a timestamp to that file write, e.g. ```bash vaults write --vault [namespace.relation_name] --private-key [PRIVATE_KEY] --timestamp 1699984703 filepath @@ -140,7 +151,7 @@ vaults write --vault [namespace.relation_name] --private-key [PRIVATE_KEY] --tim If a timestamp is not provided, the CLI will assume the timestamp is the current client epoch in UTC. -## Listing Vaults +### Listing Vaults You can list the vaults from an account by running: @@ -148,7 +159,7 @@ You can list the vaults from an account by running: vaults list --account [ETH_ADDRESS] ``` -## Listing Events +### Listing Events You can list events of a given vault by running: @@ -162,18 +173,18 @@ Events command accept `--before`,`--after` , and `--at` flags to filter events b # examples vaults events --vault demotest.data --at 1699569502 vaults events --vault demotest.data --before 2023-11-09T19:38:23-03:00 -vaults events --vault demotest.data --after 2023-11-09 +vaults events --vault demotest.data --after 2023-11-09 ``` -## Retrieving +### Retrieving ```bash vaults retrieve bafybeifr5njnrw67yyb2h2t7k6ukm3pml4fgphsxeurqcmgmeb7omc2vlq ``` -# Development +## Development -## Running +### Running You can make use of the scripts inside `scripts` to facilitate running the CLI locally without building. @@ -181,14 +192,14 @@ You can make use of the scripts inside `scripts` to facilitate running the CLI l # Starting the Provider Server PORT=8888 ./scripts/server.sh -# Create a wallet -./scripts/run.sh wallet create pk.out +# Create an account +./scripts/run.sh account create pk.out # Start replicating ./scripts/run.sh vaults stream --private-key [PRIVATE_KEY] namespace.relation_name ``` -## Run tests +### Run tests ```bash make test @@ -196,14 +207,13 @@ make test Note: One of the tests requires Docker Engine to be running. - -# Contributing +## Contributing PRs accepted. Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. -# License +## License MIT AND Apache-2.0, © 2021-2023 Tableland Network Contributors From c270b94d58fdf165fdb1b86da390235534be8698 Mon Sep 17 00:00:00 2001 From: Dan Buchholz Date: Sun, 17 Dec 2023 21:19:15 -0800 Subject: [PATCH 06/12] fix: alter gh version action logic, version logging --- .github/workflows/update-version.yml | 38 ++++++++++++---------------- cmd/vaults/main.go | 2 +- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/.github/workflows/update-version.yml b/.github/workflows/update-version.yml index 292d82f..642c1b1 100644 --- a/.github/workflows/update-version.yml +++ b/.github/workflows/update-version.yml @@ -1,38 +1,32 @@ -name: Update Version +name: Update version file on: push: branches: - main - dtb/cli-positionals # tmp + workflow_dispatch: jobs: - update-version: + update_version: runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Set up Git - run: | - git config --global user.name 'GitHub Actions' - git config --global user.email 'actions@github.com' + - uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Get latest tag - id: get-latest-tag - run: echo ::set-output name=TAG::$(git describe --tags --abbrev=0) + id: get-tag + run: | + echo "LATEST_TAG=$(git describe --tags $(git rev-list --tags --max-count=1))" >> $GITHUB_OUTPUT - name: Update version.json run: | - echo "{\"version\": \"${{ steps.get-latest-tag.outputs.TAG }}\"}" > version.json + echo "{ + \"version\": \"${{steps.get-tag.outputs.LATEST_TAG}}\" + }" > version.json - - name: Commit and push if changed - run: | - git diff - if [ -n "$(git diff --name-only)" ]; then - git add version.json - git commit -m "Update version to ${{ steps.get-latest-tag.outputs.TAG }}" - git push - else - echo "No changes in version.json" + - name: Commit changes + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "chore: update version to ${{steps.get-tag.outputs.LATEST_TAG}}" diff --git a/cmd/vaults/main.go b/cmd/vaults/main.go index 0c6d0ca..d4dfd9b 100644 --- a/cmd/vaults/main.go +++ b/cmd/vaults/main.go @@ -11,7 +11,7 @@ import ( func init() { cli.VersionFlag = &cli.BoolFlag{Name: "version", Aliases: []string{"V"}, Usage: "show version"} // Enforce uppercase cli.VersionPrinter = func(c *cli.Context) { - fmt.Printf("v%s\n", c.App.Version) + fmt.Printf("%s\n", c.App.Version) } } From dea664ea17d0009a4e2d1406d0c70dd41f144ddf Mon Sep 17 00:00:00 2001 From: dtbuchholz Date: Mon, 18 Dec 2023 05:19:32 +0000 Subject: [PATCH 07/12] chore: update version to v0.0.6 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 1be1b18..0c7dfa8 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "0.0.0" + "version": "v0.0.6" } From b7a45aa1ef0359487fd128ca172a233ac7b47125 Mon Sep 17 00:00:00 2001 From: Dan Buchholz Date: Sun, 17 Dec 2023 21:25:08 -0800 Subject: [PATCH 08/12] feat: add vault alias flag '-v' --- cmd/vaults/commands.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/vaults/commands.go b/cmd/vaults/commands.go index 78f9d5a..12df9b6 100644 --- a/cmd/vaults/commands.go +++ b/cmd/vaults/commands.go @@ -280,6 +280,7 @@ func newWriteCommand() *cli.Command { }, &cli.StringFlag{ Name: "vault", + Aliases: []string{"v"}, Category: "REQUIRED", Usage: "Vault name", Destination: &vaultName, @@ -435,6 +436,7 @@ func newListEventsCommand() *cli.Command { Flags: []cli.Flag{ &cli.StringFlag{ Name: "vault", + Aliases: []string{"v"}, Category: "REQUIRED", Usage: "Vault name", Destination: &vault, From d71ceac10b540e2e902af95dedfd8dc30eb0b495 Mon Sep 17 00:00:00 2001 From: Dan Buchholz Date: Sun, 17 Dec 2023 22:46:02 -0800 Subject: [PATCH 09/12] feat: retrieve to custom output dir or stdout --- .github/workflows/update-version.yml | 3 +- README.md | 16 +++++++- cmd/vaults/commands.go | 60 +++++++++++++++++++++++++--- 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/.github/workflows/update-version.yml b/.github/workflows/update-version.yml index 642c1b1..209fd09 100644 --- a/.github/workflows/update-version.yml +++ b/.github/workflows/update-version.yml @@ -4,7 +4,6 @@ on: push: branches: - main - - dtb/cli-positionals # tmp workflow_dispatch: jobs: @@ -23,7 +22,7 @@ jobs: - name: Update version.json run: | echo "{ - \"version\": \"${{steps.get-tag.outputs.LATEST_TAG}}\" + \"version\": \"${{steps.get-tag.outputs.LATEST_TAG}}\" }" > version.json - name: Commit changes diff --git a/README.md b/README.md index 7d599fd..93608a9 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ A new private key will be written to `FILENAME`. The name of a vault contains a `namespace` (e.g. `my_company`) and the name of an existing database relation (e.g. `my_table`), separated by a period (`.`). Use `vaults create` to create a new vault. See `vaults create --help` for more info. ```bash -vaults create --dburi [DBURI] --account [WALLET_ADDRESS] namespace.relation_name +vaults create --dburi [DBURI] --account [WALLET_ADDRESS] namespace.relation_name ``` 🚧 Vaults currently only replicates `INSERT` statements, which means that it only replicates append-only data (e.g., log-style data). Row updates and deletes will be ignored. 🚧 @@ -178,10 +178,24 @@ vaults events --vault demotest.data --after 2023-11-09 ### Retrieving +You can retrieve a file from a vault by running: + ```bash vaults retrieve bafybeifr5njnrw67yyb2h2t7k6ukm3pml4fgphsxeurqcmgmeb7omc2vlq ``` +You can also specify where to save the file: + +```bash +vaults retrieve --output /path/to/dir bafybeifr5njnrw67yyb2h2t7k6ukm3pml4fgphsxeurqcmgmeb7omc2vlq +``` + +Or stream the file to stdout the `-` value (note: the short form `-o` is for `--output`), and then pipe it to something like [`car extract`](https://github.com/ipld/go-car) to unpack the CAR file's contents: + +```bash +vaults retrieve -o - bafybeifr5njnrw67yyb2h2t7k6ukm3pml4fgphsxeurqcmgmeb7omc2vlq | car extract +``` + ## Development ### Running diff --git a/cmd/vaults/commands.go b/cmd/vaults/commands.go index 12df9b6..e6a9358 100644 --- a/cmd/vaults/commands.go +++ b/cmd/vaults/commands.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "io" "os" "path" "regexp" @@ -581,20 +582,32 @@ func newListEventsCommand() *cli.Command { } func newRetrieveCommand() *cli.Command { + var output string + return &cli.Command{ Name: "retrieve", Usage: "Retrieve an event by CID", - UsageText: "vaults retrieve ", - Description: "Retrieving an event will download the event's CAR file into the current directory.", + ArgsUsage: "", + Description: "Retrieving an event will download the event's CAR file into the current directory, a provided directory path, or to stdout.\n\nExample:\n\nvaults retrieve --output /path/to/dir bafy...", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "output", + Aliases: []string{"o"}, + Category: "OPTIONAL", + Usage: "Output directory path, or '-' for stdout", + DefaultText: "current directory", + Destination: &output, + }, + }, Action: func(cCtx *cli.Context) error { arg := cCtx.Args().Get(0) if arg == "" { - return errors.New("argument is empty") + return errors.New("must provide an event CID") } rootCid, err := cid.Parse(arg) if err != nil { - return errors.New("cid is invalid") + return errors.New("CID is invalid") } lassie, err := lassie.NewLassie(cCtx.Context) @@ -607,7 +620,35 @@ func newRetrieveCommand() *cli.Command { car.StoreIdentityCIDs(false), car.UseWholeCIDs(false), } - carWriter := deferred.NewDeferredCarWriterForPath(fmt.Sprintf("./%s.car", arg), []cid.Cid{rootCid}, carOpts...) + + var carWriter *deferred.DeferredCarWriter + var tmpFile *os.File + + if output == "-" { + // Create a temporary file only for writing to stdout case + tmpFile, err := os.CreateTemp("", fmt.Sprintf("%s.car", arg)) + if err != nil { + return fmt.Errorf("failed to create temporary file: %s", err) + } + defer os.Remove(tmpFile.Name()) + carWriter = deferred.NewDeferredCarWriterForPath(tmpFile.Name(), []cid.Cid{rootCid}, carOpts...) + } else { + // Write to the provided path or current directory + if output == "" { + output = "." // Default to current directory + } + // Ensure path is a valid directory + info, err := os.Stat(output) + if err != nil { + return fmt.Errorf("failed to access output directory: %s", err) + } + if !info.IsDir() { + return fmt.Errorf("output path is not a directory: %s", output) + } + carPath := path.Join(output, fmt.Sprintf("%s.car", arg)) + carWriter = deferred.NewDeferredCarWriterForPath(carPath, []cid.Cid{rootCid}, carOpts...) + } + defer func() { _ = carWriter.Close() }() @@ -627,6 +668,15 @@ func newRetrieveCommand() *cli.Command { return fmt.Errorf("failed to fetch: %s", err) } + // Write to stdout only if the output flag is set to '-' + if output == "-" && tmpFile != nil { + _, _ = tmpFile.Seek(0, io.SeekStart) + _, err = io.Copy(os.Stdout, tmpFile) + if err != nil { + return fmt.Errorf("failed to write to stdout: %s", err) + } + } + return nil }, } From 571935a592d4c5311a1a2c891da29421087416eb Mon Sep 17 00:00:00 2001 From: Dan Buchholz Date: Mon, 18 Dec 2023 11:55:28 -0800 Subject: [PATCH 10/12] chore: linting fixes; capitalization, new lines, colon usage in doc strings --- cmd/vaults/commands.go | 135 ++++++++++++++++++++++++----------------- cmd/vaults/main.go | 9 ++- 2 files changed, 87 insertions(+), 57 deletions(-) diff --git a/cmd/vaults/commands.go b/cmd/vaults/commands.go index e6a9358..adc8c66 100644 --- a/cmd/vaults/commands.go +++ b/cmd/vaults/commands.go @@ -41,15 +41,17 @@ func newVaultCreateCommand() *cli.Command { var winSize, cache int64 return &cli.Command{ - Name: "create", - Usage: "Create a new vault", - ArgsUsage: "", - Description: "Create a vault for a given account's address as either database streaming or file uploading. Optionally, also set a cache duration for the data.\n\nExample:\n\nvaults create --account 0x1234abcd --cache 10 my.vault", + Name: "create", + Usage: "Create a new vault", + ArgsUsage: "", + Description: "Create a vault for a given account's address as either database streaming \n" + + "or file uploading. Optionally, also set a cache duration for the data.\n\nEXAMPLE:\n\n" + + "vaults create --account 0x1234abcd --cache 10 my.vault", Flags: []cli.Flag{ &cli.StringFlag{ Name: "account", Aliases: []string{"a"}, - Category: "REQUIRED", + Category: "REQUIRED:", Usage: "Ethereum wallet address", Destination: &address, Required: true, @@ -57,7 +59,7 @@ func newVaultCreateCommand() *cli.Command { &cli.StringFlag{ Name: "provider", Aliases: []string{"p"}, - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "The provider's address and port (e.g., localhost:8080)", DefaultText: DefaultProviderHost, Destination: &provider, @@ -65,7 +67,7 @@ func newVaultCreateCommand() *cli.Command { }, &cli.Int64Flag{ Name: "cache", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "Time duration (in minutes) that the data will be available in the cache", DefaultText: "0", Destination: &cache, @@ -73,13 +75,13 @@ func newVaultCreateCommand() *cli.Command { }, &cli.StringFlag{ Name: "dburi", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "PostgreSQL connection string (e.g., postgresql://postgres:[PASSWORD]@[HOST]:[PORT]/postgres)", Destination: &dburi, }, &cli.Int64Flag{ Name: "window-size", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "Number of seconds for which WAL updates are buffered before being sent to the provider", DefaultText: fmt.Sprintf("%d", DefaultWindowSize), Destination: &winSize, @@ -162,15 +164,18 @@ func newStreamCommand() *cli.Command { var privateKey string return &cli.Command{ - Name: "stream", - Usage: "Starts a daemon process that streams Postgres changes to a vault", - ArgsUsage: "", - Description: "The daemon will continuously stream database changes (except deletions) to the vault, as long as the daemon is actively running.\n\nExample:\n\nvaults stream --vault my.vault --private-key 0x1234abcd", + Name: "stream", + Usage: "Starts a daemon process that streams Postgres changes to a vault", + ArgsUsage: "", + Description: "The daemon will continuously stream database changes (except deletions) \n" + + "to the vault, as long as the daemon is actively running.\n\n" + + "EXAMPLE:\n\nvaults stream --vault my.vault --private-key 0x1234abcd", + Flags: []cli.Flag{ &cli.StringFlag{ Name: "private-key", Aliases: []string{"k"}, - Category: "REQUIRED", + Category: "REQUIRED:", Usage: "Ethereum wallet private key", Destination: &privateKey, Required: true, @@ -266,15 +271,17 @@ func newWriteCommand() *cli.Command { var timestamp string return &cli.Command{ - Name: "write", - Usage: "Write a Parquet file", - ArgsUsage: "", - Description: "A Parquet file can be pushed directly to the vault, as an alternative to continuous Postgres data streaming.\n\nExample:\n\nvaults write --vault my.vault --private-key 0x1234abcd /path/to/file.parquet", + Name: "write", + Usage: "Write a Parquet file", + ArgsUsage: "", + Description: "A Parquet file can be pushed directly to the vault, as an \n" + + "alternative to continuous Postgres data streaming.\n\n" + + "EXAMPLE:\n\nvaults write --vault my.vault --private-key 0x1234abcd /path/to/file.parquet", Flags: []cli.Flag{ &cli.StringFlag{ Name: "private-key", Aliases: []string{"k"}, - Category: "REQUIRED", + Category: "REQUIRED:", Usage: "Ethereum wallet private key", Destination: &privateKey, Required: true, @@ -282,14 +289,14 @@ func newWriteCommand() *cli.Command { &cli.StringFlag{ Name: "vault", Aliases: []string{"v"}, - Category: "REQUIRED", + Category: "REQUIRED:", Usage: "Vault name", Destination: &vaultName, Required: true, }, &cli.StringFlag{ Name: "timestamp", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "The time the file was created", DefaultText: "current epoch in UTC", Destination: ×tamp, @@ -364,14 +371,16 @@ func newListCommand() *cli.Command { var address, provider, format string return &cli.Command{ - Name: "list", - Usage: "List vaults of a given account", - Description: "Listing vaults will show all vaults that have been created by the provided account's address and logged as either line delimited text or a json array.\n\nExample:\n\nvaults list --account 0x1234abcd --format json", + Name: "list", + Usage: "List vaults of a given account", + Description: "Listing vaults will show all vaults that have been created by the provided \n" + + "account's address and logged as either line delimited text or a json array.\n\n" + + "EXAMPLE:\n\nvaults list --account 0x1234abcd --format json", Flags: []cli.Flag{ &cli.StringFlag{ Name: "account", Aliases: []string{"a"}, - Category: "REQUIRED", + Category: "REQUIRED:", Usage: "Ethereum wallet address", Destination: &address, Required: true, @@ -379,7 +388,7 @@ func newListCommand() *cli.Command { &cli.StringFlag{ Name: "provider", Aliases: []string{"p"}, - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "The provider's address and port (e.g., localhost:8080)", DefaultText: DefaultProviderHost, Destination: &provider, @@ -387,7 +396,7 @@ func newListCommand() *cli.Command { }, &cli.StringFlag{ Name: "format", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "The output format (text or json)", DefaultText: "text", Destination: &format, @@ -430,15 +439,20 @@ func newListEventsCommand() *cli.Command { var limit, offset, latest int return &cli.Command{ - Name: "events", - Usage: "List events of a given vault", - UsageText: "vaults events [command options]", - Description: "Vault events can be filtered by date ranges (unix, ISO 8601 date, or ISO 8601 date & time), returning the event metadata and corresponding CID.\n\nExample:\n\nvaults events --vault my.vault \\\n--limit 10 --offset 3 \\\n--after 2023-09-01 --before 2023-12-01 \\\n--format json", + Name: "events", + Usage: "List events of a given vault", + UsageText: "vaults events [command options]", + Description: "Vault events can be filtered by date ranges (unix, ISO 8601 date,\n" + + "or ISO 8601 date & time), returning the event metadata and \n" + + "corresponding CID.\n\n" + + "EXAMPLE:\n\nvaults events --vault my.vault \\\n" + + "--limit 10 --offset 3 \\\n--after 2023-09-01 --before 2023-12-01 \\\n" + + "--format json", Flags: []cli.Flag{ &cli.StringFlag{ Name: "vault", Aliases: []string{"v"}, - Category: "REQUIRED", + Category: "REQUIRED:", Usage: "Vault name", Destination: &vault, Required: true, @@ -446,7 +460,7 @@ func newListEventsCommand() *cli.Command { &cli.StringFlag{ Name: "provider", Aliases: []string{"p"}, - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "The provider's address and port (e.g., localhost:8080)", DefaultText: DefaultProviderHost, Destination: &provider, @@ -454,7 +468,7 @@ func newListEventsCommand() *cli.Command { }, &cli.IntFlag{ Name: "limit", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "The number of deals to fetch", DefaultText: "10", Destination: &limit, @@ -462,13 +476,13 @@ func newListEventsCommand() *cli.Command { }, &cli.IntFlag{ Name: "latest", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "The latest N deals to fetch", Destination: &latest, }, &cli.IntFlag{ Name: "offset", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "The epoch to start from", DefaultText: "0", Destination: &offset, @@ -476,28 +490,28 @@ func newListEventsCommand() *cli.Command { }, &cli.StringFlag{ Name: "before", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "Filter deals created before this timestamp", Destination: &before, Value: "", }, &cli.StringFlag{ Name: "after", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "Filter deals created after this timestamp", Destination: &after, Value: "", }, &cli.StringFlag{ Name: "at", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "Filter deals created at this timestamp", Destination: &at, Value: "", }, &cli.StringFlag{ Name: "format", - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "The output format (table or json)", DefaultText: "table", Destination: &format, @@ -585,15 +599,17 @@ func newRetrieveCommand() *cli.Command { var output string return &cli.Command{ - Name: "retrieve", - Usage: "Retrieve an event by CID", - ArgsUsage: "", - Description: "Retrieving an event will download the event's CAR file into the current directory, a provided directory path, or to stdout.\n\nExample:\n\nvaults retrieve --output /path/to/dir bafy...", + Name: "retrieve", + Usage: "Retrieve an event by CID", + ArgsUsage: "", + Description: "Retrieving an event will download the event's CAR file into the \n" + + "current directory, a provided directory path, or to stdout.\n\n" + + "EXAMPLE:\n\nvaults retrieve --output /path/to/dir bafy...", Flags: []cli.Flag{ &cli.StringFlag{ Name: "output", Aliases: []string{"o"}, - Category: "OPTIONAL", + Category: "OPTIONAL:", Usage: "Output directory path, or '-' for stdout", DefaultText: "current directory", Destination: &output, @@ -630,7 +646,9 @@ func newRetrieveCommand() *cli.Command { if err != nil { return fmt.Errorf("failed to create temporary file: %s", err) } - defer os.Remove(tmpFile.Name()) + defer func() { + _ = os.Remove(tmpFile.Name()) + }() carWriter = deferred.NewDeferredCarWriterForPath(tmpFile.Name(), []cid.Cid{rootCid}, carOpts...) } else { // Write to the provided path or current directory @@ -689,10 +707,12 @@ func newWalletCommand() *cli.Command { UsageText: "vaults account [arguments...]", Subcommands: []*cli.Command{ { - Name: "create", - Usage: "Creates a new account", - UsageText: "vaults account create ", - Description: "Create an Ethereum-style wallet (secp256k1 key pair) at a provided file path.\n\nExample:\n\nvaults account create /path/to/file", + Name: "create", + Usage: "Creates a new account", + UsageText: "vaults account create ", + Description: "Create an Ethereum-style wallet (secp256k1 key pair) at a \n" + + "provided file path.\n\n" + + "EXAMPLE:\n\nvaults account create /path/to/file", Action: func(cCtx *cli.Context) error { filename := cCtx.Args().Get(0) if filename == "" { @@ -717,10 +737,12 @@ func newWalletCommand() *cli.Command { }, }, { - Name: "address", - Usage: "Print the public key for an account's private key", - UsageText: "vaults account address ", - Description: "The result of the `vaults account create` command will write a private key to a file, and this lets you retrieve that value for use in other commands.\n\nExample:\n\nvaults account address /path/to/file", + Name: "address", + Usage: "Print the public key for an account's private key", + UsageText: "vaults account address ", + Description: "The result of the `vaults account create` command will write a private key to a file, \n" + + "and this lets you retrieve the public key value for use in other commands.\n\n" + + "EXAMPLE:\n\nvaults account address /path/to/file", Action: func(cCtx *cli.Context) error { filename := cCtx.Args().Get(0) if filename == "" { @@ -746,7 +768,10 @@ func newWalletCommand() *cli.Command { func parseVaultName(name string) (ns string, rel string, err error) { match := pubNameRx.FindStringSubmatch(name) if len(match) != 3 { - return "", "", errors.New("vault name must be of the form `namespace.relation_name` using only letters, numbers, and underscores (_), where `namespace` and `relation` do not start with a number") // nolint + return "", "", errors.New( + "vault name must be of the form `namespace.relation_name` using only letters, numbers, " + + "and underscores (_), where `namespace` and `relation` do not start with a number", + ) // nolint } ns = match[1] rel = match[2] diff --git a/cmd/vaults/main.go b/cmd/vaults/main.go index d4dfd9b..1fb98db 100644 --- a/cmd/vaults/main.go +++ b/cmd/vaults/main.go @@ -9,7 +9,12 @@ import ( ) func init() { - cli.VersionFlag = &cli.BoolFlag{Name: "version", Aliases: []string{"V"}, Usage: "show version"} // Enforce uppercase + // Enforce uppercase version shorthand flag + cli.VersionFlag = &cli.BoolFlag{ + Name: "version", + Aliases: []string{"V"}, + Usage: "show version", + } cli.VersionPrinter = func(c *cli.Context) { fmt.Printf("%s\n", c.App.Version) } @@ -18,7 +23,7 @@ func init() { func main() { // migrate v1 config to v2 config migrateConfigV1ToV2() - var version = getVersion() + version := getVersion() cliApp := &cli.App{ Name: "vaults", From 91d733a511e2ded4e22a68806fe5881bf2e690e9 Mon Sep 17 00:00:00 2001 From: Dan Buchholz Date: Tue, 19 Dec 2023 09:14:44 -0800 Subject: [PATCH 11/12] docs: fix incorrect vaults install link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93608a9..6ad5fd9 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Textile Vaults is a secure and verifiable open data platform. The Vaults CLI is You can either install the CLI from the remote source: ```bash -go install github.com/tablelandnetwork/basin-cli/cmd/basin@latest +go install github.com/tablelandnetwork/basin-cli/cmd/vaults@latest ``` Or clone from source and run the Makefile `install` command: From a670d233219be0ddc5d48a469701e3625bd21f83 Mon Sep 17 00:00:00 2001 From: Dan Buchholz Date: Tue, 19 Dec 2023 11:51:23 -0800 Subject: [PATCH 12/12] chore: alter GH version workflow --- .github/workflows/update-version.yml | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/.github/workflows/update-version.yml b/.github/workflows/update-version.yml index 209fd09..9bf00fb 100644 --- a/.github/workflows/update-version.yml +++ b/.github/workflows/update-version.yml @@ -1,10 +1,9 @@ name: Update version file on: - push: - branches: - - main - workflow_dispatch: + release: + types: + - created jobs: update_version: @@ -14,18 +13,13 @@ jobs: with: fetch-depth: 0 - - name: Get latest tag - id: get-tag - run: | - echo "LATEST_TAG=$(git describe --tags $(git rev-list --tags --max-count=1))" >> $GITHUB_OUTPUT - - name: Update version.json run: | echo "{ - \"version\": \"${{steps.get-tag.outputs.LATEST_TAG}}\" + \"version\": \"${{ github.event.release.tag_name }}\" }" > version.json - name: Commit changes uses: stefanzweifel/git-auto-commit-action@v4 with: - commit_message: "chore: update version to ${{steps.get-tag.outputs.LATEST_TAG}}" + commit_message: "chore: update version to ${{ github.event.release.tag_name }}"