Developer happiness tool (also used for onboarding and project-documentation-as-code)
MIT License
A CLI tool for improving the developer experience.
Codebase: https://gitlab.com/zephinzer/dev Mirror: https://github.com/zephinzer/dev
Please file bugs/issues/etc on the GITLAB repository at https://gitlab.com/zephinzer/dev/-/issues
Onboarding
Development
Table of Contents
Releases are available on Github at https://github.com/zephinzer/dev/releases.
You can also install it via go install
:
go install github.com/zephinzer/dev
Clone this repository and run make install
:
git clone [email protected]:zephinzer/dev.git;
cd dev;
make install;
Test the installation works by running dev -v
.
dev
loads its configuration from the home directory and the current working directory from which dev
is run. A file is considered a configuration file if it matches a pattern of ^.dev(.labels)+.yaml$
. Some examples of valid configuration file names are:
.dev.yaml
.dev.github.yaml
.dev.gitlab.yourdomain.com.yaml
.dev.some1elses.yaml
To automate this with some degree of sanity, some strongly-opinionated assumptions are made:
<hostname>/<username>/<path-to-repo>
. For example, this repo will be stored at /home/${USER}/github.com/zephinzer/dev
Repositories are configured using the repositories
root level property in the configuration file as such:
# ...
repositories:
- description: working repository for the dev tool
name: dev (do work here)
url: [email protected]/zephinzer/dev.git
workspaces: [productivity, development]
- description: public repository for the dev tool
name: dev (install from here)
url: [email protected]/zephinzer/dev.git
workspaces: [productivity, production]
# ...
The structure for each repository item can be found at ./pkg/repository/repository.go
. In summary the fields are:
Field | Required | Default | Description |
---|---|---|---|
description |
No | "" |
An arbitrary description displayed in dev metadata only |
name |
No | "" |
An arbitrary name displayed in dev metadata only |
path |
No | ~/${HOSTNAME}/${REPO_PATH} |
The path on your local machine to put this repository |
url |
Yes | - |
The URL to this repository. dev will always convert this to an SSH clone URL |
workspaces |
No | [] |
A list of workspace names that this repository should belong to |
To verify that all repositories have been installed locally, use:
dev check repositories;
If a repository is listed in the configuration but is not available locally, it's possible to clone it using this tool using:
dev install repos;
Known issue #1: You won't be able to clone a bare repository.
Known issue #2: If you have a long list of repositories, some might fail because too many requests are being made to the server.
If you've defined the workspaces
property for your repositories, you can export repositories related to a workspace by using:
# get the workspace ${WORKSPACE_NAME}
dev get workspace ${WORKSPACE_NAME};
Use the --output-directory
/-o
flag to export it directly to the current directory (a file at ./${WORKSPACE_NAME}.code-workspace
will be created):
# export to the current directory
dev get workspace ${WORKSPACE_NAME} --output-directory .;
To export it directly to /some/path/at
(a file at /some/path/at/${WORKSPACE_NAME}.code-workspace
will be created):
# export to the directory at /some/path/at
dev get workspace ${WORKSPACE_NAME} -o /some/path/at;
If the file already exists, dev
will complain. Use the --overwrite
/-O
flag to tell it to overwrite the file:
# export to the directory at /some/path/at, overwriting it if the target file exists
dev get workspace ${WORKSPACE_NAME} -o /some/path/at --overwrite;
To change the formatting of the workspace, use the --format
/-f
flag:
dev get workspace ${WORKSPACE_NAME} -f vscode;
The following workspace formats are supported:
vscode
)The software management feature allows developers to check whether required software have been installed and if not, to install them.
Software is configured using the root level softwares
property in the configuration file as such:
# ...
softwares:
- name: brew
description: used for system dependency installations
platforms: [macos]
check:
command: [brew, --version]
stdout: ^Homebrew
install:
link: https://brew.sh/
- name: node
description: used for the primary projects
check:
command: ["node", "-v"]
stdout: ^v\d+\.\d+\.\d+$
install:
link: https://github.com/nvm-sh/nvm#installing-and-updating
- name: terraform
description: used for bringing up our infrastructure
check:
command: ["terraform", "version"]
stdout: ^Terraform v\d+\.\d+\.\d+$
install:
link: https://www.terraform.io/downloads.html
# ...
The structure for each software item is detailed in the ./pkg/software
directory and a summary follows:
Field | Required | Default | Description |
---|---|---|---|
name |
No | "" |
An arbitrary name displayed in dev outputs when metadata is required |
check |
Yes | - | Declarative instructions describing how to check for the software's presence |
check.command |
Yes | - | A list of strings that form the command to check for the software. For example, if you run go version in your CLI to check for Go, the list will look like ["go", "version"]
|
check.stdout |
No | "" |
A regex-compatible string to match with the command's output on stdout
|
check.stderr |
No | "" |
A regex-compatible string to match with the command's output on stderr
|
check.exitCode |
No | 0 |
An integer exit code to match with the command's exit code |
description |
No | "" |
An arbitrary description of how the software is used/why it's needed displayed in dev outputs when metadata is required |
install |
No | - | Declarative instructions describing how to install the software if it's not found |
install.link |
No | "" |
A link to direct users to if the software is not found installed on the current machine |
platforms |
No | - | A list of platform strings that define which operating systems this check is valid for. Valid lists are subsets of {linux, windows, macos} . When not specified, does not check for platform compatibility. |
To run checks on the software available locally:
dev check software;
Traditionally, teams/organisations typically have internal networks (intranets) for developers to access where privately owned code is pulled from/pushed to. This feature assists the developer to see what networks exist and to verify they have access to the networks they should have access to.
Networks are configured using the root level networks
property in the configuration file as such:
# ...
networks:
- name: internet
check:
url: https://google.com
- name: internal-vpn
registrationUrl: https://openvpn.internal.com
check:
url: https://gitlab.internal.com
# ...
The structure of each network can be found in the ./pkg/network
directory, a summary is as follows:
Field | Required | Default | Description |
---|---|---|---|
name |
No | "" |
An arbitrary name for the network to be displayed in dev metadata when required |
registrationUrl |
No | "" |
A URL for users to request access to this network if applicable |
check |
Yes | - | Declarative instructions on what to check for |
check.url |
Yes | - | A URL to ping that should be accessible if network connectivity to this network has been established |
check.method |
No | "GET" |
The HTTP method to use to ping the provided check.url
|
check.statusCode |
No | ^2\d\d$ |
The expected HTTP status code of the response to the ping |
check.headers |
No | {} |
A dictionary of expected headers |
check.responseBody |
No | "" |
A regex-compatible string that the response body should be expected to match with. Does not apply if not specified/an empty string is provided |
To run a check on your required network connectivity:
dev check networks;
This feature assists with awareness of team resources by providing a list of resources that a developer can use to explore the team's resources.
The link directory is configured using the root level links
property in the configuration file as such:
links:
- label: official source-of-truth release repository
categories: [scm]
url: https://gitlab.com/zephinzer/dev
- label: dev tool build pipeline
categories: [cicd]
url: https://gitlab.com/zephinzer/dev/pipelines
- label: dev tool release pipeline
categories: [cicd, release]
url: https://travis-ci.org/github/zephinzer/dev/
- label: dev tool code quality checks
categories: [cicd]
url: https://codeclimate.com/github/zephinzer/dev
- label: dev tool releases
categories: [cicd, release]
url: https://github.com/zephinzer/dev/releases
The structure for each link object can be found in the ./internal/link
directory and a summary follows.
Field | Required | Default | Description |
---|---|---|---|
label |
No | "" |
An arbitrary label for this link to be included in link metadata |
categories |
No | [] |
A hashtag-based way of searching to be included in link metadata |
url |
Yes | - | The URL to open if this link is selected |
To activate the link directory from the terminal, run:
dev goto;
Being able to create new repositories based on a pre-defined list of templates makes it easy to do the right thing for developers by providing an easy way to kickstart a new service in a organisation/team-approved manner.
Repository templates can be configured using the configuration key at dev.repository/.templates
which should be an array of template objects as such:
# ...
dev:
# ...
repository:
templates:
- name: test for bare repository
url: https://github.com/zephinzer/template-bare
- name: golang repository
url: https://gitlab.com/zephinzer/template-go-package
# ...
# ...
# ...
The structure for each template object can be found at ./internal/config/dev.go
and a summary follows.
Field | Required | Default | Description |
---|---|---|---|
name |
NO | "" |
An arbitrary label used to identify this repository template |
url |
YES | - | One of the template repository's HTTP URL, HTTPS clone URL, or SSH clone URL |
dev init repo ./path/to/new/repo;
## output:
## > choose a repository template to use
## > 1. ...
## > 2. ...
##
## > your selection (enter 0 to skip):
The Github integration is not refined for use yet, try it at your own risk!
Retrieve your accessToken
by generating a new personal access token from https://github.com/settings/tokens/new. You'll need the following scopes:
An example follows of a configuration:
# ...
platforms:
# ...
github:
accounts:
# ...
- name: personal github
description: my own stuff
accessToken: ...
public: false
# ...
# ...
dev get github account;
dev get github notifs;
The Gitlab integration is not refined for use yet, try it at your own risk!
Retrieve your accessToken
by generating a new personal access token from https://gitlab.com/profile/personal_access_tokens. You'll need the following scopes:
If you're using an on-premise Gitlab, change
gitlab.com
to your Gitlab's hostname
dev get gitlab account;
dev get gitlab notifs;
Retrieve your accessToken
from https://www.pivotaltracker.com/profile and enter it as the accessToken
as a property at platforms.pivotaltracker
Example:
# ...
platforms:
# ...
pivotaltracker:
accessToken: ...
# ...
https://www.pivotaltracker.com/n/projects/1234567
, the project ID is 1234567
)platforms.pivotaltracker.projects
. The array item has a structure containing 3 properties:
name
: an arbitrary label you can use to identify the projectprojectID
the project ID as retrieved from above as a string (surround with "double quotes"
to be sure)Example:
# ...
platforms:
# ...
pivotaltracker:
accessToken: ...
projects:
- name: (some arbitrary name you use to identify your project)
projectID: "1234567"
# ... other projects ...
# ...
dev get pivotal account;
dev get pivotal notifs;
The Trello integration is not refined for use yet, try it at your own risk!
accessKey
from https://trello.com/app-key.accessToken
from the link to Token from the above linkaccessKey
and accessToken
as properties at platforms.trello
Example:
# ...
platforms:
# ...
trello:
accessKey: ...
accessToken: ...
# ...
The boards
property at platforms.trello.boards
takes in an array of board shortlinks. You can retrieve a board's shortlink by visiting the board in your browser and extracting it from the URL.
Assuming your board can be found at the URL https://trello.com/b/xxxxxxxx/lorem-ipsum
, the board shortlink is xxxxxxxx
.
Example:
# ...
platforms:
# ...
trello:
# ... api keys ...
boards:
- xxxxxxxx
# ...
dev get trello account;
dev get trello notifs;
dev
is able to notify you via Telegram if the integration has been set up.
/start
if you haven't talked to it before./newbot
command to create a new bot. Give your bot a logical name (eg. "My Notification Bot") followed by a bot username (eg. my_notification_bot
).1234556789:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
, add the access token at the property dev.client.notifications.telegram.token
.dev init telegram notifs
dev
's logsdev.client.notifications.telegram.id
as a string (surround the ID with quotes)dev debug notifications
and confirm you receive a notification in TelegramYour configuration should look like:
# ... other properties ...
dev:
# ... other properties ...
notifications:
telegram:
token: 1234556789:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
id: "987654321"
# ... other properties ...
All output that's prefixed with a log level is being sent to stderr
.
To display just stderr
output, append 2>/dev/null
to your command.
All output that appears as-is without a log level is being sent to stdout
To display just stdout
output, append 1>/dev/null
to your command.
Exit codes are bitmasks of error types which are docuemnted at ./internal/constants/exit_codes.go
.
Type | Value | Indication |
---|---|---|
OK | 0 |
Success |
System | 1 |
An error occurred at the system level |
User | 2 |
An error occurred because of user actions |
Input | 4 |
An error occurred because of user input |
Configuration | 8 |
An error occurred because of the consumed configuration |
Application | 16 |
There's likely a bug |
Validation | 32 |
Some expected values seem off |
Number of errors | 128-255 |
When such an exit code is encountered it's a count of failed iterations from a requested operation, take $((256 - $?)) to get the number of errors from the operation |
Two global flags are made available to improve debuggability by increasing the amount of logs.
--debug
: display DEBUG level logs (this prints start and end messages, and input/output values)--trace
: display TRACE level logs (this prints all sorts of nonsense but could be useful sometimes)master
, the repository will be synced to Github and will be automatically releasedmake deps
to retrieve Go dependenciesmake setup_build
to retrieve system dependenciesmake build
to run a test build with cachingmake build_production
to run a full non-cached buildmake build_static
to run a test build with static linking and cachingmake build_static_production
to run a full non-cached build with static linkingmake test
to run Go test suitesmake compress
to test whether compression worksmake image
to test the Docker image buildmake test_image
to run tests on the built Docker imageVersion | Breaking | Description |
---|---|---|
v0.1.24 | NO | Added error handling for triggering of dev add - commands without an existing configuration file |
v0.1.18 | NO | Added command to initialising a repository using a template (dev init repo <path> ) |
v0.1.7 | NO | Added descriptions for dev check software
|
v0.1.6 | NO | Made repository selection deterministic when using dev add repo
|
v0.1.4 | NO | Removal of unused fields using the omitempty struct tag for networks, softwares, links, and repositories, fixed bug where the dev configuration wasn't being correctly merged, refined Pivotal Tracker notification messages |
v0.1.0 | YES | Changing of configuration filename from dev.yaml to .dev.yaml
|
Code is licensed under the MIT license (click to view the full text).