├── .github ├── release.yml └── workflows │ ├── ci.yml │ └── tagpr.yml ├── .gitignore ├── .goreleaser.yml ├── .octocov.yml ├── .tagpr ├── CHANGELOG.md ├── CREDITS ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── cmd ├── commit.go ├── completion.go ├── gist.go ├── issue.go ├── issueComment.go ├── prComment.go ├── root.go ├── tag.go └── version.go ├── gh ├── gh.go └── gh_test.go ├── go.mod ├── go.sum ├── main.go ├── scripts └── entrypoint.sh └── version └── version.go /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - tagpr 5 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | job-test: 11 | name: Test 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Check out source code 15 | uses: actions/checkout@v4 16 | 17 | - name: Set up Go 18 | uses: actions/setup-go@v5 19 | with: 20 | go-version-file: go.mod 21 | 22 | - name: Test 23 | run: make ci 24 | env: 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | 27 | - name: Run octocov 28 | uses: k1LoW/octocov-action@v1 29 | -------------------------------------------------------------------------------- /.github/workflows/tagpr.yml: -------------------------------------------------------------------------------- 1 | name: tagpr 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | jobs: 8 | tagpr: 9 | runs-on: ubuntu-latest 10 | outputs: 11 | tagpr-tag: ${{ steps.run-tagpr.outputs.tag }} 12 | env: 13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 14 | steps: 15 | - name: Check out source code 16 | uses: actions/checkout@v4 17 | 18 | - name: Set up Go 19 | uses: actions/setup-go@v5 20 | with: 21 | go-version-file: go.mod 22 | 23 | - id: run-tagpr 24 | name: Run tagpr 25 | uses: Songmu/tagpr@v1 26 | 27 | build-assets: 28 | needs: tagpr 29 | if: needs.tagpr.outputs.tagpr-tag != '' 30 | runs-on: macos-latest 31 | steps: 32 | - name: Check out source code 33 | uses: actions/checkout@v4 34 | with: 35 | fetch-depth: 0 36 | 37 | - name: Set up Go 38 | uses: actions/setup-go@v5 39 | with: 40 | go-version-file: go.mod 41 | 42 | - name: Run GoReleaser 43 | uses: goreleaser/goreleaser-action@v6 44 | with: 45 | distribution: goreleaser 46 | version: latest 47 | args: --clean 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | 51 | dockerimage: 52 | needs: tagpr 53 | if: needs.tagpr.outputs.tagpr-tag != '' 54 | runs-on: ubuntu-latest 55 | env: 56 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | steps: 58 | - name: Check out source code 59 | uses: actions/checkout@v4 60 | with: 61 | fetch-depth: 0 62 | 63 | - name: Get latest version 64 | id: latest_version 65 | run: | 66 | echo -n 'version=' > $GITHUB_OUTPUT 67 | gh release list --limit 1 | cut -f 1 >> $GITHUB_OUTPUT 68 | cat $GITHUB_OUTPUT 69 | 70 | - name: Set up Docker Buildx 71 | uses: docker/setup-buildx-action@v3 72 | 73 | - name: Login to ghcr.io 74 | uses: docker/login-action@v3 75 | with: 76 | registry: ghcr.io 77 | username: ${{ github.actor }} 78 | password: ${{ secrets.GITHUB_TOKEN }} 79 | 80 | - name: Build and push 81 | uses: docker/build-push-action@v5 82 | with: 83 | context: . 84 | file: Dockerfile 85 | platforms: linux/amd64,linux/arm64 86 | push: true 87 | tags: | 88 | ghcr.io/k1low/ghput:${{ steps.latest_version.outputs.version }} 89 | ghcr.io/k1low/ghput:latest 90 | labels: | 91 | org.opencontainers.image.name=ghput 92 | org.opencontainers.image.revision=${{ github.sha }} 93 | org.opencontainers.image.version=${{ steps.latest_version.outputs.version }} 94 | org.opencontainers.image.source=https://github.com/k1LoW/runn 95 | 96 | release: 97 | needs: [build-assets, dockerimage, tagpr] 98 | runs-on: ubuntu-latest 99 | steps: 100 | - name: Release 101 | run: | 102 | gh api /repos/${{ github.repository }}/releases/generate-notes -f tag_name=${{ needs.tagpr.outputs.tagpr-tag }} --jq .body | gh release edit ${{ needs.tagpr.outputs.tagpr-tag }} --repo ${{ github.repository }} --draft=false --latest --notes-file=- 103 | env: 104 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 105 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .go-version 2 | dist/ 3 | coverage.out 4 | /ghput -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | before: 3 | hooks: 4 | - go mod download 5 | - go mod tidy 6 | builds: 7 | - 8 | id: ghput-linux 9 | env: 10 | - CGO_ENABLED=0 11 | goos: 12 | - linux 13 | goarch: 14 | - amd64 15 | - arm64 16 | ldflags: 17 | - -s -w -X github.com/k1LoW/ghput.version={{.Version}} -X github.com/k1LoW/ghput.commit={{.FullCommit}} -X github.com/k1LoW/ghput.date={{.Date}} -X github.com/k1LoW/ghput/version.Version={{.Version}} 18 | - 19 | id: ghput-darwin 20 | env: 21 | - CGO_ENABLED=0 22 | goos: 23 | - darwin 24 | goarch: 25 | - amd64 26 | - arm64 27 | ldflags: 28 | - -s -w -X github.com/k1LoW/ghput.version={{.Version}} -X github.com/k1LoW/ghput.commit={{.FullCommit}} -X github.com/k1LoW/ghput.date={{.Date}} -X github.com/k1LoW/ghput/version.Version={{.Version}} 29 | - 30 | id: ghput-windows 31 | env: 32 | - CGO_ENABLED=0 33 | goos: 34 | - windows 35 | goarch: 36 | - amd64 37 | ldflags: 38 | - -s -w -X github.com/k1LoW/ghput.version={{.Version}} -X github.com/k1LoW/ghput.commit={{.FullCommit}} -X github.com/k1LoW/ghput.date={{.Date}} -X github.com/k1LoW/ghput/version.Version={{.Version}} 39 | archives: 40 | - 41 | id: ghput-archive 42 | name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' 43 | format_overrides: 44 | - goos: darwin 45 | formats: [ 'zip' ] 46 | files: 47 | - LICENSE 48 | - CREDITS 49 | - README.md 50 | - CHANGELOG.md 51 | - 52 | id: ghput-binary 53 | name_template: '{{ .Binary }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' 54 | formats: [ 'binary' ] 55 | checksum: 56 | name_template: 'checksums.txt' 57 | nfpms: 58 | - id: ghput-nfpms 59 | file_name_template: "{{ .ProjectName }}_{{ .Version }}-1_{{ .Arch }}" 60 | builds: 61 | - ghput-linux 62 | homepage: https://github.com/k1LoW/ghput 63 | maintainer: Ken'ichiro Oyama 64 | description: ghput is a CI-friendly tool that puts * on GitHub. 65 | license: MIT 66 | formats: 67 | - apk 68 | - deb 69 | - rpm 70 | bindir: /usr/bin 71 | epoch: 1 72 | release: 73 | draft: true 74 | replace_existing_draft: true 75 | -------------------------------------------------------------------------------- /.octocov.yml: -------------------------------------------------------------------------------- 1 | # generated by octocov init 2 | coverage: 3 | if: true 4 | codeToTestRatio: 5 | code: 6 | - '**/*.go' 7 | - '!**/*_test.go' 8 | test: 9 | - '**/*_test.go' 10 | testExecutionTime: 11 | if: true 12 | diff: 13 | datastores: 14 | - artifact://${GITHUB_REPOSITORY} 15 | comment: 16 | if: is_pull_request 17 | report: 18 | if: is_default_branch 19 | datastores: 20 | - artifact://${GITHUB_REPOSITORY} 21 | -------------------------------------------------------------------------------- /.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 pcpr 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.tmplate (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 | [tagpr] 33 | vPrefix = true 34 | releaseBranch = main 35 | release = draft 36 | versionFile = version/version.go 37 | command = "make prerelease_for_tagpr" 38 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [v0.14.5](https://github.com/k1LoW/ghput/compare/v0.14.4...v0.14.5) - 2025-04-14 4 | - Bump golang.org/x/crypto from 0.17.0 to 0.31.0 by @dependabot in https://github.com/k1LoW/ghput/pull/40 5 | 6 | ## [v0.14.4](https://github.com/k1LoW/ghput/compare/v0.14.3...v0.14.4) - 2024-05-29 7 | 8 | ## [v0.14.3](https://github.com/k1LoW/ghput/compare/v0.14.2...v0.14.3) - 2024-05-29 9 | 10 | ## [v0.14.2](https://github.com/k1LoW/ghput/compare/v0.14.1...v0.14.2) - 2024-05-29 11 | - Set up tagpr by @k1LoW in https://github.com/k1LoW/ghput/pull/36 12 | 13 | ## [v0.14.1](https://github.com/k1LoW/ghput/compare/v0.14.0...v0.14.1) (2024-05-29) 14 | 15 | 16 | ## [v0.14.0](https://github.com/k1LoW/ghput/compare/v0.14.0...v0.14.0) (2024-05-29) 17 | 18 | 19 | ## [v0.14.0](https://github.com/k1LoW/ghput/compare/v0.14.0...v0.14.0) (2024-05-29) 20 | 21 | 22 | ## [v0.14.0](https://github.com/k1LoW/ghput/compare/v0.13.0...v0.14.0) (2024-05-29) 23 | 24 | * Identify the PR number from the branch name. [#35](https://github.com/k1LoW/ghput/pull/35) ([pyama86](https://github.com/pyama86)) 25 | * Bump golang.org/x/crypto from 0.1.0 to 0.17.0 [#34](https://github.com/k1LoW/ghput/pull/34) ([dependabot[bot]](https://github.com/apps/dependabot)) 26 | * Bump golang.org/x/crypto from 0.0.0-20210817164053-32db794688a5 to 0.1.0 [#33](https://github.com/k1LoW/ghput/pull/33) ([dependabot[bot]](https://github.com/apps/dependabot)) 27 | 28 | ## [v0.13.0](https://github.com/k1LoW/ghput/compare/v0.12.2...v0.13.0) (2022-11-11) 29 | 30 | * Support binary [#32](https://github.com/k1LoW/ghput/pull/32) ([k1LoW](https://github.com/k1LoW)) 31 | * Update go and pkg version [#31](https://github.com/k1LoW/ghput/pull/31) ([k1LoW](https://github.com/k1LoW)) 32 | 33 | ## [v0.12.2](https://github.com/k1LoW/ghput/compare/v0.12.1...v0.12.2) (2022-06-29) 34 | 35 | * Fix release flow [#30](https://github.com/k1LoW/ghput/pull/30) ([k1LoW](https://github.com/k1LoW)) 36 | 37 | ## [v0.12.1](https://github.com/k1LoW/ghput/compare/v0.12.0...v0.12.1) (2022-06-09) 38 | 39 | * Fix handling of line breaks in headers and footers [#29](https://github.com/k1LoW/ghput/pull/29) ([k1LoW](https://github.com/k1LoW)) 40 | * Git.io deprecation [#28](https://github.com/k1LoW/ghput/pull/28) ([k1LoW](https://github.com/k1LoW)) 41 | * Use octocov [#27](https://github.com/k1LoW/ghput/pull/27) ([k1LoW](https://github.com/k1LoW)) 42 | * User k1LoW/go-github-client [#26](https://github.com/k1LoW/ghput/pull/26) ([k1LoW](https://github.com/k1LoW)) 43 | 44 | ## [v0.12.0](https://github.com/k1LoW/ghput/compare/v0.11.0...v0.12.0) (2021-10-06) 45 | 46 | * Put a time based tag when `--tag` option is omitted. [#25](https://github.com/k1LoW/ghput/pull/25) ([k1LoW](https://github.com/k1LoW)) 47 | 48 | ## [v0.11.0](https://github.com/k1LoW/ghput/compare/v0.10.0...v0.11.0) (2021-10-06) 49 | 50 | * Add `--release` option [#24](https://github.com/k1LoW/ghput/pull/24) ([k1LoW](https://github.com/k1LoW)) 51 | * Change `ghput commit` `--branch` option to set default branch as default value [#23](https://github.com/k1LoW/ghput/pull/23) ([k1LoW](https://github.com/k1LoW)) 52 | * Add `ghput tag` [#22](https://github.com/k1LoW/ghput/pull/22) ([k1LoW](https://github.com/k1LoW)) 53 | * Support GITHUB_REPOSITORY on all sub commands [#21](https://github.com/k1LoW/ghput/pull/21) ([k1LoW](https://github.com/k1LoW)) 54 | * Get `owner` and `repo` from `GITHUB_REPOSITORY` [#20](https://github.com/k1LoW/ghput/pull/20) ([k1LoW](https://github.com/k1LoW)) 55 | 56 | ## [v0.10.0](https://github.com/k1LoW/ghput/compare/v0.9.0...v0.10.0) (2021-10-06) 57 | 58 | * Put comment to latest merged pull request ( Add `--latest-merged` ) [#19](https://github.com/k1LoW/ghput/pull/19) ([k1LoW](https://github.com/k1LoW)) 59 | 60 | ## [v0.9.0](https://github.com/k1LoW/ghput/compare/v0.8.0...v0.9.0) (2021-03-08) 61 | 62 | * Support GITHUB_API_URL ( GITHUB_BASE_URL is deprecated ) [#18](https://github.com/k1LoW/ghput/pull/18) ([k1LoW](https://github.com/k1LoW)) 63 | 64 | ## [v0.8.0](https://github.com/k1LoW/ghput/compare/v0.7.0...v0.8.0) (2021-01-27) 65 | 66 | * Add --close-issues-using-title to close current issues [#17](https://github.com/k1LoW/ghput/pull/17) ([k1LoW](https://github.com/k1LoW)) 67 | * Silence usage [#16](https://github.com/k1LoW/ghput/pull/16) ([k1LoW](https://github.com/k1LoW)) 68 | 69 | ## [v0.7.0](https://github.com/k1LoW/ghput/compare/v0.6.1...v0.7.0) (2020-12-24) 70 | 71 | * Support assigning team members [#15](https://github.com/k1LoW/ghput/pull/15) ([k1LoW](https://github.com/k1LoW)) 72 | 73 | ## [v0.6.1](https://github.com/k1LoW/ghput/compare/v0.6.0...v0.6.1) (2020-11-24) 74 | 75 | * Support assignees ( `ghput issue` ) [#14](https://github.com/k1LoW/ghput/pull/14) ([k1LoW](https://github.com/k1LoW)) 76 | 77 | ## [v0.6.0](https://github.com/k1LoW/ghput/compare/v0.5.2...v0.6.0) (2020-11-20) 78 | 79 | * Add `ghput issue` [#13](https://github.com/k1LoW/ghput/pull/13) ([k1LoW](https://github.com/k1LoW)) 80 | * Bump up go and pkg version [#12](https://github.com/k1LoW/ghput/pull/12) ([k1LoW](https://github.com/k1LoW)) 81 | 82 | ## [v0.5.2](https://github.com/k1LoW/ghput/compare/v0.5.1...v0.5.2) (2020-07-31) 83 | 84 | * Refactor code [#11](https://github.com/k1LoW/ghput/pull/11) ([k1LoW](https://github.com/k1LoW)) 85 | 86 | ## [v0.5.1](https://github.com/k1LoW/ghput/compare/v0.5.0...v0.5.1) (2020-05-03) 87 | 88 | * Add `--filename` option [#10](https://github.com/k1LoW/ghput/pull/10) ([k1LoW](https://github.com/k1LoW)) 89 | 90 | ## [v0.5.0](https://github.com/k1LoW/ghput/compare/v0.4.0...v0.5.0) (2020-05-02) 91 | 92 | * [BREAKING]Change footer key [#9](https://github.com/k1LoW/ghput/pull/9) ([k1LoW](https://github.com/k1LoW)) 93 | * Add `ghput gist` [#8](https://github.com/k1LoW/ghput/pull/8) ([k1LoW](https://github.com/k1LoW)) 94 | 95 | ## [v0.4.0](https://github.com/k1LoW/ghput/compare/v0.3.0...v0.4.0) (2020-04-28) 96 | 97 | * Add `ghput issue-comment` [#7](https://github.com/k1LoW/ghput/pull/7) ([k1LoW](https://github.com/k1LoW)) 98 | 99 | ## [v0.3.0](https://github.com/k1LoW/ghput/compare/v0.2.1...v0.3.0) (2020-04-28) 100 | 101 | * Add `ghput commit` [#6](https://github.com/k1LoW/ghput/pull/6) ([k1LoW](https://github.com/k1LoW)) 102 | 103 | ## [v0.2.1](https://github.com/k1LoW/ghput/compare/v0.2.0...v0.2.1) (2020-04-21) 104 | 105 | * Fix ghput footer [#5](https://github.com/k1LoW/ghput/pull/5) ([k1LoW](https://github.com/k1LoW)) 106 | 107 | ## [v0.2.0](https://github.com/k1LoW/ghput/compare/v0.1.0...v0.2.0) (2020-04-17) 108 | 109 | * Add --key option for uniquely identifying the comment [#4](https://github.com/k1LoW/ghput/pull/4) ([k1LoW](https://github.com/k1LoW)) 110 | 111 | ## [v0.1.0](https://github.com/k1LoW/ghput/compare/v0.0.1...v0.1.0) (2020-04-15) 112 | 113 | * Add option `--header` `--footer` [#3](https://github.com/k1LoW/ghput/pull/3) ([k1LoW](https://github.com/k1LoW)) 114 | * By default, there is only one latest pr comment via ghput [#2](https://github.com/k1LoW/ghput/pull/2) ([k1LoW](https://github.com/k1LoW)) 115 | * Format comment using github.com/mattn/go-colorable [#1](https://github.com/k1LoW/ghput/pull/1) ([k1LoW](https://github.com/k1LoW)) 116 | 117 | ## [v0.0.1](https://github.com/k1LoW/ghput/compare/175bc1d55020...v0.0.1) (2020-04-15) 118 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Go (the standard library) 2 | https://golang.org/ 3 | ---------------------------------------------------------------- 4 | Copyright (c) 2009 The Go Authors. All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following disclaimer 14 | in the documentation and/or other materials provided with the 15 | distribution. 16 | * Neither the name of Google Inc. nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | ================================================================ 33 | 34 | github.com/google/go-cmp 35 | https://github.com/google/go-cmp 36 | ---------------------------------------------------------------- 37 | Copyright (c) 2017 The Go Authors. All rights reserved. 38 | 39 | Redistribution and use in source and binary forms, with or without 40 | modification, are permitted provided that the following conditions are 41 | met: 42 | 43 | * Redistributions of source code must retain the above copyright 44 | notice, this list of conditions and the following disclaimer. 45 | * Redistributions in binary form must reproduce the above 46 | copyright notice, this list of conditions and the following disclaimer 47 | in the documentation and/or other materials provided with the 48 | distribution. 49 | * Neither the name of Google Inc. nor the names of its 50 | contributors may be used to endorse or promote products derived from 51 | this software without specific prior written permission. 52 | 53 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 54 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 55 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 56 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 57 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 58 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 59 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 60 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 61 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 62 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 63 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 64 | 65 | ================================================================ 66 | 67 | github.com/google/go-github/v41 68 | https://github.com/google/go-github/v41 69 | ---------------------------------------------------------------- 70 | Copyright (c) 2013 The go-github AUTHORS. All rights reserved. 71 | 72 | Redistribution and use in source and binary forms, with or without 73 | modification, are permitted provided that the following conditions are 74 | met: 75 | 76 | * Redistributions of source code must retain the above copyright 77 | notice, this list of conditions and the following disclaimer. 78 | * Redistributions in binary form must reproduce the above 79 | copyright notice, this list of conditions and the following disclaimer 80 | in the documentation and/or other materials provided with the 81 | distribution. 82 | * Neither the name of Google Inc. nor the names of its 83 | contributors may be used to endorse or promote products derived from 84 | this software without specific prior written permission. 85 | 86 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 87 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 88 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 89 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 90 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 91 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 92 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 93 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 94 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 95 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 96 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 97 | 98 | ================================================================ 99 | 100 | github.com/google/go-github/v45 101 | https://github.com/google/go-github/v45 102 | ---------------------------------------------------------------- 103 | Copyright (c) 2013 The go-github AUTHORS. All rights reserved. 104 | 105 | Redistribution and use in source and binary forms, with or without 106 | modification, are permitted provided that the following conditions are 107 | met: 108 | 109 | * Redistributions of source code must retain the above copyright 110 | notice, this list of conditions and the following disclaimer. 111 | * Redistributions in binary form must reproduce the above 112 | copyright notice, this list of conditions and the following disclaimer 113 | in the documentation and/or other materials provided with the 114 | distribution. 115 | * Neither the name of Google Inc. nor the names of its 116 | contributors may be used to endorse or promote products derived from 117 | this software without specific prior written permission. 118 | 119 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 120 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 121 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 122 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 123 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 124 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 125 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 126 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 127 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 128 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 129 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 130 | 131 | ================================================================ 132 | 133 | github.com/google/go-querystring 134 | https://github.com/google/go-querystring 135 | ---------------------------------------------------------------- 136 | Copyright (c) 2013 Google. All rights reserved. 137 | 138 | Redistribution and use in source and binary forms, with or without 139 | modification, are permitted provided that the following conditions are 140 | met: 141 | 142 | * Redistributions of source code must retain the above copyright 143 | notice, this list of conditions and the following disclaimer. 144 | * Redistributions in binary form must reproduce the above 145 | copyright notice, this list of conditions and the following disclaimer 146 | in the documentation and/or other materials provided with the 147 | distribution. 148 | * Neither the name of Google Inc. nor the names of its 149 | contributors may be used to endorse or promote products derived from 150 | this software without specific prior written permission. 151 | 152 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 153 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 154 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 155 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 156 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 157 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 158 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 159 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 160 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 161 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 162 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 163 | 164 | ================================================================ 165 | 166 | github.com/gorilla/mux 167 | https://github.com/gorilla/mux 168 | ---------------------------------------------------------------- 169 | Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved. 170 | 171 | Redistribution and use in source and binary forms, with or without 172 | modification, are permitted provided that the following conditions are 173 | met: 174 | 175 | * Redistributions of source code must retain the above copyright 176 | notice, this list of conditions and the following disclaimer. 177 | * Redistributions in binary form must reproduce the above 178 | copyright notice, this list of conditions and the following disclaimer 179 | in the documentation and/or other materials provided with the 180 | distribution. 181 | * Neither the name of Google Inc. nor the names of its 182 | contributors may be used to endorse or promote products derived from 183 | this software without specific prior written permission. 184 | 185 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 186 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 188 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 189 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 190 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 191 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 192 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 193 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 194 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 195 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 196 | 197 | ================================================================ 198 | 199 | github.com/inconshreveable/mousetrap 200 | https://github.com/inconshreveable/mousetrap 201 | ---------------------------------------------------------------- 202 | Apache License 203 | Version 2.0, January 2004 204 | http://www.apache.org/licenses/ 205 | 206 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 207 | 208 | 1. Definitions. 209 | 210 | "License" shall mean the terms and conditions for use, reproduction, 211 | and distribution as defined by Sections 1 through 9 of this document. 212 | 213 | "Licensor" shall mean the copyright owner or entity authorized by 214 | the copyright owner that is granting the License. 215 | 216 | "Legal Entity" shall mean the union of the acting entity and all 217 | other entities that control, are controlled by, or are under common 218 | control with that entity. For the purposes of this definition, 219 | "control" means (i) the power, direct or indirect, to cause the 220 | direction or management of such entity, whether by contract or 221 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 222 | outstanding shares, or (iii) beneficial ownership of such entity. 223 | 224 | "You" (or "Your") shall mean an individual or Legal Entity 225 | exercising permissions granted by this License. 226 | 227 | "Source" form shall mean the preferred form for making modifications, 228 | including but not limited to software source code, documentation 229 | source, and configuration files. 230 | 231 | "Object" form shall mean any form resulting from mechanical 232 | transformation or translation of a Source form, including but 233 | not limited to compiled object code, generated documentation, 234 | and conversions to other media types. 235 | 236 | "Work" shall mean the work of authorship, whether in Source or 237 | Object form, made available under the License, as indicated by a 238 | copyright notice that is included in or attached to the work 239 | (an example is provided in the Appendix below). 240 | 241 | "Derivative Works" shall mean any work, whether in Source or Object 242 | form, that is based on (or derived from) the Work and for which the 243 | editorial revisions, annotations, elaborations, or other modifications 244 | represent, as a whole, an original work of authorship. For the purposes 245 | of this License, Derivative Works shall not include works that remain 246 | separable from, or merely link (or bind by name) to the interfaces of, 247 | the Work and Derivative Works thereof. 248 | 249 | "Contribution" shall mean any work of authorship, including 250 | the original version of the Work and any modifications or additions 251 | to that Work or Derivative Works thereof, that is intentionally 252 | submitted to Licensor for inclusion in the Work by the copyright owner 253 | or by an individual or Legal Entity authorized to submit on behalf of 254 | the copyright owner. For the purposes of this definition, "submitted" 255 | means any form of electronic, verbal, or written communication sent 256 | to the Licensor or its representatives, including but not limited to 257 | communication on electronic mailing lists, source code control systems, 258 | and issue tracking systems that are managed by, or on behalf of, the 259 | Licensor for the purpose of discussing and improving the Work, but 260 | excluding communication that is conspicuously marked or otherwise 261 | designated in writing by the copyright owner as "Not a Contribution." 262 | 263 | "Contributor" shall mean Licensor and any individual or Legal Entity 264 | on behalf of whom a Contribution has been received by Licensor and 265 | subsequently incorporated within the Work. 266 | 267 | 2. Grant of Copyright License. Subject to the terms and conditions of 268 | this License, each Contributor hereby grants to You a perpetual, 269 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 270 | copyright license to reproduce, prepare Derivative Works of, 271 | publicly display, publicly perform, sublicense, and distribute the 272 | Work and such Derivative Works in Source or Object form. 273 | 274 | 3. Grant of Patent License. Subject to the terms and conditions of 275 | this License, each Contributor hereby grants to You a perpetual, 276 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 277 | (except as stated in this section) patent license to make, have made, 278 | use, offer to sell, sell, import, and otherwise transfer the Work, 279 | where such license applies only to those patent claims licensable 280 | by such Contributor that are necessarily infringed by their 281 | Contribution(s) alone or by combination of their Contribution(s) 282 | with the Work to which such Contribution(s) was submitted. If You 283 | institute patent litigation against any entity (including a 284 | cross-claim or counterclaim in a lawsuit) alleging that the Work 285 | or a Contribution incorporated within the Work constitutes direct 286 | or contributory patent infringement, then any patent licenses 287 | granted to You under this License for that Work shall terminate 288 | as of the date such litigation is filed. 289 | 290 | 4. Redistribution. You may reproduce and distribute copies of the 291 | Work or Derivative Works thereof in any medium, with or without 292 | modifications, and in Source or Object form, provided that You 293 | meet the following conditions: 294 | 295 | (a) You must give any other recipients of the Work or 296 | Derivative Works a copy of this License; and 297 | 298 | (b) You must cause any modified files to carry prominent notices 299 | stating that You changed the files; and 300 | 301 | (c) You must retain, in the Source form of any Derivative Works 302 | that You distribute, all copyright, patent, trademark, and 303 | attribution notices from the Source form of the Work, 304 | excluding those notices that do not pertain to any part of 305 | the Derivative Works; and 306 | 307 | (d) If the Work includes a "NOTICE" text file as part of its 308 | distribution, then any Derivative Works that You distribute must 309 | include a readable copy of the attribution notices contained 310 | within such NOTICE file, excluding those notices that do not 311 | pertain to any part of the Derivative Works, in at least one 312 | of the following places: within a NOTICE text file distributed 313 | as part of the Derivative Works; within the Source form or 314 | documentation, if provided along with the Derivative Works; or, 315 | within a display generated by the Derivative Works, if and 316 | wherever such third-party notices normally appear. The contents 317 | of the NOTICE file are for informational purposes only and 318 | do not modify the License. You may add Your own attribution 319 | notices within Derivative Works that You distribute, alongside 320 | or as an addendum to the NOTICE text from the Work, provided 321 | that such additional attribution notices cannot be construed 322 | as modifying the License. 323 | 324 | You may add Your own copyright statement to Your modifications and 325 | may provide additional or different license terms and conditions 326 | for use, reproduction, or distribution of Your modifications, or 327 | for any such Derivative Works as a whole, provided Your use, 328 | reproduction, and distribution of the Work otherwise complies with 329 | the conditions stated in this License. 330 | 331 | 5. Submission of Contributions. Unless You explicitly state otherwise, 332 | any Contribution intentionally submitted for inclusion in the Work 333 | by You to the Licensor shall be under the terms and conditions of 334 | this License, without any additional terms or conditions. 335 | Notwithstanding the above, nothing herein shall supersede or modify 336 | the terms of any separate license agreement you may have executed 337 | with Licensor regarding such Contributions. 338 | 339 | 6. Trademarks. This License does not grant permission to use the trade 340 | names, trademarks, service marks, or product names of the Licensor, 341 | except as required for reasonable and customary use in describing the 342 | origin of the Work and reproducing the content of the NOTICE file. 343 | 344 | 7. Disclaimer of Warranty. Unless required by applicable law or 345 | agreed to in writing, Licensor provides the Work (and each 346 | Contributor provides its Contributions) on an "AS IS" BASIS, 347 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 348 | implied, including, without limitation, any warranties or conditions 349 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 350 | PARTICULAR PURPOSE. You are solely responsible for determining the 351 | appropriateness of using or redistributing the Work and assume any 352 | risks associated with Your exercise of permissions under this License. 353 | 354 | 8. Limitation of Liability. In no event and under no legal theory, 355 | whether in tort (including negligence), contract, or otherwise, 356 | unless required by applicable law (such as deliberate and grossly 357 | negligent acts) or agreed to in writing, shall any Contributor be 358 | liable to You for damages, including any direct, indirect, special, 359 | incidental, or consequential damages of any character arising as a 360 | result of this License or out of the use or inability to use the 361 | Work (including but not limited to damages for loss of goodwill, 362 | work stoppage, computer failure or malfunction, or any and all 363 | other commercial damages or losses), even if such Contributor 364 | has been advised of the possibility of such damages. 365 | 366 | 9. Accepting Warranty or Additional Liability. While redistributing 367 | the Work or Derivative Works thereof, You may choose to offer, 368 | and charge a fee for, acceptance of support, warranty, indemnity, 369 | or other liability obligations and/or rights consistent with this 370 | License. However, in accepting such obligations, You may act only 371 | on Your own behalf and on Your sole responsibility, not on behalf 372 | of any other Contributor, and only if You agree to indemnify, 373 | defend, and hold each Contributor harmless for any liability 374 | incurred by, or claims asserted against, such Contributor by reason 375 | of your accepting any such warranty or additional liability. 376 | 377 | END OF TERMS AND CONDITIONS 378 | 379 | APPENDIX: How to apply the Apache License to your work. 380 | 381 | To apply the Apache License to your work, attach the following 382 | boilerplate notice, with the fields enclosed by brackets "[]" 383 | replaced with your own identifying information. (Don't include 384 | the brackets!) The text should be enclosed in the appropriate 385 | comment syntax for the file format. We also recommend that a 386 | file or class name and description of purpose be included on the 387 | same "printed page" as the copyright notice for easier 388 | identification within third-party archives. 389 | 390 | Copyright 2022 Alan Shreve (@inconshreveable) 391 | 392 | Licensed under the Apache License, Version 2.0 (the "License"); 393 | you may not use this file except in compliance with the License. 394 | You may obtain a copy of the License at 395 | 396 | http://www.apache.org/licenses/LICENSE-2.0 397 | 398 | Unless required by applicable law or agreed to in writing, software 399 | distributed under the License is distributed on an "AS IS" BASIS, 400 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 401 | See the License for the specific language governing permissions and 402 | limitations under the License. 403 | 404 | ================================================================ 405 | 406 | github.com/itchyny/timefmt-go 407 | https://github.com/itchyny/timefmt-go 408 | ---------------------------------------------------------------- 409 | The MIT License (MIT) 410 | 411 | Copyright (c) 2020-2022 itchyny 412 | 413 | Permission is hereby granted, free of charge, to any person obtaining a copy 414 | of this software and associated documentation files (the "Software"), to deal 415 | in the Software without restriction, including without limitation the rights 416 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 417 | copies of the Software, and to permit persons to whom the Software is 418 | furnished to do so, subject to the following conditions: 419 | 420 | The above copyright notice and this permission notice shall be included in all 421 | copies or substantial portions of the Software. 422 | 423 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 424 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 425 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 426 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 427 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 428 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 429 | SOFTWARE. 430 | 431 | ================================================================ 432 | 433 | github.com/k1LoW/go-github-client/v45 434 | https://github.com/k1LoW/go-github-client/v45 435 | ---------------------------------------------------------------- 436 | The MIT License (MIT) 437 | 438 | Copyright © 2021 Ken'ichiro Oyama 439 | 440 | Permission is hereby granted, free of charge, to any person obtaining a copy 441 | of this software and associated documentation files (the "Software"), to deal 442 | in the Software without restriction, including without limitation the rights 443 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 444 | copies of the Software, and to permit persons to whom the Software is 445 | furnished to do so, subject to the following conditions: 446 | 447 | The above copyright notice and this permission notice shall be included in 448 | all copies or substantial portions of the Software. 449 | 450 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 451 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 452 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 453 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 454 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 455 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 456 | THE SOFTWARE. 457 | 458 | ================================================================ 459 | 460 | github.com/mattn/go-colorable 461 | https://github.com/mattn/go-colorable 462 | ---------------------------------------------------------------- 463 | The MIT License (MIT) 464 | 465 | Copyright (c) 2016 Yasuhiro Matsumoto 466 | 467 | Permission is hereby granted, free of charge, to any person obtaining a copy 468 | of this software and associated documentation files (the "Software"), to deal 469 | in the Software without restriction, including without limitation the rights 470 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 471 | copies of the Software, and to permit persons to whom the Software is 472 | furnished to do so, subject to the following conditions: 473 | 474 | The above copyright notice and this permission notice shall be included in all 475 | copies or substantial portions of the Software. 476 | 477 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 478 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 479 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 480 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 481 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 482 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 483 | SOFTWARE. 484 | 485 | ================================================================ 486 | 487 | github.com/mattn/go-isatty 488 | https://github.com/mattn/go-isatty 489 | ---------------------------------------------------------------- 490 | Copyright (c) Yasuhiro MATSUMOTO 491 | 492 | MIT License (Expat) 493 | 494 | 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: 495 | 496 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 497 | 498 | 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. 499 | 500 | ================================================================ 501 | 502 | github.com/migueleliasweb/go-github-mock 503 | https://github.com/migueleliasweb/go-github-mock 504 | ---------------------------------------------------------------- 505 | MIT License 506 | 507 | Copyright (c) 2021 Miguel Elias dos Santos 508 | 509 | Permission is hereby granted, free of charge, to any person obtaining a copy 510 | of this software and associated documentation files (the "Software"), to deal 511 | in the Software without restriction, including without limitation the rights 512 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 513 | copies of the Software, and to permit persons to whom the Software is 514 | furnished to do so, subject to the following conditions: 515 | 516 | The above copyright notice and this permission notice shall be included in all 517 | copies or substantial portions of the Software. 518 | 519 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 520 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 521 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 522 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 523 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 524 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 525 | SOFTWARE. 526 | 527 | ================================================================ 528 | 529 | github.com/spf13/cobra 530 | https://github.com/spf13/cobra 531 | ---------------------------------------------------------------- 532 | Apache License 533 | Version 2.0, January 2004 534 | http://www.apache.org/licenses/ 535 | 536 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 537 | 538 | 1. Definitions. 539 | 540 | "License" shall mean the terms and conditions for use, reproduction, 541 | and distribution as defined by Sections 1 through 9 of this document. 542 | 543 | "Licensor" shall mean the copyright owner or entity authorized by 544 | the copyright owner that is granting the License. 545 | 546 | "Legal Entity" shall mean the union of the acting entity and all 547 | other entities that control, are controlled by, or are under common 548 | control with that entity. For the purposes of this definition, 549 | "control" means (i) the power, direct or indirect, to cause the 550 | direction or management of such entity, whether by contract or 551 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 552 | outstanding shares, or (iii) beneficial ownership of such entity. 553 | 554 | "You" (or "Your") shall mean an individual or Legal Entity 555 | exercising permissions granted by this License. 556 | 557 | "Source" form shall mean the preferred form for making modifications, 558 | including but not limited to software source code, documentation 559 | source, and configuration files. 560 | 561 | "Object" form shall mean any form resulting from mechanical 562 | transformation or translation of a Source form, including but 563 | not limited to compiled object code, generated documentation, 564 | and conversions to other media types. 565 | 566 | "Work" shall mean the work of authorship, whether in Source or 567 | Object form, made available under the License, as indicated by a 568 | copyright notice that is included in or attached to the work 569 | (an example is provided in the Appendix below). 570 | 571 | "Derivative Works" shall mean any work, whether in Source or Object 572 | form, that is based on (or derived from) the Work and for which the 573 | editorial revisions, annotations, elaborations, or other modifications 574 | represent, as a whole, an original work of authorship. For the purposes 575 | of this License, Derivative Works shall not include works that remain 576 | separable from, or merely link (or bind by name) to the interfaces of, 577 | the Work and Derivative Works thereof. 578 | 579 | "Contribution" shall mean any work of authorship, including 580 | the original version of the Work and any modifications or additions 581 | to that Work or Derivative Works thereof, that is intentionally 582 | submitted to Licensor for inclusion in the Work by the copyright owner 583 | or by an individual or Legal Entity authorized to submit on behalf of 584 | the copyright owner. For the purposes of this definition, "submitted" 585 | means any form of electronic, verbal, or written communication sent 586 | to the Licensor or its representatives, including but not limited to 587 | communication on electronic mailing lists, source code control systems, 588 | and issue tracking systems that are managed by, or on behalf of, the 589 | Licensor for the purpose of discussing and improving the Work, but 590 | excluding communication that is conspicuously marked or otherwise 591 | designated in writing by the copyright owner as "Not a Contribution." 592 | 593 | "Contributor" shall mean Licensor and any individual or Legal Entity 594 | on behalf of whom a Contribution has been received by Licensor and 595 | subsequently incorporated within the Work. 596 | 597 | 2. Grant of Copyright License. Subject to the terms and conditions of 598 | this License, each Contributor hereby grants to You a perpetual, 599 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 600 | copyright license to reproduce, prepare Derivative Works of, 601 | publicly display, publicly perform, sublicense, and distribute the 602 | Work and such Derivative Works in Source or Object form. 603 | 604 | 3. Grant of Patent License. Subject to the terms and conditions of 605 | this License, each Contributor hereby grants to You a perpetual, 606 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 607 | (except as stated in this section) patent license to make, have made, 608 | use, offer to sell, sell, import, and otherwise transfer the Work, 609 | where such license applies only to those patent claims licensable 610 | by such Contributor that are necessarily infringed by their 611 | Contribution(s) alone or by combination of their Contribution(s) 612 | with the Work to which such Contribution(s) was submitted. If You 613 | institute patent litigation against any entity (including a 614 | cross-claim or counterclaim in a lawsuit) alleging that the Work 615 | or a Contribution incorporated within the Work constitutes direct 616 | or contributory patent infringement, then any patent licenses 617 | granted to You under this License for that Work shall terminate 618 | as of the date such litigation is filed. 619 | 620 | 4. Redistribution. You may reproduce and distribute copies of the 621 | Work or Derivative Works thereof in any medium, with or without 622 | modifications, and in Source or Object form, provided that You 623 | meet the following conditions: 624 | 625 | (a) You must give any other recipients of the Work or 626 | Derivative Works a copy of this License; and 627 | 628 | (b) You must cause any modified files to carry prominent notices 629 | stating that You changed the files; and 630 | 631 | (c) You must retain, in the Source form of any Derivative Works 632 | that You distribute, all copyright, patent, trademark, and 633 | attribution notices from the Source form of the Work, 634 | excluding those notices that do not pertain to any part of 635 | the Derivative Works; and 636 | 637 | (d) If the Work includes a "NOTICE" text file as part of its 638 | distribution, then any Derivative Works that You distribute must 639 | include a readable copy of the attribution notices contained 640 | within such NOTICE file, excluding those notices that do not 641 | pertain to any part of the Derivative Works, in at least one 642 | of the following places: within a NOTICE text file distributed 643 | as part of the Derivative Works; within the Source form or 644 | documentation, if provided along with the Derivative Works; or, 645 | within a display generated by the Derivative Works, if and 646 | wherever such third-party notices normally appear. The contents 647 | of the NOTICE file are for informational purposes only and 648 | do not modify the License. You may add Your own attribution 649 | notices within Derivative Works that You distribute, alongside 650 | or as an addendum to the NOTICE text from the Work, provided 651 | that such additional attribution notices cannot be construed 652 | as modifying the License. 653 | 654 | You may add Your own copyright statement to Your modifications and 655 | may provide additional or different license terms and conditions 656 | for use, reproduction, or distribution of Your modifications, or 657 | for any such Derivative Works as a whole, provided Your use, 658 | reproduction, and distribution of the Work otherwise complies with 659 | the conditions stated in this License. 660 | 661 | 5. Submission of Contributions. Unless You explicitly state otherwise, 662 | any Contribution intentionally submitted for inclusion in the Work 663 | by You to the Licensor shall be under the terms and conditions of 664 | this License, without any additional terms or conditions. 665 | Notwithstanding the above, nothing herein shall supersede or modify 666 | the terms of any separate license agreement you may have executed 667 | with Licensor regarding such Contributions. 668 | 669 | 6. Trademarks. This License does not grant permission to use the trade 670 | names, trademarks, service marks, or product names of the Licensor, 671 | except as required for reasonable and customary use in describing the 672 | origin of the Work and reproducing the content of the NOTICE file. 673 | 674 | 7. Disclaimer of Warranty. Unless required by applicable law or 675 | agreed to in writing, Licensor provides the Work (and each 676 | Contributor provides its Contributions) on an "AS IS" BASIS, 677 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 678 | implied, including, without limitation, any warranties or conditions 679 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 680 | PARTICULAR PURPOSE. You are solely responsible for determining the 681 | appropriateness of using or redistributing the Work and assume any 682 | risks associated with Your exercise of permissions under this License. 683 | 684 | 8. Limitation of Liability. In no event and under no legal theory, 685 | whether in tort (including negligence), contract, or otherwise, 686 | unless required by applicable law (such as deliberate and grossly 687 | negligent acts) or agreed to in writing, shall any Contributor be 688 | liable to You for damages, including any direct, indirect, special, 689 | incidental, or consequential damages of any character arising as a 690 | result of this License or out of the use or inability to use the 691 | Work (including but not limited to damages for loss of goodwill, 692 | work stoppage, computer failure or malfunction, or any and all 693 | other commercial damages or losses), even if such Contributor 694 | has been advised of the possibility of such damages. 695 | 696 | 9. Accepting Warranty or Additional Liability. While redistributing 697 | the Work or Derivative Works thereof, You may choose to offer, 698 | and charge a fee for, acceptance of support, warranty, indemnity, 699 | or other liability obligations and/or rights consistent with this 700 | License. However, in accepting such obligations, You may act only 701 | on Your own behalf and on Your sole responsibility, not on behalf 702 | of any other Contributor, and only if You agree to indemnify, 703 | defend, and hold each Contributor harmless for any liability 704 | incurred by, or claims asserted against, such Contributor by reason 705 | of your accepting any such warranty or additional liability. 706 | 707 | ================================================================ 708 | 709 | github.com/spf13/pflag 710 | https://github.com/spf13/pflag 711 | ---------------------------------------------------------------- 712 | Copyright (c) 2012 Alex Ogier. All rights reserved. 713 | Copyright (c) 2012 The Go Authors. All rights reserved. 714 | 715 | Redistribution and use in source and binary forms, with or without 716 | modification, are permitted provided that the following conditions are 717 | met: 718 | 719 | * Redistributions of source code must retain the above copyright 720 | notice, this list of conditions and the following disclaimer. 721 | * Redistributions in binary form must reproduce the above 722 | copyright notice, this list of conditions and the following disclaimer 723 | in the documentation and/or other materials provided with the 724 | distribution. 725 | * Neither the name of Google Inc. nor the names of its 726 | contributors may be used to endorse or promote products derived from 727 | this software without specific prior written permission. 728 | 729 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 730 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 731 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 732 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 733 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 734 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 735 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 736 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 737 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 738 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 739 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 740 | 741 | ================================================================ 742 | 743 | golang.org/x/crypto 744 | https://golang.org/x/crypto 745 | ---------------------------------------------------------------- 746 | Copyright (c) 2009 The Go Authors. All rights reserved. 747 | 748 | Redistribution and use in source and binary forms, with or without 749 | modification, are permitted provided that the following conditions are 750 | met: 751 | 752 | * Redistributions of source code must retain the above copyright 753 | notice, this list of conditions and the following disclaimer. 754 | * Redistributions in binary form must reproduce the above 755 | copyright notice, this list of conditions and the following disclaimer 756 | in the documentation and/or other materials provided with the 757 | distribution. 758 | * Neither the name of Google Inc. nor the names of its 759 | contributors may be used to endorse or promote products derived from 760 | this software without specific prior written permission. 761 | 762 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 763 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 764 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 765 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 766 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 767 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 768 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 769 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 770 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 771 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 772 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 773 | 774 | ================================================================ 775 | 776 | golang.org/x/sys 777 | https://golang.org/x/sys 778 | ---------------------------------------------------------------- 779 | Copyright (c) 2009 The Go Authors. All rights reserved. 780 | 781 | Redistribution and use in source and binary forms, with or without 782 | modification, are permitted provided that the following conditions are 783 | met: 784 | 785 | * Redistributions of source code must retain the above copyright 786 | notice, this list of conditions and the following disclaimer. 787 | * Redistributions in binary form must reproduce the above 788 | copyright notice, this list of conditions and the following disclaimer 789 | in the documentation and/or other materials provided with the 790 | distribution. 791 | * Neither the name of Google Inc. nor the names of its 792 | contributors may be used to endorse or promote products derived from 793 | this software without specific prior written permission. 794 | 795 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 796 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 797 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 798 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 799 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 800 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 801 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 802 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 803 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 804 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 805 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 806 | 807 | ================================================================ 808 | 809 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1-bullseye AS builder 2 | 3 | WORKDIR /workdir/ 4 | COPY . /workdir/ 5 | 6 | RUN apt-get update 7 | 8 | RUN update-ca-certificates 9 | 10 | RUN make build 11 | 12 | FROM debian:bullseye-slim 13 | 14 | COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ 15 | COPY --from=builder /workdir/ghput ./usr/bin 16 | 17 | ENTRYPOINT ["/entrypoint.sh"] 18 | 19 | COPY scripts/entrypoint.sh /entrypoint.sh 20 | RUN chmod +x /entrypoint.sh 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2020 Ken'ichiro Oyama 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PKG = github.com/k1LoW/ghput 2 | COMMIT = $$(git describe --tags --always) 3 | OSNAME=${shell uname -s} 4 | ifeq ($(OSNAME),Darwin) 5 | DATE = $$(gdate --utc '+%Y-%m-%d_%H:%M:%S') 6 | else 7 | DATE = $$(date --utc '+%Y-%m-%d_%H:%M:%S') 8 | endif 9 | 10 | export GO111MODULE=on 11 | 12 | BUILD_LDFLAGS = -X $(PKG).commit=$(COMMIT) -X $(PKG).date=$(DATE) 13 | 14 | default: test 15 | 16 | ci: depsdev test sec 17 | 18 | test: 19 | go test ./... -coverprofile=coverage.out -covermode=count 20 | 21 | sec: 22 | gosec ./... 23 | 24 | build: 25 | go build -ldflags="$(BUILD_LDFLAGS)" 26 | 27 | depsdev: 28 | go install github.com/Songmu/ghch/cmd/ghch@latest 29 | go install github.com/Songmu/gocredits/cmd/gocredits@latest 30 | go install github.com/securego/gosec/v2/cmd/gosec@latest 31 | 32 | prerelease: 33 | git pull origin --tag 34 | ghch -w -N ${VER} 35 | gocredits -w . 36 | git add CHANGELOG.md CREDITS 37 | git commit -m'Bump up version number' 38 | git tag ${VER} 39 | 40 | prerelease_for_tagpr: 41 | gocredits -w . 42 | git add CHANGELOG.md CREDITS go.mod go.sum 43 | 44 | release: 45 | git push origin main --tag 46 | goreleaser --clean 47 | 48 | .PHONY: default test 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ghput [![Build Status](https://github.com/k1LoW/ghput/workflows/build/badge.svg)](https://github.com/k1LoW/ghput/actions) [![GitHub release](https://img.shields.io/github/release/k1LoW/ghput.svg)](https://github.com/k1LoW/ghput/releases) 2 | 3 | :octocat: ghput is a CI-friendly tool that puts `*` on GitHub. 4 | 5 | ## Usage 6 | 7 | **Put comment to issue:** 8 | 9 | ``` console 10 | $ echo 'This is comment !!' | GITHUB_TOKEN=XXXXXxxxxxXXxxxx ghput issue-comment --owner k1LoW --repo myrepo --number 1 11 | ``` 12 | 13 | **Put comment to issue on GitHub Actions:** 14 | 15 | ghput get `owner` and `repo` from [`GITHUB_REPOSITORY`](https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables). 16 | 17 | ``` yaml 18 | - name: Put comment 19 | run: echo 'This is comment !!' | ghput issue-comment --number 1 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | ``` 23 | 24 | **Put comment to pull request:** 25 | 26 | ``` console 27 | $ echo 'This is comment !!' | GITHUB_TOKEN=XXXXXxxxxxXXxxxx ghput pr-comment --owner k1LoW --repo myrepo --number 2 28 | ``` 29 | 30 | **Put comment to latest merged pull request:** 31 | 32 | ``` console 33 | $ echo 'Hello merged pull request !!' | GITHUB_TOKEN=XXXXXxxxxxXXxxxx ghput pr-comment --owner k1LoW --repo myrepo --latest-merged 34 | ``` 35 | 36 | **Put issue to repo:** 37 | 38 | ``` console 39 | $ echo 'This is new isssue !!' | GITHUB_TOKEN=XXXXXxxxxxXXxxxx ghput issue --owner k1LoW --repo myrepo --title 'New Issue !!!!!' 40 | ``` 41 | 42 | **Put commit to branch:** 43 | 44 | ``` console 45 | $ GITHUB_TOKEN=XXXXXxxxxxXXxxxx ghput commit --owner k1LoW --repo myrepo --branch main --file file.txt --path path/to/file.txt --message 'Commit file !!' 46 | ``` 47 | 48 | **Put tag to branch:** 49 | 50 | 51 | ``` console 52 | $ GITHUB_TOKEN=XXXXXxxxxxXXxxxx ghput tag --owner k1LoW --repo myrepo --branch main --tag v0.0.1 53 | ``` 54 | 55 | Put a time based tag when the tag option is omitted ( default time format: `%Y%m%d-%H%M%S%z` ) 56 | 57 | ``` console 58 | $ GITHUB_TOKEN=XXXXXxxxxxXXxxxx ghput tag --owner k1LoW --repo myrepo --tag-time-format '%Y%m%d%H%M' 59 | ``` 60 | 61 | **Put tag as release:** 62 | 63 | 64 | ``` console 65 | $ GITHUB_TOKEN=XXXXXxxxxxXXxxxx ghput tag --owner k1LoW --repo myrepo --tag v0.0.1 --release --release-title 'Code name: Elvis Juice' --release-body 'Release !!' 66 | ``` 67 | 68 | or 69 | 70 | ``` console 71 | $ echo 'Release !!' | GITHUB_TOKEN=XXXXXxxxxxXXxxxx ghput tag --owner k1LoW --repo myrepo --tag v0.0.1 --release --release-title 'Code name: Elvis Juice' 72 | ``` 73 | 74 | **Put file to Gist:** 75 | 76 | ``` console 77 | $ GITHUB_TOKEN=XXXXXxxxxxXXxxxx ghput gist --file file.txt 78 | ``` 79 | 80 | ``` console 81 | $ cat file.txt | GITHUB_TOKEN=XXXXXxxxxxXXxxxx ghput gist 82 | ``` 83 | 84 | **Use on GitHub Enterprise:** 85 | 86 | ``` console 87 | $ export GITHUB_API_URL=https://git.my-company.com/api/v3/ 88 | ``` 89 | 90 | ## Install 91 | 92 | **deb:** 93 | 94 | ``` console 95 | $ export GHPUT_VERSION=X.X.X 96 | $ curl -o ghput.deb -L https://github.com/k1LoW/ghput/releases/download/v$GHPUT_VERSION/ghput_$GHPUT_VERSION-1_amd64.deb 97 | $ dpkg -i ghput.deb 98 | ``` 99 | 100 | **RPM:** 101 | 102 | ``` console 103 | $ export GHPUT_VERSION=X.X.X 104 | $ yum install https://github.com/k1LoW/ghput/releases/download/v$GHPUT_VERSION/ghput_$GHPUT_VERSION-1_amd64.rpm 105 | ``` 106 | 107 | **homebrew tap:** 108 | 109 | ```console 110 | $ brew install k1LoW/tap/ghput 111 | ``` 112 | 113 | **manually:** 114 | 115 | Download binany from [releases page](https://github.com/k1LoW/ghput/releases) 116 | 117 | **go install:** 118 | 119 | ```console 120 | $ go install github.com/k1LoW/ghput@latest 121 | ``` 122 | 123 | ## Alternatives 124 | 125 | - [github-commenter](https://github.com/cloudposse/github-commenter): Command line utility for creating GitHub comments on Commits, Pull Request Reviews or Issues 126 | -------------------------------------------------------------------------------- /cmd/commit.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2020 Ken'ichiro Oyama 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 cmd 23 | 24 | import ( 25 | "context" 26 | "io" 27 | "os" 28 | 29 | "github.com/k1LoW/ghput/gh" 30 | "github.com/spf13/cobra" 31 | ) 32 | 33 | // commitCmd represents the commit command 34 | var commitCmd = &cobra.Command{ 35 | Use: "commit", 36 | Short: "Put commit to branch", 37 | Long: `Put commit to branch.`, 38 | Args: func(cmd *cobra.Command, args []string) error { 39 | if err := setOwnerRepo(); err != nil { 40 | return err 41 | } 42 | return nil 43 | }, 44 | RunE: func(cmd *cobra.Command, args []string) error { 45 | return runCommit(os.Stdin, os.Stdout) 46 | }, 47 | } 48 | 49 | func runCommit(stdin io.Reader, stdout io.Writer) error { 50 | ctx := context.Background() 51 | g, err := gh.New(owner, repo, key) 52 | if err != nil { 53 | return err 54 | } 55 | if branch == "" { 56 | branch, err = g.GetDefaultBranch(ctx) 57 | if err != nil { 58 | return err 59 | } 60 | } 61 | return g.CommitAndPushFile(ctx, branch, file, path, message) 62 | } 63 | 64 | func init() { 65 | rootCmd.AddCommand(commitCmd) 66 | commitCmd.Flags().StringVarP(&owner, "owner", "", "", "owner") 67 | commitCmd.Flags().StringVarP(&repo, "repo", "", "", "repo") 68 | commitCmd.Flags().StringVarP(&branch, "branch", "", "", "branch (default: default branch of repository)") 69 | commitCmd.Flags().StringVarP(&file, "file", "", "", "target file") 70 | commitCmd.Flags().StringVarP(&path, "path", "", "", "commit path") 71 | commitCmd.Flags().StringVarP(&message, "message", "", "commit by ghput", "commit message") 72 | } 73 | -------------------------------------------------------------------------------- /cmd/completion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2020 Ken'ichiro Oyama 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 cmd 23 | 24 | import ( 25 | "fmt" 26 | "os" 27 | "path/filepath" 28 | 29 | "github.com/spf13/cobra" 30 | ) 31 | 32 | var out string 33 | 34 | // completionCmd represents the completion command 35 | var completionCmd = &cobra.Command{ 36 | Use: "completion", 37 | Short: "Output shell completion code", 38 | Long: `Output shell completion code. 39 | To configure your shell to load completions for each session 40 | 41 | # bash 42 | echo '. <(ghput completion bash)' > ~/.bashrc 43 | 44 | # zsh 45 | ghput completion zsh > $fpath[1]/_ghput 46 | `, 47 | ValidArgs: []string{"bash", "zsh"}, 48 | Args: func(cmd *cobra.Command, args []string) error { 49 | if len(args) != 1 { 50 | return fmt.Errorf("accepts 1 arg, received %d", len(args)) 51 | } 52 | if err := cobra.OnlyValidArgs(cmd, args); err != nil { 53 | return err 54 | } 55 | return nil 56 | }, 57 | RunE: func(cmd *cobra.Command, args []string) error { 58 | var ( 59 | o *os.File 60 | err error 61 | ) 62 | sh := args[0] 63 | if out == "" { 64 | o = os.Stdout 65 | } else { 66 | o, err = os.Create(filepath.Clean(out)) 67 | if err != nil { 68 | return err 69 | } 70 | } 71 | 72 | switch sh { 73 | case "bash": 74 | if err := rootCmd.GenBashCompletion(o); err != nil { 75 | _ = o.Close() 76 | return err 77 | } 78 | case "zsh": 79 | if err := rootCmd.GenZshCompletion(o); err != nil { 80 | _ = o.Close() 81 | return err 82 | } 83 | } 84 | if err := o.Close(); err != nil { 85 | return err 86 | } 87 | return nil 88 | }, 89 | } 90 | 91 | func init() { 92 | rootCmd.AddCommand(completionCmd) 93 | completionCmd.Flags().StringVarP(&out, "out", "o", "", "output file path") 94 | } 95 | -------------------------------------------------------------------------------- /cmd/gist.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2020 Ken'ichiro Oyama 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 cmd 23 | 24 | import ( 25 | "context" 26 | "errors" 27 | "io" 28 | "os" 29 | "path/filepath" 30 | 31 | "github.com/k1LoW/ghput/gh" 32 | "github.com/spf13/cobra" 33 | ) 34 | 35 | // gistCmd represents the gist command 36 | var gistCmd = &cobra.Command{ 37 | Use: "gist", 38 | Short: "Put gist", 39 | Long: `Put gist.`, 40 | Args: func(cmd *cobra.Command, args []string) error { 41 | fi, err := os.Stdin.Stat() 42 | if err != nil { 43 | return err 44 | } 45 | if (fi.Mode()&os.ModeCharDevice) != 0 && file == "" { 46 | return errors.New("`ghput gist` need `--file` OR STDIN") 47 | } 48 | return nil 49 | }, 50 | RunE: func(cmd *cobra.Command, args []string) error { 51 | return runGist(os.Stdin, os.Stdout) 52 | }, 53 | } 54 | 55 | func runGist(stdin io.Reader, stdout io.Writer) (err error) { 56 | ctx := context.Background() 57 | g, err := gh.New(owner, repo, key) 58 | if err != nil { 59 | return err 60 | } 61 | var ( 62 | r io.Reader 63 | ) 64 | if file != "" { 65 | f, err := os.Open(file) 66 | if err != nil { 67 | return err 68 | } 69 | defer func() { 70 | err = f.Close() 71 | }() 72 | r = f 73 | if filename == "" { 74 | filename = filepath.Base(file) 75 | } 76 | } else { 77 | r = stdin 78 | if filename == "" { 79 | filename = "stdin" 80 | } 81 | } 82 | return g.CreateGist(ctx, filename, public, r, stdout) 83 | } 84 | 85 | func init() { 86 | rootCmd.AddCommand(gistCmd) 87 | gistCmd.Flags().StringVarP(&file, "file", "", "", "target file") 88 | gistCmd.Flags().StringVarP(&filename, "filename", "", "", "filename") 89 | gistCmd.Flags().BoolVarP(&public, "public", "", false, "public gist") 90 | } 91 | -------------------------------------------------------------------------------- /cmd/issue.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2020 Ken'ichiro Oyama 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 cmd 23 | 24 | import ( 25 | "context" 26 | "errors" 27 | "fmt" 28 | "io" 29 | "os" 30 | 31 | "github.com/k1LoW/ghput/gh" 32 | "github.com/spf13/cobra" 33 | ) 34 | 35 | var issueCmd = &cobra.Command{ 36 | Use: "issue", 37 | Short: "Put new issue to repo", 38 | Long: `Put new issue to repo.`, 39 | Args: func(cmd *cobra.Command, args []string) error { 40 | if err := setOwnerRepo(); err != nil { 41 | return err 42 | } 43 | fi, err := os.Stdin.Stat() 44 | if err != nil { 45 | return err 46 | } 47 | if (fi.Mode() & os.ModeCharDevice) != 0 { 48 | return errors.New("ghput need STDIN. Please use pipe") 49 | } 50 | return nil 51 | }, 52 | RunE: func(cmd *cobra.Command, args []string) error { 53 | return runIssue(os.Stdin, os.Stdout) 54 | }, 55 | } 56 | 57 | func runIssue(stdin io.Reader, stdout io.Writer) error { 58 | ctx := context.Background() 59 | g, err := gh.New(owner, repo, key) 60 | if err != nil { 61 | return err 62 | } 63 | c, err := getStdin(ctx, stdin) 64 | if err != nil { 65 | return err 66 | } 67 | body := string(c) 68 | comment, err := g.MakeComment(ctx, body, header, footer) 69 | if err != nil { 70 | return err 71 | } 72 | n, err := g.CreateIssue(ctx, title, comment, assignees) 73 | if err != nil { 74 | return err 75 | } 76 | if err := g.CloseIssuesUsingTitle(ctx, closeTitle, n); err != nil { 77 | return err 78 | } 79 | _, _ = fmt.Fprintf(stdout, "%d\n", n) 80 | return nil 81 | } 82 | 83 | func init() { 84 | rootCmd.AddCommand(issueCmd) 85 | issueCmd.Flags().StringVarP(&owner, "owner", "", "", "owner") 86 | issueCmd.Flags().StringVarP(&repo, "repo", "", "", "repo") 87 | issueCmd.Flags().StringVarP(&title, "title", "", "", "issue title") 88 | if err := issueCmd.MarkFlagRequired("title"); err != nil { 89 | issueCmd.PrintErrln(err) 90 | os.Exit(1) 91 | } 92 | issueCmd.Flags().StringVarP(&header, "header", "", "", "comment header") 93 | issueCmd.Flags().StringVarP(&footer, "footer", "", "", "comment footer") 94 | issueCmd.Flags().StringSliceVarP(&assignees, "assignee", "a", []string{}, "issue assignee") 95 | issueCmd.Flags().StringVarP(&closeTitle, "close-issues-using-title", "", "", "close current open issues using title match") 96 | } 97 | -------------------------------------------------------------------------------- /cmd/issueComment.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2020 Ken'ichiro Oyama 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 cmd 23 | 24 | import ( 25 | "context" 26 | "errors" 27 | "fmt" 28 | "io" 29 | "os" 30 | 31 | "github.com/k1LoW/ghput/gh" 32 | "github.com/spf13/cobra" 33 | ) 34 | 35 | // issueCommentCmd represents the issueComment command 36 | var issueCommentCmd = &cobra.Command{ 37 | Use: "issue-comment", 38 | Short: "Put comment to issue", 39 | Long: `Put comment to issue.`, 40 | Args: func(cmd *cobra.Command, args []string) error { 41 | if err := setOwnerRepo(); err != nil { 42 | return err 43 | } 44 | fi, err := os.Stdin.Stat() 45 | if err != nil { 46 | return err 47 | } 48 | if (fi.Mode() & os.ModeCharDevice) != 0 { 49 | return errors.New("ghput need STDIN. Please use pipe") 50 | } 51 | return nil 52 | }, 53 | RunE: func(cmd *cobra.Command, args []string) error { 54 | return runIssueComment(os.Stdin, os.Stdout) 55 | }, 56 | } 57 | 58 | func runIssueComment(stdin io.Reader, stdout io.Writer) error { 59 | ctx := context.Background() 60 | g, err := gh.New(owner, repo, key) 61 | if err != nil { 62 | return err 63 | } 64 | b, err := g.IsIssue(ctx, number) 65 | if err != nil { 66 | return err 67 | } 68 | if !b { 69 | return fmt.Errorf("#%d is not issue", number) 70 | } 71 | c, err := getStdin(ctx, stdin) 72 | if err != nil { 73 | return err 74 | } 75 | body := string(c) 76 | comment, err := g.MakeComment(ctx, body, header, footer) 77 | if err != nil { 78 | return err 79 | } 80 | if err := g.DeleteCurrentIssueComment(ctx, number); err != nil { 81 | return err 82 | } 83 | if err := g.PutIssueComment(ctx, number, comment); err != nil { 84 | return err 85 | } 86 | return nil 87 | } 88 | 89 | func init() { 90 | rootCmd.AddCommand(issueCommentCmd) 91 | issueCommentCmd.Flags().StringVarP(&owner, "owner", "", "", "owner") 92 | issueCommentCmd.Flags().StringVarP(&repo, "repo", "", "", "repo") 93 | issueCommentCmd.Flags().IntVarP(&number, "number", "", 0, "issue number") 94 | if err := issueCommentCmd.MarkFlagRequired("number"); err != nil { 95 | issueCommentCmd.PrintErrln(err) 96 | os.Exit(1) 97 | } 98 | issueCommentCmd.Flags().StringVarP(&header, "header", "", "", "comment header") 99 | issueCommentCmd.Flags().StringVarP(&footer, "footer", "", "", "comment footer") 100 | issueCommentCmd.Flags().StringVarP(&key, "key", "", "", "key for uniquely identifying the comment") 101 | } 102 | -------------------------------------------------------------------------------- /cmd/prComment.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2020 Ken'ichiro Oyama 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 cmd 23 | 24 | import ( 25 | "context" 26 | "errors" 27 | "fmt" 28 | "io" 29 | "os" 30 | 31 | "github.com/k1LoW/ghput/gh" 32 | "github.com/spf13/cobra" 33 | ) 34 | 35 | // prCommentCmd represents the prComment command 36 | var prCommentCmd = &cobra.Command{ 37 | Use: "pr-comment", 38 | Short: "Put comment to pull request", 39 | Long: `Put comment to pull request.`, 40 | Args: func(cmd *cobra.Command, args []string) error { 41 | if err := setOwnerRepo(); err != nil { 42 | return err 43 | } 44 | fillParamCnt := 0 45 | if number > 0 { 46 | fillParamCnt++ 47 | } 48 | if latestMerged { 49 | fillParamCnt++ 50 | } 51 | if branch != "" { 52 | fillParamCnt++ 53 | } 54 | 55 | if fillParamCnt != 1 { 56 | return errors.New("specify one of --number and --latest-merged and --branch") 57 | } 58 | 59 | fi, err := os.Stdin.Stat() 60 | if err != nil { 61 | return err 62 | } 63 | if (fi.Mode() & os.ModeCharDevice) != 0 { 64 | return errors.New("ghput need STDIN. Please use pipe") 65 | } 66 | return nil 67 | }, 68 | RunE: func(cmd *cobra.Command, args []string) error { 69 | return runPrComment(os.Stdin, os.Stdout) 70 | }, 71 | } 72 | 73 | func runPrComment(stdin io.Reader, stdout io.Writer) error { 74 | ctx := context.Background() 75 | g, err := gh.New(owner, repo, key) 76 | if err != nil { 77 | return err 78 | } 79 | if latestMerged { 80 | number, err = g.FetchLatestMergedPullRequest(ctx) 81 | if err != nil { 82 | return err 83 | } 84 | } 85 | 86 | if number == 0 && branch != "" { 87 | n, err := g.GetPullRequestNumber(ctx, branch) 88 | if err != nil { 89 | return err 90 | } 91 | number = n 92 | } 93 | 94 | b, err := g.IsPullRequest(ctx, number) 95 | if err != nil { 96 | return err 97 | } 98 | if !b { 99 | return fmt.Errorf("#%d is not pull request", number) 100 | } 101 | c, err := getStdin(ctx, stdin) 102 | if err != nil { 103 | return err 104 | } 105 | body := string(c) 106 | comment, err := g.MakeComment(ctx, body, header, footer) 107 | if err != nil { 108 | return err 109 | } 110 | if err := g.DeleteCurrentIssueComment(ctx, number); err != nil { 111 | return err 112 | } 113 | if err := g.PutIssueComment(ctx, number, comment); err != nil { 114 | return err 115 | } 116 | return nil 117 | } 118 | 119 | func init() { 120 | rootCmd.AddCommand(prCommentCmd) 121 | prCommentCmd.Flags().StringVarP(&owner, "owner", "", "", "owner") 122 | prCommentCmd.Flags().StringVarP(&repo, "repo", "", "", "repo") 123 | prCommentCmd.Flags().StringVarP(&branch, "branch", "", "", "branch") 124 | prCommentCmd.Flags().IntVarP(&number, "number", "", 0, "pull request number") 125 | prCommentCmd.Flags().BoolVarP(&latestMerged, "latest-merged", "", false, "latest merged pull request") 126 | prCommentCmd.Flags().StringVarP(&header, "header", "", "", "comment header") 127 | prCommentCmd.Flags().StringVarP(&footer, "footer", "", "", "comment footer") 128 | prCommentCmd.Flags().StringVarP(&key, "key", "", "", "key for uniquely identifying the comment") 129 | } 130 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2020 NAME HERE 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package cmd 17 | 18 | import ( 19 | "bufio" 20 | "bytes" 21 | "context" 22 | "errors" 23 | "io" 24 | "os" 25 | "strings" 26 | 27 | "github.com/mattn/go-colorable" 28 | "github.com/spf13/cobra" 29 | ) 30 | 31 | var ( 32 | owner string 33 | repo string 34 | number int 35 | header string 36 | footer string 37 | key string 38 | branch string 39 | file string 40 | path string 41 | message string 42 | public bool 43 | filename string 44 | title string 45 | assignees []string 46 | closeTitle string 47 | latestMerged bool 48 | tag string 49 | tagTimeFormat string 50 | release bool 51 | releaseTitle string 52 | releaseBody string 53 | ) 54 | 55 | // rootCmd represents the base command when called without any subcommands 56 | var rootCmd = &cobra.Command{ 57 | Use: "ghput", 58 | Short: "ghput is a CI-friendly tool that puts * on GitHub.", 59 | Long: `ghput is a CI-friendly tool that puts * on GitHub.`, 60 | SilenceUsage: true, 61 | } 62 | 63 | func Execute() { 64 | if err := rootCmd.Execute(); err != nil { 65 | os.Exit(1) 66 | } 67 | } 68 | 69 | func setOwnerRepo() error { 70 | if owner == "" && repo == "" && os.Getenv("GITHUB_REPOSITORY") != "" { 71 | splitted := strings.Split(os.Getenv("GITHUB_REPOSITORY"), "/") 72 | if len(splitted) == 2 { 73 | owner = splitted[0] 74 | repo = splitted[1] 75 | } 76 | } 77 | if owner == "" || repo == "" { 78 | return errors.New("--owner and --repo are not set") 79 | } 80 | return nil 81 | } 82 | 83 | func getStdin(ctx context.Context, stdin io.Reader) (string, error) { 84 | in := bufio.NewReader(stdin) 85 | out := new(bytes.Buffer) 86 | nc := colorable.NewNonColorable(out) 87 | for { 88 | s, err := in.ReadBytes('\n') 89 | if err == io.EOF { 90 | break 91 | } else if err != nil { 92 | return "", err 93 | } 94 | select { 95 | case <-ctx.Done(): 96 | break 97 | default: 98 | _, err = nc.Write(s) 99 | if err != nil { 100 | return "", err 101 | } 102 | } 103 | } 104 | return out.String(), nil 105 | } 106 | -------------------------------------------------------------------------------- /cmd/tag.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Ken'ichiro Oyama 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 cmd 23 | 24 | import ( 25 | "context" 26 | "io" 27 | "os" 28 | "time" 29 | 30 | "github.com/itchyny/timefmt-go" 31 | "github.com/k1LoW/ghput/gh" 32 | "github.com/spf13/cobra" 33 | ) 34 | 35 | // tagCmd represents the tag command 36 | var tagCmd = &cobra.Command{ 37 | Use: "tag", 38 | Short: "Put tag to branch", 39 | Long: `Put tag to branch.`, 40 | Args: func(cmd *cobra.Command, args []string) error { 41 | if err := setOwnerRepo(); err != nil { 42 | return err 43 | } 44 | return nil 45 | }, 46 | RunE: func(cmd *cobra.Command, args []string) error { 47 | return runTag(os.Stdin, os.Stdout) 48 | }, 49 | } 50 | 51 | func runTag(stdin io.Reader, stdout io.Writer) error { 52 | ctx := context.Background() 53 | g, err := gh.New(owner, repo, key) 54 | if err != nil { 55 | return err 56 | } 57 | if branch == "" { 58 | branch, err = g.GetDefaultBranch(ctx) 59 | if err != nil { 60 | return err 61 | } 62 | } 63 | if tag == "" { 64 | tag = timefmt.Format(time.Now(), tagTimeFormat) 65 | } 66 | if err := g.CreateTag(ctx, branch, tag); err != nil { 67 | return err 68 | } 69 | if release { 70 | if releaseBody == "" { 71 | fi, err := os.Stdin.Stat() 72 | if err != nil { 73 | return err 74 | } 75 | if (fi.Mode() & os.ModeCharDevice) == 0 { 76 | c, err := getStdin(ctx, stdin) 77 | if err != nil { 78 | return err 79 | } 80 | releaseBody = string(c) 81 | } 82 | } 83 | if err := g.CreateRelease(ctx, tag, releaseTitle, releaseBody); err != nil { 84 | return err 85 | } 86 | } 87 | return nil 88 | } 89 | 90 | func init() { 91 | rootCmd.AddCommand(tagCmd) 92 | tagCmd.Flags().StringVarP(&owner, "owner", "", "", "owner") 93 | tagCmd.Flags().StringVarP(&repo, "repo", "", "", "repo") 94 | tagCmd.Flags().StringVarP(&branch, "branch", "", "", "branch (default: default branch of repository)") 95 | tagCmd.Flags().StringVarP(&tag, "tag", "", "", "tag") 96 | tagCmd.Flags().StringVarP(&tagTimeFormat, "tag-time-format", "", "%Y%m%d-%H%M%S%z", "time format of tag") 97 | 98 | tagCmd.Flags().BoolVarP(&release, "release", "", false, "create a tag as a release.") 99 | tagCmd.Flags().StringVarP(&releaseTitle, "release-title", "", "", "release title") 100 | tagCmd.Flags().StringVarP(&releaseBody, "release-body", "", "", "release body") 101 | } 102 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2020 Ken'ichiro Oyama 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 cmd 23 | 24 | import ( 25 | "fmt" 26 | 27 | "github.com/k1LoW/ghput/version" 28 | "github.com/spf13/cobra" 29 | ) 30 | 31 | // versionCmd represents the version command 32 | var versionCmd = &cobra.Command{ 33 | Use: "version", 34 | Short: "Print ghput version", 35 | Long: `Print ghput version.`, 36 | Run: func(cmd *cobra.Command, args []string) { 37 | fmt.Println(version.Version) 38 | }, 39 | } 40 | 41 | func init() { 42 | rootCmd.AddCommand(versionCmd) 43 | } 44 | -------------------------------------------------------------------------------- /gh/gh.go: -------------------------------------------------------------------------------- 1 | package gh 2 | 3 | import ( 4 | "context" 5 | "encoding/base64" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "os" 10 | "path" 11 | "path/filepath" 12 | "strconv" 13 | "strings" 14 | 15 | "github.com/google/go-github/v45/github" 16 | "github.com/k1LoW/go-github-client/v45/factory" 17 | ) 18 | 19 | const ( 20 | footerFormat = "" 21 | ) 22 | 23 | var rep = strings.NewReplacer("\\n", "\n", "\\t", "\t") 24 | 25 | type Gh struct { 26 | client *github.Client 27 | owner string 28 | repo string 29 | key string 30 | } 31 | 32 | // New return Gh 33 | func New(owner, repo, key string) (*Gh, error) { 34 | client, err := factory.NewGithubClient() 35 | if err != nil { 36 | return nil, err 37 | } 38 | return &Gh{ 39 | client: client, 40 | owner: owner, 41 | repo: repo, 42 | key: key, 43 | }, nil 44 | } 45 | 46 | func (g *Gh) MakeComment(ctx context.Context, body, header, footer string) (string, error) { 47 | if body != "" && !strings.HasSuffix(body, "\n") { 48 | body += "\n" 49 | } 50 | header = rep.Replace(header) 51 | if header != "" && !strings.HasSuffix(header, "\n") { 52 | header += "\n" 53 | } 54 | footer = rep.Replace(footer) 55 | if footer != "" && !strings.HasSuffix(footer, "\n") { 56 | footer += "\n" 57 | } 58 | return fmt.Sprintf("%s%s%s%s\n", header, body, footer, g.CommentFooter()), nil 59 | } 60 | 61 | func (g *Gh) CommentFooter() string { 62 | if g.key == "" { 63 | return fmt.Sprintf(footerFormat, g.key) 64 | } 65 | key := fmt.Sprintf("[key:%s] ", g.key) 66 | return fmt.Sprintf(footerFormat, key) 67 | } 68 | 69 | func (g *Gh) FetchLatestMergedPullRequest(ctx context.Context) (int, error) { 70 | commits, _, err := g.client.Repositories.ListCommits(ctx, g.owner, g.repo, &github.CommitsListOptions{ 71 | ListOptions: github.ListOptions{ 72 | Page: 1, 73 | PerPage: 100, 74 | }, 75 | }) 76 | if err != nil { 77 | return 0, err 78 | } 79 | for _, c := range commits { 80 | m := c.GetCommit().GetMessage() 81 | if strings.HasPrefix(m, "Merge pull request #") { 82 | splitted := strings.Split(strings.TrimPrefix(m, "Merge pull request #"), " ") 83 | if len(splitted) < 1 { 84 | break 85 | } 86 | n, err := strconv.Atoi(splitted[0]) 87 | if err != nil { 88 | break 89 | } 90 | return n, nil 91 | } 92 | } 93 | // fallback 94 | q := fmt.Sprintf("type:pr is:merged sort:updated-desc repo:%s/%s", g.owner, g.repo) 95 | prs, _, err := g.client.Search.Issues(ctx, q, &github.SearchOptions{ 96 | Sort: "updated", 97 | Order: "desc", 98 | ListOptions: github.ListOptions{ 99 | Page: 1, 100 | PerPage: 1, 101 | }, 102 | }) 103 | if err != nil { 104 | return 0, err 105 | } 106 | if len(prs.Issues) == 0 { 107 | return 0, err 108 | } 109 | return prs.Issues[0].GetNumber(), nil 110 | } 111 | 112 | func (g *Gh) GetDefaultBranch(ctx context.Context) (string, error) { 113 | r, _, err := g.client.Repositories.Get(ctx, g.owner, g.repo) 114 | if err != nil { 115 | return "", err 116 | } 117 | return r.GetDefaultBranch(), nil 118 | } 119 | 120 | func (g Gh) IsPullRequest(ctx context.Context, n int) (bool, error) { 121 | i, _, err := g.client.Issues.Get(ctx, g.owner, g.repo, n) 122 | if err != nil { 123 | return false, err 124 | } 125 | return i.IsPullRequest(), nil 126 | } 127 | 128 | func (g Gh) IsIssue(ctx context.Context, n int) (bool, error) { 129 | b, err := g.IsPullRequest(ctx, n) 130 | if err != nil { 131 | return false, err 132 | } 133 | return !b, nil 134 | } 135 | 136 | func (g *Gh) CreateIssue(ctx context.Context, title string, comment string, assignees []string) (int, error) { 137 | // trim assignees 138 | as := []string{} 139 | for _, a := range assignees { 140 | splitted := strings.Split(a, " ") 141 | for _, s := range splitted { 142 | if s == "" { 143 | continue 144 | } 145 | trimed := strings.Trim(s, "@") 146 | if !strings.Contains(trimed, "/") { 147 | as = append(as, trimed) 148 | continue 149 | } 150 | splitted := strings.Split(trimed, "/") 151 | org := splitted[0] 152 | slug := splitted[1] 153 | opts := &github.TeamListTeamMembersOptions{} 154 | users, _, err := g.client.Teams.ListTeamMembersBySlug(ctx, org, slug, opts) 155 | if err != nil { 156 | return 0, err 157 | } 158 | for _, u := range users { 159 | as = append(as, *u.Login) 160 | } 161 | } 162 | } 163 | as = unique(as) 164 | 165 | r := &github.IssueRequest{Title: &title, Body: &comment, Assignees: &as} 166 | i, _, err := g.client.Issues.Create(ctx, g.owner, g.repo, r) 167 | if err != nil { 168 | return 0, err 169 | } 170 | return *i.Number, nil 171 | } 172 | 173 | func (g *Gh) PutIssueComment(ctx context.Context, n int, comment string) error { 174 | c := &github.IssueComment{Body: &comment} 175 | if _, _, err := g.client.Issues.CreateComment(ctx, g.owner, g.repo, n, c); err != nil { 176 | return err 177 | } 178 | return nil 179 | } 180 | 181 | func (g *Gh) DeleteCurrentIssueComment(ctx context.Context, n int) error { 182 | listOptions := &github.IssueListCommentsOptions{} 183 | comments, _, err := g.client.Issues.ListComments(ctx, g.owner, g.repo, n, listOptions) 184 | if err != nil { 185 | return err 186 | } 187 | for _, c := range comments { 188 | if strings.Contains(*c.Body, g.CommentFooter()) { 189 | _, err = g.client.Issues.DeleteComment(ctx, g.owner, g.repo, *c.ID) 190 | if err != nil { 191 | return err 192 | } 193 | } 194 | } 195 | return nil 196 | } 197 | 198 | func (g *Gh) CommitAndPush(ctx context.Context, branch string, content []byte, rPath, message string) error { 199 | srv := g.client.Git 200 | 201 | dRef, _, err := srv.GetRef(ctx, g.owner, g.repo, path.Join("heads", branch)) 202 | if err != nil { 203 | return err 204 | } 205 | 206 | parent, _, err := srv.GetCommit(ctx, g.owner, g.repo, *dRef.Object.SHA) 207 | if err != nil { 208 | return err 209 | } 210 | 211 | var tree *github.Tree 212 | 213 | if rPath != "" { 214 | blob := &github.Blob{ 215 | Content: github.String(base64.StdEncoding.EncodeToString(content)), 216 | Encoding: github.String("base64"), 217 | } 218 | 219 | resB, _, err := srv.CreateBlob(ctx, g.owner, g.repo, blob) 220 | if err != nil { 221 | return err 222 | } 223 | 224 | entry := &github.TreeEntry{ 225 | Path: github.String(rPath), 226 | Mode: github.String("100644"), 227 | Type: github.String("blob"), 228 | SHA: resB.SHA, 229 | } 230 | 231 | entries := []*github.TreeEntry{entry} 232 | 233 | tree, _, err = srv.CreateTree(ctx, g.owner, g.repo, *dRef.Object.SHA, entries) 234 | if err != nil { 235 | return err 236 | } 237 | } else { 238 | tree, _, err = srv.GetTree(ctx, g.owner, g.repo, *parent.Tree.SHA, false) 239 | } 240 | 241 | commit := &github.Commit{ 242 | Message: github.String(message), 243 | Tree: tree, 244 | Parents: []*github.Commit{parent}, 245 | } 246 | resC, _, err := srv.CreateCommit(ctx, g.owner, g.repo, commit) 247 | if err != nil { 248 | return err 249 | } 250 | 251 | nref := &github.Reference{ 252 | Ref: github.String(path.Join("refs", "heads", branch)), 253 | Object: &github.GitObject{ 254 | Type: github.String("commit"), 255 | SHA: resC.SHA, 256 | }, 257 | } 258 | if _, _, err := srv.UpdateRef(ctx, g.owner, g.repo, nref, false); err != nil { 259 | return err 260 | } 261 | 262 | return nil 263 | } 264 | 265 | func (g *Gh) CommitAndPushFile(ctx context.Context, branch, file, rPath, message string) error { 266 | var b []byte 267 | if file != "" { 268 | f, err := os.Stat(file) 269 | if err != nil { 270 | return err 271 | } 272 | if f.IsDir() { 273 | return errors.New("'ghput commit' does not yet support directory commit.") 274 | } 275 | b, err = os.ReadFile(filepath.Clean(file)) 276 | if err != nil { 277 | return err 278 | } 279 | if rPath == "" { 280 | rPath = filepath.Base(file) 281 | } 282 | } 283 | return g.CommitAndPush(ctx, branch, b, rPath, message) 284 | } 285 | 286 | func (g *Gh) CreateGist(ctx context.Context, fname string, public bool, in io.Reader, out io.Writer) error { 287 | b, err := io.ReadAll(in) 288 | if err != nil { 289 | return err 290 | } 291 | 292 | content := string(b) 293 | files := make(map[github.GistFilename]github.GistFile, 1) 294 | files[github.GistFilename(fname)] = github.GistFile{ 295 | Size: github.Int(len(content)), 296 | Filename: github.String(fname), 297 | Content: github.String(content), 298 | } 299 | 300 | input := &github.Gist{ 301 | Description: github.String("Put by ghput"), 302 | Public: github.Bool(public), 303 | Files: files, 304 | } 305 | gist, _, err := g.client.Gists.Create(ctx, input) 306 | if err != nil { 307 | return err 308 | } 309 | _, _ = fmt.Fprintf(out, "%s\n", *gist.HTMLURL) 310 | return nil 311 | } 312 | 313 | func (g *Gh) CloseIssuesUsingTitle(ctx context.Context, closeTitle string, ignoreNumber int) error { 314 | if closeTitle == "" { 315 | return nil 316 | } 317 | opts := &github.SearchOptions{ 318 | ListOptions: github.ListOptions{ 319 | PerPage: 100, 320 | }, 321 | } 322 | r, _, err := g.client.Search.Issues(ctx, fmt.Sprintf("%s state:open type:issue in:title repo:%s/%s", closeTitle, g.owner, g.repo), opts) 323 | if err != nil { 324 | return err 325 | } 326 | for _, i := range r.Issues { 327 | if *i.Number == ignoreNumber { 328 | continue 329 | } 330 | if err := g.PutIssueComment(ctx, *i.Number, fmt.Sprintf("Closed when ghput created #%d.", ignoreNumber)); err != nil { 331 | return err 332 | } 333 | closed := "closed" 334 | if _, _, err := g.client.Issues.Edit(ctx, g.owner, g.repo, *i.Number, &github.IssueRequest{ 335 | State: &closed, 336 | }); err != nil { 337 | return err 338 | } 339 | } 340 | return nil 341 | } 342 | 343 | func (g *Gh) CreateTag(ctx context.Context, branch, tag string) error { 344 | ref, _, err := g.client.Git.GetRef(ctx, g.owner, g.repo, path.Join("heads", branch)) 345 | if err != nil { 346 | return err 347 | } 348 | tref := fmt.Sprintf("refs/tags/%s", tag) 349 | if _, _, err := g.client.Git.CreateRef(ctx, g.owner, g.repo, &github.Reference{ 350 | Ref: &tref, 351 | Object: ref.GetObject(), 352 | }); err != nil { 353 | return err 354 | } 355 | return nil 356 | } 357 | 358 | func (g *Gh) CreateRelease(ctx context.Context, tag, title, body string) error { 359 | if _, _, err := g.client.Repositories.CreateRelease(ctx, g.owner, g.repo, &github.RepositoryRelease{ 360 | TagName: &tag, 361 | Name: &title, 362 | Body: &body, 363 | }); err != nil { 364 | return err 365 | } 366 | return nil 367 | } 368 | 369 | func (g *Gh) GetPullRequestNumber(ctx context.Context, branch string) (int, error) { 370 | prs, _, err := g.client.PullRequests.List(ctx, g.owner, g.repo, &github.PullRequestListOptions{ 371 | Head: fmt.Sprintf("%s:%s", g.owner, branch), 372 | }) 373 | if err != nil { 374 | return 0, err 375 | } 376 | if len(prs) == 0 { 377 | return 0, errors.New("pull request not found") 378 | } 379 | return prs[0].GetNumber(), nil 380 | } 381 | 382 | func unique(in []string) []string { 383 | m := map[string]struct{}{} 384 | u := []string{} 385 | for _, s := range in { 386 | if _, ok := m[s]; !ok { 387 | u = append(u, s) 388 | } 389 | m[s] = struct{}{} 390 | } 391 | return u 392 | } 393 | -------------------------------------------------------------------------------- /gh/gh_test.go: -------------------------------------------------------------------------------- 1 | package gh 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/google/go-cmp/cmp" 8 | ) 9 | 10 | func TestMakeComment(t *testing.T) { 11 | ctx := context.Background() 12 | tests := []struct { 13 | body string 14 | header string 15 | footer string 16 | want string 17 | }{ 18 | {"", "", "", "\n"}, 19 | {"body", "header", "footer", "header\nbody\nfooter\n\n"}, 20 | {"body\n", "header\n", "footer\n", "header\nbody\nfooter\n\n"}, 21 | } 22 | for _, tt := range tests { 23 | gh, err := New("o", "r", "") 24 | if err != nil { 25 | t.Fatal(err) 26 | } 27 | got, err := gh.MakeComment(ctx, tt.body, tt.header, tt.footer) 28 | if err != nil { 29 | t.Fatal(err) 30 | } 31 | if got != tt.want { 32 | t.Errorf("got\n%v\nwant\n%v", got, tt.want) 33 | } 34 | } 35 | } 36 | 37 | func TestCommentFooter(t *testing.T) { 38 | tests := []struct { 39 | key string 40 | want string 41 | }{ 42 | { 43 | key: "", 44 | want: "", 45 | }, 46 | { 47 | key: "value", 48 | want: "", 49 | }, 50 | } 51 | 52 | for _, tt := range tests { 53 | gh, err := New("o", "r", tt.key) 54 | if err != nil { 55 | t.Fatal(err) 56 | } 57 | got := gh.CommentFooter() 58 | if got != tt.want { 59 | t.Errorf("got %v want %v", got, tt.want) 60 | } 61 | } 62 | } 63 | 64 | func TestUnique(t *testing.T) { 65 | tests := []struct { 66 | in []string 67 | want []string 68 | }{ 69 | {[]string{}, []string{}}, 70 | {[]string{"a", "c", "b"}, []string{"a", "c", "b"}}, 71 | {[]string{"b", "c", "b"}, []string{"b", "c"}}, 72 | {[]string{"a", "a", "b"}, []string{"a", "b"}}, 73 | } 74 | for _, tt := range tests { 75 | got := unique(tt.in) 76 | if diff := cmp.Diff(got, tt.want, nil); diff != "" { 77 | t.Errorf("%s", diff) 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/k1LoW/ghput 2 | 3 | go 1.23.8 4 | 5 | require ( 6 | github.com/google/go-cmp v0.5.9 7 | github.com/google/go-github/v45 v45.2.0 8 | github.com/itchyny/timefmt-go v0.1.4 9 | github.com/k1LoW/go-github-client/v45 v45.2.3 10 | github.com/mattn/go-colorable v0.1.13 11 | github.com/spf13/cobra v1.6.1 12 | ) 13 | 14 | require ( 15 | github.com/google/go-querystring v1.1.0 // indirect 16 | github.com/inconshreveable/mousetrap v1.0.1 // indirect 17 | github.com/mattn/go-isatty v0.0.16 // indirect 18 | github.com/spf13/pflag v1.0.5 // indirect 19 | golang.org/x/crypto v0.35.0 // indirect 20 | golang.org/x/sys v0.30.0 // indirect 21 | ) 22 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 2 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 3 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 4 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 5 | github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg= 6 | github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= 7 | github.com/google/go-github/v45 v45.2.0 h1:5oRLszbrkvxDDqBCNj2hjDZMKmvexaZ1xw/FCD+K3FI= 8 | github.com/google/go-github/v45 v45.2.0/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28= 9 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 10 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 11 | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= 12 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 13 | github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= 14 | github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 15 | github.com/itchyny/timefmt-go v0.1.4 h1:hFEfWVdwsEi+CY8xY2FtgWHGQaBaC3JeHd+cve0ynVM= 16 | github.com/itchyny/timefmt-go v0.1.4/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= 17 | github.com/k1LoW/go-github-client/v45 v45.2.3 h1:VgL8bLfDfppHJTrCZQ826R+P4Np9+kOJXP0i0NQAqao= 18 | github.com/k1LoW/go-github-client/v45 v45.2.3/go.mod h1:c6rHQhBuUN+Ljzi9e2tvv3EPlijIRnOEFyQiD+H0rkE= 19 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 20 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 21 | github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= 22 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 23 | github.com/migueleliasweb/go-github-mock v0.0.8 h1:+V+tZ6smpaWRmocdKRkYerxZrFn7QGifoWTV0rURV28= 24 | github.com/migueleliasweb/go-github-mock v0.0.8/go.mod h1:mD5w+9J3oBBMLr7uD6owEYlYBAL8tZd+BA7iGjI4EU8= 25 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 26 | github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= 27 | github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= 28 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 29 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 30 | golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= 31 | golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= 32 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 33 | golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= 34 | golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 35 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 36 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 37 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 38 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2020 NAME HERE 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package main 17 | 18 | import "github.com/k1LoW/ghput/cmd" 19 | 20 | func main() { 21 | cmd.Execute() 22 | } 23 | -------------------------------------------------------------------------------- /scripts/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -l 2 | 3 | ghput $@ 4 | -------------------------------------------------------------------------------- /version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | // Name for this 4 | const Name string = "ghput" 5 | 6 | // Version for this 7 | var Version = "0.14.5" 8 | --------------------------------------------------------------------------------