Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

version: 2
updates:
- package-ecosystem: "gomod" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

name: CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ '1.26' ]
steps:
- uses: actions/checkout@v3

- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go }}

- name: Run CI
env:
COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
run: make ci
82 changes: 82 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: release

on:
push:
tags:
- "v*"

permissions:
contents: write

jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- goos: linux
goarch: amd64
- goos: linux
goarch: arm64
- goos: darwin
goarch: amd64
- goos: darwin
goarch: arm64
- goos: windows
goarch: amd64
- goos: windows
goarch: arm64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.22.x"
- name: Build release archive
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
VERSION: ${{ github.ref_name }}
shell: bash
run: |
set -euo pipefail
version="${VERSION#v}"
stage="$(mktemp -d)"
trap 'rm -rf "${stage}"' EXIT
suffix=""
extension="tar.gz"
if [ "${GOOS}" = "windows" ]; then
suffix=".exe"
extension="zip"
fi
go build -trimpath -ldflags "-s -w -X github.com/osspkg/gvm/internal/version.Value=${VERSION}" -o "${stage}/gvm${suffix}" ./cmd/gvm
go build -trimpath -ldflags "-s -w -X github.com/osspkg/gvm/internal/version.Value=${VERSION}" -o "${stage}/go${suffix}" ./cmd/go
archive="gvm_${version}_${GOOS}_${GOARCH}.${extension}"
if [ "${GOOS}" = "windows" ]; then
(cd "${stage}" && zip -q "${GITHUB_WORKSPACE}/${archive}" "gvm.exe" "go.exe")
else
tar -czf "${archive}" -C "${stage}" gvm go
fi
sha256sum "${archive}" > "${archive}.sha256"
- uses: actions/upload-artifact@v4
with:
name: release-${{ matrix.goos }}-${{ matrix.goarch }}
path: |
gvm_*

publish:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
path: dist
pattern: release-*
merge-multiple: true
- name: Create checksums
working-directory: dist
run: cat *.sha256 | sort -k2 > checksums.txt
- name: Publish GitHub release
env:
GH_TOKEN: ${{ github.token }}
run: gh release create "${GITHUB_REF_NAME}" dist/* --generate-notes --verify-tag
29 changes: 24 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
.idea
.vscode
.cache
.tmp
.gvmrc
.idea/
.vscode/
.cache/
.tmp/
.venv/
bin/
dist/

.tools/
vendor/
build/
coverage.txt
coverage.out
*.exe
*.exe~
*.dll
*.so
*.dylib
*.db
*.db-journal
*.mmdb
*.test
*.out
.env
68 changes: 68 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
version: "2"

run:
go: "1.26"
timeout: 5m
tests: false
issues-exit-code: 1
modules-download-mode: readonly
allow-parallel-runners: true

issues:
max-issues-per-linter: 0
max-same-issues: 0
new: false
fix: false

output:
formats:
text:
print-linter-name: true
print-issued-lines: true

formatters:
exclusions:
paths:
- vendors/
enable:
- gofmt
- goimports

linters:
settings:
staticcheck:
checks:
- all
- -S1023
- -ST1000
- -ST1003
- -ST1020
gosec:
excludes:
- G104
- G115
- G301
- G304
- G306
- G501
- G505
exclusions:
paths:
- vendors/
default: none
enable:
- govet
- errcheck
- misspell
- gocyclo
- ineffassign
- unparam
- unused
- prealloc
- durationcheck
- staticcheck
- makezero
- nilerr
- errorlint
- bodyclose
- gosec
3 changes: 3 additions & 0 deletions .lic.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
author: "Mikhail Knyazhev <markus621@yandex.com>"
lic_short: "BSD 3-Clause"
lic_file: LICENSE
97 changes: 97 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Agent instructions

## Repository scope

- Work from the repository root.
- This is the Go module `github.com/osspkg/gvm`. The minimum declared Go version is 1.22; CI and lint configuration currently use Go 1.26.
- Keep command entrypoints in `cmd/gvm` and `cmd/go`.
- Keep implementation packages private under `internal/`:
- `internal/app` orchestrates CLI commands.
- `internal/config` parses and writes safe dotenv-style `.gvmrc` files.
- `internal/env` computes the managed runtime environment and PATH.
- `internal/sdk` installs, lists, validates, and removes Go SDKs.
- `internal/venv` manages project virtual environments and tools.
- `internal/release` handles GitHub release archives and updates.
- `internal/progress`, `internal/runner`, and `internal/version` provide shared runtime behavior.
- Treat `README.md`, `install.sh`, `install.ps1`, and `.github/workflows/` as public operational contracts.

## Configuration and safety contracts

- Parse `.gvmrc` as data. Never add shell sourcing, `eval`, command substitution, or executable configuration behavior.
- Preserve unrelated environment entries when changing only `GVM_GO_VERSION`, `GVM_VENV`, or `GVM_TOOLS`.
- When `gvm local` creates a project-local `.gvmrc` without an explicit version, inspect `go.work` first and `go.mod` second, taking the valid `go` directive as `GVM_GO_VERSION`. If both files exist, `go.work` wins; if neither has a valid directive, return an actionable error instead of selecting the system Go implicitly.
- Preserve the resolution order: process environment, nearest local `.gvmrc` from the current directory or its parents, global `$GVM_HOME/.gvmrc`, then defaults. Managed `GOROOT`, `GOPATH`, `GOMODCACHE`, `GOBIN`, and `PATH` must not be overridden by project config.
- Keep SDKs under `$GVM_HOME/.cache/src/go<version>`, global tools under `$GVM_HOME/.cache/bin`, module cache under `$GVM_HOME/.cache/pkg`, and manager binaries under `$GVM_HOME/bin`.
- SDK installation, release updates, and tool installation must stage work safely and clean up temporary files on failure.
- Validate SDK versions before constructing paths. Do not turn user-supplied versions into arbitrary filesystem paths.
- Keep `gvm rm <version>` limited to the requested SDK. Never replace it with a broad recursive deletion or a path-based delete.
- Do not use the real user `GVM_HOME`, shell profiles, or live GitHub releases for tests. Use `t.TempDir()`, injected environments, and fake HTTP servers.

## Code and test conventions

- Use standard Go packages and platform-aware APIs such as `filepath` and `os.PathListSeparator`; do not hard-code Unix path separators in cross-platform code.
- Put tests next to the package they cover in `*_test.go` files. Prefer table-driven tests and temporary directories for filesystem behavior.
- Cover malformed configuration, path traversal, checksum failures, incomplete SDKs, atomic cleanup, PATH ordering, and argument forwarding when changing those areas.
- Keep network tests deterministic with fake HTTP servers. Do not make unit or integration tests depend on the public Go download API or GitHub.
- Update the public README when changing CLI commands, configuration precedence, cache layout, supported platforms, release assets, or installer behavior.
- Avoid committing generated or local output from `bin/`, `dist/`, `.cache/`, `build/`, `coverage.*`, or binaries.

## Development commands

Run commands from the repository root.

For a focused package test:

```sh
go test ./internal/config
go test ./internal/sdk
```

For normal validation:

```sh
go fmt ./...
go test ./...
go vet ./...
git diff --check
```

Before handoff, also run the race suite when the change affects shared state, filesystem lifecycle, process execution, or concurrency:

```sh
go test -race ./...
```

The repository's CI-equivalent target is:

```sh
make ci
```

`make ci` installs `goppy`, runs license setup, linting, tests, and the build pipeline. It may modify generated/license or build outputs; inspect `git status` afterward. The underlying targets are available individually as `make license`, `make lint`, `make tests`, and `make build`.

Build both command binaries locally with:

```sh
go build -o bin/gvm ./cmd/gvm
go build -o bin/go ./cmd/go
```

The release workflow cross-builds these binaries for Linux, macOS, and Windows on amd64 and arm64. When changing release packaging, keep archive names, `checksums.txt`, executable suffixes, and the matrix in `.github/workflows/release.yml` synchronized with the installers and update client.

## Installer and release boundaries

- Keep `install.sh` and `install.ps1` thin and repeatable. They create `GVM_HOME` layout, download a published release, install only `gvm` and `go`, and configure user profiles/environment variables idempotently.
- Test installer syntax with `bash -n install.sh`. Do not execute installers against the real home directory during validation; use an isolated home or inspect the script.
- Changes to GitHub release behavior must preserve SHA-256 verification and atomic replacement of manager binaries without altering installed SDKs.
- Do not run publication, deployment, profile mutation, or release commands merely as validation. These actions require an explicit request.

## Handoff checklist

- Re-read the changed code and documentation.
- Run formatting, focused tests, and the broader checks appropriate to the change.
- Run `go test -race ./...` for lifecycle, process, filesystem, or concurrency changes.
- Run `bash -n install.sh` when the Unix installer changes; use a PowerShell syntax check when the Windows installer changes and the tool is available.
- Run `git diff --check` and inspect `git status` for accidental artifacts.
- Report checks that actually ran and distinguish unavailable platform-specific checks from successful checks.

41 changes: 24 additions & 17 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
MIT License
BSD 3-Clause License

Copyright (c) 2024 OSSPkg Team
Copyright (c) 2024-2026, Mikhail Knyazhev <markus621@yandex.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 changes: 28 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
SHELL=/bin/bash

.PHONY: install
install:
PATH="$$(go env GOROOT)/bin:$$PATH" go install go.osspkg.com/goppy/v3/cmd/goppy@latest
PATH="$$(go env GOROOT)/bin:$$PATH" goppy setup-lib

.PHONY: lint
lint:
PATH="$$(go env GOROOT)/bin:$$PATH" goppy lint

.PHONY: license
license:
PATH="$$(go env GOROOT)/bin:$$PATH" goppy license

.PHONY: build
build:
PATH="$$(go env GOROOT)/bin:$$PATH" goppy build --arch=amd64

.PHONY: tests
tests:
PATH="$$(go env GOROOT)/bin:$$PATH" goppy test

.PHONY: pre-commit
pre-commit: install license lint tests build

.PHONY: ci
ci: pre-commit
Loading
Loading