├── .github ├── CODEOWNERS ├── release.yml └── workflows │ ├── tagpr.yml │ ├── release.yml │ └── mega-linter.yml ├── .gitignore ├── img ├── demo.gif └── demo.tape ├── .markdownlint.json ├── .editorconfig ├── var ├── top │ └── Makefile └── side │ └── Makefile ├── .jscpd.json ├── .mega-linter.yml ├── .cspell.json ├── .ecrc ├── Taskfile.yaml ├── Taskfile.yml ├── revive.toml ├── cmd ├── root_test.go ├── version.go ├── taskfile_test.go ├── taskfile.go ├── ui_test.go ├── makefile_test.go ├── makefile.go ├── ui.go └── root.go ├── Makefile ├── LICENSE ├── .goreleaser.yml ├── main.go ├── go.mod ├── .tagpr ├── CHANGELOG.md ├── README.md └── go.sum /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @orangekame3 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | megalinter-reports/ 3 | -------------------------------------------------------------------------------- /img/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangekame3/mk/HEAD/img/demo.gif -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - tagpr 5 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD033": false, 3 | "MD041": false, 4 | "MD013": false 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | insert_final_newline = true 6 | 7 | [*.md] 8 | trim_trailing_whitespace = false 9 | -------------------------------------------------------------------------------- /var/top/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := bash 2 | .SHELLFLAGS := -eu -o pipefail -c 3 | .DEFAULT_GOAL := help 4 | 5 | .PHONY: test fmt 6 | 7 | ## Run tests 8 | test: 9 | go test ./... 10 | 11 | ## Format source code 12 | fmt: 13 | go fmt ./... 14 | -------------------------------------------------------------------------------- /var/side/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := bash 2 | .SHELLFLAGS := -eu -o pipefail -c 3 | .DEFAULT_GOAL := help 4 | 5 | .PHONY: test fmt 6 | 7 | test: ## Run tests 8 | export MK_DESC_POSITION=side && go test ./... 9 | 10 | fmt: ## Format source code 11 | export MK_DESC_POSITION=side && go fmt ./... 12 | -------------------------------------------------------------------------------- /.jscpd.json: -------------------------------------------------------------------------------- 1 | { 2 | "threshold": 0, 3 | "reporters": ["html", "markdown"], 4 | "ignore": [ 5 | "**/node_modules/**", 6 | "**/.git/**", 7 | "**/.rbenv/**", 8 | "**/.venv/**", 9 | "**/*cache*/**", 10 | "**/.github/**", 11 | "**/.idea/**", 12 | "**/report/**", 13 | "**/*.svg" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/tagpr.yml: -------------------------------------------------------------------------------- 1 | name: tagpr 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | tagpr: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | with: 12 | token: ${{ secrets.GH_PAT }} 13 | - uses: Songmu/tagpr@main 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GH_PAT }} 16 | -------------------------------------------------------------------------------- /.mega-linter.yml: -------------------------------------------------------------------------------- 1 | # Configuration file for MegaLinter 2 | # See all available variables at https://megalinter.io/configuration/ and in linters documentation 3 | 4 | APPLY_FIXES: all 5 | ENABLE_LINTERS: 6 | - GO_REVIVE 7 | - EDITORCONFIG_EDITORCONFIG_CHECKER 8 | - MARKDOWN_MARKDOWNLINT 9 | - BASH_SHELLCHECK 10 | SHOW_ELAPSED_TIME: true 11 | FILEIO_REPORTER: false 12 | -------------------------------------------------------------------------------- /.cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePaths": [ 3 | "**/node_modules/**", 4 | "**/vscode-extension/**", 5 | "**/.git/**", 6 | "**/.pnpm-lock.json", 7 | ".vscode", 8 | "megalinter", 9 | "package-lock.json", 10 | "report" 11 | ], 12 | "language": "en", 13 | "noConfigSearch": true, 14 | "words": ["megalinter", "oxsecurity"], 15 | "version": "0.2" 16 | } 17 | -------------------------------------------------------------------------------- /.ecrc: -------------------------------------------------------------------------------- 1 | { 2 | "Verbose": false, 3 | "Debug": false, 4 | "IgnoreDefaults": false, 5 | "SpacesAftertabs": false, 6 | "NoColor": false, 7 | "exclude": [ 8 | "volume" 9 | ], 10 | "AllowedContentTypes": [], 11 | "PassedFiles": [], 12 | "Disable": { 13 | "EndOfLine": false, 14 | "Indentation": false, 15 | "InsertFinalNewline": false, 16 | "TrimTrailingWhitespace": false, 17 | "IndentSize": false, 18 | "MaxLineLength": false 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Taskfile.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | tasks: 4 | lint: 5 | desc: "Lint the code for Taskfile" 6 | cmds: 7 | - npx mega-linter-runner --flavor go 8 | 9 | fmt: 10 | desc: "Format the code for Taskfile" 11 | cmds: 12 | - go fmt ./... 13 | 14 | test: 15 | desc: "Run the tests for Taskfile" 16 | cmds: 17 | - go clean -testcache 18 | - | 19 | go test -v ./... && echo -e "\033[32mOK\033[0m" || echo -e "\033[31mERROR\033[0m" 20 | 21 | hello: 22 | desc: "Hello World for Taskfile" 23 | cmds: 24 | - echo "Hello World" 25 | -------------------------------------------------------------------------------- /Taskfile.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | tasks: 4 | lint: 5 | desc: "Lint the code for Taskfile" 6 | cmds: 7 | - npx mega-linter-runner --flavor go 8 | 9 | fmt: 10 | desc: "Format the code for Taskfile" 11 | cmds: 12 | - go fmt ./... 13 | 14 | test: 15 | desc: "Run the tests for Taskfile" 16 | cmds: 17 | - go clean -testcache 18 | - | 19 | go test -v ./... && echo -e "\033[32mOK\033[0m" || echo -e "\033[31mERROR\033[0m" 20 | 21 | hello: 22 | desc: "Hello World for Taskfile" 23 | cmds: 24 | - echo "Hello World" 25 | -------------------------------------------------------------------------------- /revive.toml: -------------------------------------------------------------------------------- 1 | ignoreGeneratedHeader = false 2 | severity = "warning" 3 | confidence = 0.8 4 | errorCode = 0 5 | warningCode = 0 6 | 7 | [rule.blank-imports] 8 | [rule.context-as-argument] 9 | [rule.context-keys-type] 10 | [rule.dot-imports] 11 | [rule.error-return] 12 | [rule.error-strings] 13 | [rule.error-naming] 14 | [rule.exported] 15 | [rule.if-return] 16 | [rule.increment-decrement] 17 | [rule.var-naming] 18 | [rule.var-declaration] 19 | [rule.package-comments] 20 | [rule.range] 21 | [rule.receiver-naming] 22 | [rule.time-naming] 23 | [rule.unexported-return] 24 | [rule.indent-error-flow] 25 | [rule.errorf] 26 | [rule.superfluous-else] 27 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: write 13 | steps: 14 | # チェックアウト 15 | - uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 18 | 19 | # Go をセットアップ 20 | - uses: actions/setup-go@v3 21 | with: 22 | go-version-file: go.mod 23 | cache: true 24 | 25 | # リリース 26 | - uses: goreleaser/goreleaser-action@v4 27 | with: 28 | args: release --clean 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }} 32 | -------------------------------------------------------------------------------- /cmd/root_test.go: -------------------------------------------------------------------------------- 1 | // Package cmd is a root command. 2 | package cmd 3 | 4 | import ( 5 | "testing" 6 | ) 7 | 8 | func TestRootCmd(t *testing.T) { 9 | tests := []struct { 10 | name string 11 | expected string 12 | actual string 13 | }{ 14 | {name: "Use", expected: "mk", actual: rootCmd.Use}, 15 | {name: "Short", expected: "mk is a CLI tool for executing make commands interactively.", actual: rootCmd.Short}, 16 | {name: "Long", expected: "mk is a CLI tool for executing make commands interactively.", actual: rootCmd.Long}, 17 | } 18 | 19 | for _, tt := range tests { 20 | t.Run(tt.name, func(t *testing.T) { 21 | if tt.expected != tt.actual { 22 | t.Errorf("Expected '%s', got '%s'", tt.expected, tt.actual) 23 | } 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := bash 2 | .SHELLFLAGS := -eu -o pipefail -c 3 | .DEFAULT_GOAL := help 4 | 5 | .PHONY: lint fmt test test-side lint-side fmt-side hello 6 | 7 | ## Lint the code 8 | lint: 9 | @npx mega-linter-runner --flavor go 10 | 11 | lin-side: ## Lint the code exp. MK_DESC_POSITION=side 12 | @npx mega-linter-runner --flavor go 13 | 14 | ## Format the code 15 | fmt: 16 | @go fmt ./... 17 | 18 | fmt-side: ## Format the code exp. MK_DESC_POSITION=side 19 | @go fmt ./... 20 | 21 | 22 | ## Run the tests 23 | test: 24 | @go clean -testcache 25 | @go test -v ./... && echo -e "\033[32mOK\033[0m" || echo -e "\033[31mERROR\033[0m"; 26 | 27 | test-side: ## Run the tests exp. MK_DESC_POSITION=side 28 | @go clean -testcache 29 | @go test -v ./... && echo -e "\033[32mOK\033[0m" || echo -e "\033[31mERROR\033[0m"; 30 | 31 | ## Hello World 32 | hello: 33 | @echo "Hello World" 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2024 Takafumi Miyanaga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # .goreleaser.yml 2 | version: 2 3 | # Before section 4 | before: 5 | hooks: 6 | # Ensure go modules are tidy 7 | - go mod tidy 8 | # Optionally, run go generate if needed 9 | - go generate ./... 10 | # Builds section 11 | builds: 12 | - env: 13 | - CGO_ENABLED=0 14 | goos: 15 | - linux 16 | - windows 17 | - darwin 18 | # Add additional build configurations as needed 19 | # Archives section 20 | archives: 21 | - id: tar_gz 22 | format: tar.gz 23 | # Customize archive name based on OS and Arch 24 | name_template: >- 25 | {{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }} 26 | - id: zip 27 | format: zip 28 | # Format override for Windows 29 | name_template: >- 30 | {{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }} 31 | # Checksum section 32 | checksum: 33 | name_template: "checksums.txt" 34 | # Snapshot section 35 | snapshot: 36 | name_template: "{{ incpatch .Version }}-next" 37 | # Changelog section 38 | changelog: 39 | sort: asc 40 | filters: 41 | exclude: 42 | - "^docs:" 43 | - "^test:" 44 | # Brews section (if applicable) 45 | brews: 46 | - 47 | ids: 48 | - tar_gz 49 | repository: 50 | owner: orangekame3 51 | name: homebrew-tap 52 | token: "{{ .Env.TAP_GITHUB_TOKEN }}" 53 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 Takafumi Miyanaga 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | package main 23 | 24 | import ( 25 | "time" 26 | 27 | "github.com/orangekame3/mk/cmd" 28 | ) 29 | 30 | // main is the entry point of this application. 31 | func main() { 32 | cmd.SetVersionInfo(cmd.Version, time.Now().String()) 33 | cmd.Execute() 34 | } 35 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | // Package cmd is a root command. 2 | /* 3 | Copyright © 2024 Takafumi Miyanaga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | package cmd 24 | 25 | import "fmt" 26 | 27 | // Version is a version of this application. 28 | const Version = "0.0.16" 29 | 30 | // SetVersionInfo sets version and date to rootCmd 31 | func SetVersionInfo(version, date string) { 32 | rootCmd.Version = fmt.Sprintf("%s (Built on %s)", version, date) 33 | } 34 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/orangekame3/mk 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/charmbracelet/bubbles v0.18.0 7 | github.com/charmbracelet/bubbletea v0.26.6 8 | github.com/spf13/cobra v1.7.0 9 | gopkg.in/yaml.v2 v2.4.0 10 | ) 11 | 12 | require ( 13 | github.com/atotto/clipboard v0.1.4 // indirect 14 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 15 | github.com/charmbracelet/lipgloss v0.9.1 // indirect 16 | github.com/charmbracelet/x/ansi v0.1.2 // indirect 17 | github.com/charmbracelet/x/input v0.1.0 // indirect 18 | github.com/charmbracelet/x/term v0.1.1 // indirect 19 | github.com/charmbracelet/x/windows v0.1.0 // indirect 20 | github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect 21 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 22 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 23 | github.com/mattn/go-isatty v0.0.18 // indirect 24 | github.com/mattn/go-localereader v0.0.1 // indirect 25 | github.com/mattn/go-runewidth v0.0.15 // indirect 26 | github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect 27 | github.com/muesli/cancelreader v0.2.2 // indirect 28 | github.com/muesli/reflow v0.3.0 // indirect 29 | github.com/muesli/termenv v0.15.2 // indirect 30 | github.com/rivo/uniseg v0.4.7 // indirect 31 | github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect 32 | github.com/spf13/pflag v1.0.5 // indirect 33 | github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect 34 | golang.org/x/sync v0.7.0 // indirect 35 | golang.org/x/sys v0.21.0 // indirect 36 | golang.org/x/text v0.3.8 // indirect 37 | ) 38 | -------------------------------------------------------------------------------- /cmd/taskfile_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | ) 7 | 8 | func TestParseTaskfile(t *testing.T) { 9 | // Setup: create a temporary Taskfile 10 | testData := ` 11 | version: '3' 12 | 13 | tasks: 14 | lint: 15 | desc: Lint the code 16 | cmds: 17 | - npx mega-linter-runner --flavor go 18 | 19 | fmt: 20 | desc: Format the code 21 | cmds: 22 | - go fmt ./... 23 | 24 | test: 25 | desc: Run the tests 26 | cmds: 27 | - go clean -testcache 28 | - go test -v ./... 29 | - echo -e "\033[32mOK\033[0m" || echo -e "\033[31mERROR\033[0m" 30 | ` 31 | tempFile, err := os.CreateTemp("", "Taskfile.yml") 32 | if err != nil { 33 | t.Fatalf("Failed to create temporary file: %v", err) 34 | } 35 | defer os.Remove(tempFile.Name()) 36 | 37 | _, err = tempFile.Write([]byte(testData)) 38 | if err != nil { 39 | t.Fatalf("Failed to write to temporary file: %v", err) 40 | } 41 | tempFile.Close() 42 | 43 | // Execute the function under test 44 | commands, err := parseTaskfile(tempFile.Name()) 45 | if err != nil { 46 | t.Fatalf("parseTaskfile failed: %v", err) 47 | } 48 | 49 | // Verify the results 50 | expectedCommands := []MakeCommand{ 51 | {Name: "lint", Description: "Lint the code", Command: "lint"}, 52 | {Name: "fmt", Description: "Format the code", Command: "fmt"}, 53 | {Name: "test", Description: "Run the tests", Command: "test"}, 54 | } 55 | 56 | if len(commands) != len(expectedCommands) { 57 | t.Fatalf("Expected %d commands, but got %d", len(expectedCommands), len(commands)) 58 | } 59 | 60 | for i, cmd := range commands { 61 | if cmd.Name != expectedCommands[i].Name || cmd.Description != expectedCommands[i].Description || cmd.Command != expectedCommands[i].Command { 62 | t.Errorf("Command %d: expected %+v, but got %+v", i, expectedCommands[i], cmd) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /.tagpr: -------------------------------------------------------------------------------- 1 | # config file for the tagpr in git config format 2 | # The tagpr generates the initial configuration, which you can rewrite to suit your environment. 3 | # CONFIGURATIONS: 4 | # tagpr.releaseBranch 5 | # Generally, it is "main." It is the branch for releases. The tagpr tracks this branch, 6 | # creates or updates a pull request as a release candidate, or tags when they are merged. 7 | # 8 | # tagpr.versionFile 9 | # Versioning file containing the semantic version needed to be updated at release. 10 | # It will be synchronized with the "git tag". 11 | # Often this is a meta-information file such as gemspec, setup.cfg, package.json, etc. 12 | # Sometimes the source code file, such as version.go or Bar.pm, is used. 13 | # If you do not want to use versioning files but only git tags, specify the "-" string here. 14 | # You can specify multiple version files by comma separated strings. 15 | # 16 | # tagpr.vPrefix 17 | # Flag whether or not v-prefix is added to semver when git tagging. (e.g. v1.2.3 if true) 18 | # This is only a tagging convention, not how it is described in the version file. 19 | # 20 | # tagpr.changelog (Optional) 21 | # Flag whether or not changelog is added or changed during the release. 22 | # 23 | # tagpr.command (Optional) 24 | # Command to change files just before release. 25 | # 26 | # tagpr.template (Optional) 27 | # Pull request template in go template format 28 | # 29 | # tagpr.release (Optional) 30 | # GitHub Release creation behavior after tagging [true, draft, false] 31 | # If this value is not set, the release is to be created. 32 | # 33 | # tagpr.majorLabels (Optional) 34 | # Label of major update targets. Default is [major] 35 | # 36 | # tagpr.minorLabels (Optional) 37 | # Label of minor update targets. Default is [minor] 38 | # 39 | [tagpr] 40 | vPrefix = true 41 | releaseBranch = main 42 | versionFile = cmd/version.go 43 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [v0.0.16](https://github.com/orangekame3/mk/compare/v0.0.15...v0.0.16) - 2024-10-28 4 | 5 | - adopot yaml by @orangekame3 in 6 | 7 | ## [v0.0.15](https://github.com/orangekame3/mk/compare/v0.0.14...v0.0.15) - 2024-10-27 8 | 9 | - call form current dir by @orangekame3 in 10 | 11 | ## [v0.0.14](https://github.com/orangekame3/mk/compare/v0.0.13...v0.0.14) - 2024-07-01 12 | 13 | - [Fix]: update README about Taskfile by @orangekame3 in 14 | 15 | ## [v0.0.13](https://github.com/orangekame3/mk/compare/v0.0.12...v0.0.13) - 2024-06-30 16 | 17 | - chore: Update root command to support Taskfile and Makefile by @orangekame3 in 18 | 19 | ## [v0.0.12](https://github.com/orangekame3/mk/compare/v0.0.11...v0.0.12) - 2024-06-29 20 | 21 | - update README by @orangekame3 in 22 | 23 | ## [v0.0.11](https://github.com/orangekame3/mk/compare/v0.0.10...v0.0.11) - 2024-06-29 24 | 25 | - feat: Add support for lazy loading images in UI by @orangekame3 in 26 | 27 | ## [v0.0.10](https://github.com/orangekame3/mk/compare/v0.0.9...v0.0.10) - 2024-06-29 28 | 29 | - feat: Add support for downloading Makefile from URL by @orangekame3 in 30 | 31 | ## [v0.0.9](https://github.com/orangekame3/mk/compare/v0.0.8...v0.0.9) - 2024-06-28 32 | 33 | - [bug]:fix go.mod by @orangekame3 in 34 | 35 | ## [v0.0.8](https://github.com/orangekame3/mk/compare/v0.0.7...v0.0.8) - 2024-06-27 36 | 37 | ## [v0.0.7](https://github.com/orangekame3/mk/compare/v0.0.6...v0.0.7) - 2024-06-27 38 | 39 | ## [v0.0.6](https://github.com/orangekame3/mk/compare/v0.0.5...v0.0.6) - 2024-06-26 40 | 41 | ## [v0.0.5](https://github.com/orangekame3/mk/compare/v0.0.4...v0.0.5) - 2024-06-26 42 | 43 | ## [v0.0.4](https://github.com/orangekame3/mk/compare/v0.0.3...v0.0.4) - 2024-06-26 44 | 45 | ## [v0.0.3](https://github.com/orangekame3/mk/compare/v0.0.2...v0.0.3) - 2024-06-26 46 | 47 | ## [v0.0.2](https://github.com/orangekame3/mk/compare/v0.0.1...v0.0.2) - 2024-06-26 48 | 49 | ## [v0.0.1](https://github.com/orangekame3/mk/commits/v0.0.1) - 2024-06-26 50 | -------------------------------------------------------------------------------- /cmd/taskfile.go: -------------------------------------------------------------------------------- 1 | // Package cmd is a root command. 2 | /* 3 | Copyright © 2024 Takafumi Miyanaga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | package cmd 24 | 25 | import ( 26 | "fmt" 27 | "os" 28 | 29 | "gopkg.in/yaml.v2" 30 | ) 31 | 32 | // Task represents a single task in the Taskfile. 33 | type Task struct { 34 | Desc string `yaml:"desc"` 35 | Cmds []string `yaml:"cmds"` 36 | } 37 | 38 | // Taskfile represents the structure of the Taskfile.yml. 39 | type Taskfile struct { 40 | Version string `yaml:"version"` 41 | Tasks map[string]Task `yaml:"tasks"` 42 | } 43 | 44 | // parseTaskfile parses the Taskfile and returns a list of MakeCommand. 45 | func parseTaskfile(filepath string) ([]MakeCommand, error) { 46 | data, err := os.ReadFile(filepath) 47 | if err != nil { 48 | return nil, fmt.Errorf("failed to read Taskfile.yml: %v", err) 49 | } 50 | 51 | var taskfile Taskfile 52 | err = yaml.Unmarshal(data, &taskfile) 53 | if err != nil { 54 | return nil, fmt.Errorf("failed to parse Taskfile.yml: %v", err) 55 | } 56 | 57 | var commands []MakeCommand 58 | for name, task := range taskfile.Tasks { 59 | commands = append(commands, MakeCommand{ 60 | Name: name, 61 | Description: task.Desc, 62 | Command: name, 63 | }) 64 | } 65 | 66 | return commands, nil 67 | } 68 | -------------------------------------------------------------------------------- /cmd/ui_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "os/exec" 6 | "testing" 7 | ) 8 | 9 | func TestInitialModel(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | commands []MakeCommand 13 | }{ 14 | { 15 | name: "Single Command", 16 | commands: []MakeCommand{ 17 | {Name: "build", Description: "Build the project", Command: "build: # Build the project"}, 18 | }, 19 | }, 20 | { 21 | name: "Multiple Commands", 22 | commands: []MakeCommand{ 23 | {Name: "build", Description: "Build the project", Command: "build: # Build the project"}, 24 | {Name: "test", Description: "Run tests", Command: "test: # Run tests"}, 25 | {Name: "deploy", Description: "Deploy the project", Command: "deploy: # Deploy the project"}, 26 | }, 27 | }, 28 | } 29 | 30 | for _, tt := range tests { 31 | t.Run(tt.name, func(t *testing.T) { 32 | m := initialModel(tt.commands, "mk") 33 | 34 | if m.list.Title != "mk" { 35 | t.Errorf("Expected title 'mk', got '%s'", m.list.Title) 36 | } 37 | 38 | if len(m.list.Items()) != len(tt.commands) { 39 | t.Fatalf("Expected %d items, got %d", len(tt.commands), len(m.list.Items())) 40 | } 41 | 42 | for i, listItem := range m.list.Items() { 43 | item, ok := listItem.(item) 44 | if !ok { 45 | t.Fatalf("Expected item of type 'item', got '%T'", listItem) 46 | } 47 | cmd := tt.commands[i] 48 | if item.title != cmd.Name || item.description != cmd.Description { 49 | t.Errorf("Expected %v, got %v", cmd, item) 50 | } 51 | } 52 | }) 53 | } 54 | } 55 | 56 | func TestRunCommand(t *testing.T) { 57 | tests := []struct { 58 | name string 59 | cmdName string 60 | cmdArgs []string 61 | expected string 62 | }{ 63 | { 64 | name: "Successful Command", 65 | cmdName: "echo", 66 | cmdArgs: []string{"Hello, World!"}, 67 | expected: "Hello, World!\n", 68 | }, 69 | { 70 | name: "Failing Command", 71 | cmdName: "nonexistentcommand", 72 | cmdArgs: []string{"arg"}, 73 | expected: "", 74 | }, 75 | } 76 | 77 | for _, tt := range tests { 78 | t.Run(tt.name, func(t *testing.T) { 79 | var out bytes.Buffer 80 | cmd := exec.Command(tt.cmdName, tt.cmdArgs...) 81 | cmd.Stdout = &out 82 | cmd.Stderr = &out 83 | 84 | err := cmd.Run() 85 | if tt.name == "Failing Command" && err == nil { 86 | t.Fatalf("Expected error for failing command, but got none") 87 | } else if tt.name != "Failing Command" && err != nil { 88 | t.Fatalf("Error running command: %v", err) 89 | } 90 | 91 | actual := out.String() 92 | if actual != tt.expected { 93 | t.Errorf("Expected output:\n%s\nBut got:\n%s", tt.expected, actual) 94 | } 95 | }) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /img/demo.tape: -------------------------------------------------------------------------------- 1 | # VHS documentation 2 | # 3 | # Output: 4 | # Output .gif Create a GIF output at the given 5 | # Output .mp4 Create an MP4 output at the given 6 | # Output .webm Create a WebM output at the given 7 | # 8 | # Settings: 9 | # Set FontSize Set the font size of the terminal 10 | # Set FontFamily Set the font family of the terminal 11 | # Set Height Set the height of the terminal 12 | # Set Width Set the width of the terminal 13 | # Set LetterSpacing Set the font letter spacing (tracking) 14 | # Set LineHeight Set the font line height 15 | # Set Theme Set the theme of the terminal (JSON) 16 | # Set Padding Set the padding of the terminal 17 | # Set Framerate Set the framerate of the recording 18 | # Set PlaybackSpeed Set the playback speed of the recording 19 | # 20 | # Sleep: 21 | # Sleep