mirror of
https://github.com/lukaszraczylo/semver-generator.git
synced 2026-06-18 01:41:19 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b279c7f24 | |||
| 888415366a | |||
| dfbc4d4012 | |||
| dfeb03b8bb | |||
| ab52de167e | |||
| 564f39ed10 | |||
| 99b8bf937b | |||
| b555e410cc | |||
| 521e5c1ff1 | |||
| a223f15e1c | |||
| d1b8192b78 | |||
| a3aed9ef93 | |||
| 5f205e9856 | |||
| a77bc0c7ae | |||
| 99338e8527 | |||
| 911513c106 | |||
| c2a7a4e156 | |||
| 21b87300cc | |||
| 3e0a7239c4 | |||
| 49a46a74c1 | |||
| 3a48a67c75 | |||
| 18b9b474e0 | |||
| f5a118fd1a | |||
| a1c4133e94 | |||
| 2a51752663 | |||
| 0bc848f6f4 | |||
| 8590963822 | |||
| f4285403f7 | |||
| b3d104f0a8 | |||
| 7a70ed6614 | |||
| f9a18995d0 | |||
| 66756b6772 | |||
| a0f1ab6930 | |||
| b80929ff52 |
@@ -8,6 +8,7 @@ on:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
actions: write
|
actions: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
autoupdate:
|
autoupdate:
|
||||||
@@ -15,3 +16,4 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: "1.24"
|
go-version: "1.24"
|
||||||
release-workflow: "release.yaml"
|
release-workflow: "release.yaml"
|
||||||
|
secrets: inherit
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
name: Pull Request
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "**"
|
||||||
|
- "!main"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pr-checks:
|
||||||
|
uses: lukaszraczylo/shared-actions/.github/workflows/go-pr.yaml@main
|
||||||
|
with:
|
||||||
|
go-version: "1.24"
|
||||||
@@ -6,11 +6,11 @@ on:
|
|||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
- '**/release.yaml'
|
- '**/release.yaml'
|
||||||
- 'action.yml'
|
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
id-token: write
|
||||||
contents: write
|
contents: write
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
@@ -18,9 +18,39 @@ jobs:
|
|||||||
release:
|
release:
|
||||||
uses: lukaszraczylo/shared-actions/.github/workflows/go-release.yaml@main
|
uses: lukaszraczylo/shared-actions/.github/workflows/go-release.yaml@main
|
||||||
with:
|
with:
|
||||||
go-version: "1.24"
|
go-version: ">=1.24"
|
||||||
docker-enabled: true
|
docker-enabled: true
|
||||||
rolling-release-tag: "v1"
|
rolling-release-tag: "v1"
|
||||||
semver-config: "config-release.yaml"
|
semver-config: "config-release.yaml"
|
||||||
secrets:
|
secrets: inherit
|
||||||
homebrew-tap-token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
|
||||||
|
update-action-version:
|
||||||
|
needs: release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: needs.release.outputs.version != ''
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: main
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Update action.yml with release version
|
||||||
|
env:
|
||||||
|
VERSION: ${{ needs.release.outputs.version }}
|
||||||
|
run: |
|
||||||
|
echo "Updating action.yml to version: ${VERSION}"
|
||||||
|
sed -i "s|ghcr.io/lukaszraczylo/semver-generator:[^\"]*|ghcr.io/lukaszraczylo/semver-generator:${VERSION}|" action.yml
|
||||||
|
echo "Updated action.yml:"
|
||||||
|
grep "image:" action.yml
|
||||||
|
|
||||||
|
- name: Commit and push
|
||||||
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add action.yml
|
||||||
|
if git diff --staged --quiet; then
|
||||||
|
echo "No changes to commit"
|
||||||
|
else
|
||||||
|
git commit -m "chore: pin action.yml Docker image to v${{ needs.release.outputs.version }}"
|
||||||
|
git push
|
||||||
|
fi
|
||||||
|
|||||||
+36
-53
@@ -7,7 +7,7 @@ before:
|
|||||||
builds:
|
builds:
|
||||||
- id: semver-gen
|
- id: semver-gen
|
||||||
main: .
|
main: .
|
||||||
binary: semver-gen
|
binary: semver-generator
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=0
|
- CGO_ENABLED=0
|
||||||
goos:
|
goos:
|
||||||
@@ -24,7 +24,7 @@ builds:
|
|||||||
archives:
|
archives:
|
||||||
- id: semver-gen
|
- id: semver-gen
|
||||||
formats: [tar.gz]
|
formats: [tar.gz]
|
||||||
name_template: "semver-gen-{{ .Version }}-{{ .Os }}-{{ .Arch }}"
|
name_template: "semver-generator-{{ .Os }}-{{ .Arch }}"
|
||||||
format_overrides:
|
format_overrides:
|
||||||
- goos: windows
|
- goos: windows
|
||||||
formats: [zip]
|
formats: [zip]
|
||||||
@@ -34,7 +34,7 @@ archives:
|
|||||||
- config.yaml
|
- config.yaml
|
||||||
|
|
||||||
checksum:
|
checksum:
|
||||||
name_template: "semver-gen-{{ .Version }}-checksums.txt"
|
name_template: "semver-generator-checksums.txt"
|
||||||
algorithm: sha256
|
algorithm: sha256
|
||||||
|
|
||||||
changelog:
|
changelog:
|
||||||
@@ -55,59 +55,24 @@ release:
|
|||||||
draft: false
|
draft: false
|
||||||
prerelease: auto
|
prerelease: auto
|
||||||
|
|
||||||
dockers:
|
dockers_v2:
|
||||||
- id: semver-gen-amd64
|
- images:
|
||||||
goos: linux
|
- "ghcr.io/lukaszraczylo/semver-generator"
|
||||||
goarch: amd64
|
tags:
|
||||||
ids:
|
- "{{ .Version }}"
|
||||||
- semver-gen
|
- "latest"
|
||||||
image_templates:
|
- "v1"
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:{{ .Version }}-amd64"
|
platforms:
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:latest-amd64"
|
- linux/amd64
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:v1-amd64"
|
- linux/arm64
|
||||||
dockerfile: Dockerfile.goreleaser
|
dockerfile: Dockerfile.goreleaser
|
||||||
use: buildx
|
|
||||||
build_flag_templates:
|
|
||||||
- "--platform=linux/amd64"
|
|
||||||
extra_files:
|
extra_files:
|
||||||
- config-release.yaml
|
- config-release.yaml
|
||||||
- entrypoint.sh
|
- entrypoint.sh
|
||||||
|
|
||||||
- id: semver-gen-arm64
|
|
||||||
goos: linux
|
|
||||||
goarch: arm64
|
|
||||||
ids:
|
|
||||||
- semver-gen
|
|
||||||
image_templates:
|
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:{{ .Version }}-arm64"
|
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:latest-arm64"
|
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:v1-arm64"
|
|
||||||
dockerfile: Dockerfile.goreleaser
|
|
||||||
use: buildx
|
|
||||||
build_flag_templates:
|
|
||||||
- "--platform=linux/arm64"
|
|
||||||
extra_files:
|
|
||||||
- config-release.yaml
|
|
||||||
- entrypoint.sh
|
|
||||||
|
|
||||||
docker_manifests:
|
|
||||||
- name_template: "ghcr.io/lukaszraczylo/semver-generator:{{ .Version }}"
|
|
||||||
image_templates:
|
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:{{ .Version }}-amd64"
|
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:{{ .Version }}-arm64"
|
|
||||||
|
|
||||||
- name_template: "ghcr.io/lukaszraczylo/semver-generator:latest"
|
|
||||||
image_templates:
|
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:latest-amd64"
|
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:latest-arm64"
|
|
||||||
|
|
||||||
- name_template: "ghcr.io/lukaszraczylo/semver-generator:v1"
|
|
||||||
image_templates:
|
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:v1-amd64"
|
|
||||||
- "ghcr.io/lukaszraczylo/semver-generator:v1-arm64"
|
|
||||||
|
|
||||||
homebrew_casks:
|
homebrew_casks:
|
||||||
- repository:
|
- name: semver-generator
|
||||||
|
repository:
|
||||||
owner: lukaszraczylo
|
owner: lukaszraczylo
|
||||||
name: homebrew-taps
|
name: homebrew-taps
|
||||||
token: "{{ .Env.HOMEBREW_TAP_TOKEN }}"
|
token: "{{ .Env.HOMEBREW_TAP_TOKEN }}"
|
||||||
@@ -115,12 +80,30 @@ homebrew_casks:
|
|||||||
homepage: https://github.com/lukaszraczylo/semver-generator
|
homepage: https://github.com/lukaszraczylo/semver-generator
|
||||||
description: "Automatic semantic version generator based on git commit messages"
|
description: "Automatic semantic version generator based on git commit messages"
|
||||||
license: MIT
|
license: MIT
|
||||||
url:
|
|
||||||
verified: github.com/lukaszraczylo/semver-generator
|
|
||||||
hooks:
|
hooks:
|
||||||
post:
|
post:
|
||||||
install: |
|
install: |
|
||||||
if OS.mac?
|
if OS.mac?
|
||||||
system_command "/usr/bin/xattr",
|
system_command "/usr/bin/xattr",
|
||||||
args: ["-dr", "com.apple.quarantine", "#{staged_path}/semver-gen"]
|
args: ["-dr", "com.apple.quarantine", "#{staged_path}/semver-generator"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
signs:
|
||||||
|
- cmd: cosign
|
||||||
|
signature: "${artifact}.sigstore.json"
|
||||||
|
args:
|
||||||
|
- sign-blob
|
||||||
|
- "--bundle=${signature}"
|
||||||
|
- "${artifact}"
|
||||||
|
- "--yes"
|
||||||
|
artifacts: checksum
|
||||||
|
output: true
|
||||||
|
|
||||||
|
docker_signs:
|
||||||
|
- cmd: cosign
|
||||||
|
artifacts: manifests
|
||||||
|
output: true
|
||||||
|
args:
|
||||||
|
- sign
|
||||||
|
- "${artifact}@${digest}"
|
||||||
|
- "--yes"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
FROM ubuntu:jammy
|
FROM ubuntu:jammy
|
||||||
COPY semver-gen /go/src/app/semver-gen
|
ARG TARGETPLATFORM
|
||||||
|
COPY ${TARGETPLATFORM}/semver-generator /go/src/app/semver-generator
|
||||||
COPY config-release.yaml /go/src/app/config.yaml
|
COPY config-release.yaml /go/src/app/config.yaml
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
RUN chmod +x /entrypoint.sh
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|||||||
@@ -11,13 +11,19 @@ Project created overnight, to prove that management of semantic versioning is NO
|
|||||||
- [Usage](#usage)
|
- [Usage](#usage)
|
||||||
- [Authentication](#authentication)
|
- [Authentication](#authentication)
|
||||||
- [As a binary](#as-a-binary)
|
- [As a binary](#as-a-binary)
|
||||||
|
- [Homebrew (macOS)](#homebrew-macos)
|
||||||
|
- [Manual Download](#manual-download)
|
||||||
|
- [Self-Update](#self-update)
|
||||||
- [As a github action](#as-a-github-action)
|
- [As a github action](#as-a-github-action)
|
||||||
- [As a docker container](#as-a-docker-container)
|
- [As a docker container](#as-a-docker-container)
|
||||||
|
- [Verifying Release Signatures](#verifying-release-signatures)
|
||||||
- [Calculations example \[standard\]](#calculations-example-standard)
|
- [Calculations example \[standard\]](#calculations-example-standard)
|
||||||
- [Calculations example \[strict matching\]](#calculations-example-strict-matching)
|
- [Calculations example \[strict matching\]](#calculations-example-strict-matching)
|
||||||
- [Release candidates](#release-candidates)
|
- [Release candidates](#release-candidates)
|
||||||
|
- [Tag prefix stripping](#tag-prefix-stripping)
|
||||||
- [Example configuration](#example-configuration)
|
- [Example configuration](#example-configuration)
|
||||||
- [Good to know](#good-to-know)
|
- [Good to knows](#good-to-knows)
|
||||||
|
- [Telemetry](#telemetry)
|
||||||
|
|
||||||
### How does it work
|
### How does it work
|
||||||
|
|
||||||
@@ -29,6 +35,7 @@ Project created overnight, to prove that management of semantic versioning is NO
|
|||||||
|
|
||||||
* With flag `-e` or config `force.existing: true` the existing tags in versioning will be respected, helping you to avoid the version conflicts.
|
* With flag `-e` or config `force.existing: true` the existing tags in versioning will be respected, helping you to avoid the version conflicts.
|
||||||
* With config `force.commit: deadbeef` where `deadbeef` is the commit hash - calculations will start from the specified commit.
|
* With config `force.commit: deadbeef` where `deadbeef` is the commit hash - calculations will start from the specified commit.
|
||||||
|
* Tag prefix stripping: The `v` prefix is automatically stripped from tags (e.g., `v1.2.3` → `1.2.3`). Additional prefixes can be configured via `tag_prefixes` for monorepo setups (e.g., `app-1.2.3`, `infra-1.2.3`).
|
||||||
|
|
||||||
### Important changes
|
### Important changes
|
||||||
|
|
||||||
@@ -52,7 +59,7 @@ export GITHUB_TOKEN=yourPersonalApiToken
|
|||||||
##### Homebrew (macOS)
|
##### Homebrew (macOS)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
brew install --cask lukaszraczylo/taps/semver-gen
|
brew install --cask lukaszraczylo/taps/semver-generator
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Manual Download
|
##### Manual Download
|
||||||
@@ -63,9 +70,9 @@ You can download latest versions of the binaries from the [release page](https:/
|
|||||||
Darwin ARM64/AMD64, Linux ARM64/AMD64, Windows AMD64
|
Darwin ARM64/AMD64, Linux ARM64/AMD64, Windows AMD64
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash$ ./semver-gen generate -r https://github.com/nextapps-de/winbox
|
bash$ semver-generator generate -r https://github.com/nextapps-de/winbox
|
||||||
SEMVER 9.0.10
|
SEMVER 9.0.10
|
||||||
bash$ ./semver-gen generate -l
|
bash$ semver-generator generate -l
|
||||||
SEMVER 5.1.1
|
SEMVER 5.1.1
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -73,8 +80,8 @@ SEMVER 5.1.1
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
Usage:
|
Usage:
|
||||||
semver-gen generate [flags]
|
semver-generator generate [flags]
|
||||||
semver-gen [command]
|
semver-generator [command]
|
||||||
|
|
||||||
Available Commands:
|
Available Commands:
|
||||||
generate Generates semantic version
|
generate Generates semantic version
|
||||||
@@ -84,15 +91,25 @@ Flags:
|
|||||||
-c, --config string Path to config file (default "semver.yaml")
|
-c, --config string Path to config file (default "semver.yaml")
|
||||||
-d, --debug Enable debug mode
|
-d, --debug Enable debug mode
|
||||||
-e, --existing Respect existing tags
|
-e, --existing Respect existing tags
|
||||||
-h, --help help for semver-gen
|
-h, --help help for semver-generator
|
||||||
-l, --local Use local repository
|
-l, --local Use local repository
|
||||||
-r, --repository string Remote repository URL. (default "https://github.com/lukaszraczylo/simple-gql-client")
|
-r, --repository string Remote repository URL. (default "https://github.com/lukaszraczylo/simple-gql-client")
|
||||||
-b, --branch string Remote repository URL Branch. (default "main")
|
-b, --branch string Remote repository URL Branch. (default "main")
|
||||||
-s, --strict Strict matching
|
-s, --strict Strict matching
|
||||||
-u, --update Update binary with latest
|
-u, --update Update binary with latest (no authentication required)
|
||||||
-v, --version Display version
|
-v, --version Display version
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### Self-Update
|
||||||
|
|
||||||
|
The binary can update itself to the latest version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
semver-generator -u
|
||||||
|
```
|
||||||
|
|
||||||
|
This downloads the latest release for your platform directly from GitHub releases. No authentication is required.
|
||||||
|
|
||||||
#### As a github action
|
#### As a github action
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -134,6 +151,25 @@ jobs:
|
|||||||
docker pull ghcr.io/lukaszraczylo/semver-generator:latest
|
docker pull ghcr.io/lukaszraczylo/semver-generator:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Verifying Release Signatures
|
||||||
|
|
||||||
|
All release checksums and Docker images are signed with [cosign](https://github.com/sigstore/cosign) using keyless signing. To verify:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verify checksum signature
|
||||||
|
cosign verify-blob \
|
||||||
|
--certificate-identity-regexp "https://github.com/lukaszraczylo/semver-generator/.*" \
|
||||||
|
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
|
||||||
|
--bundle "<checksums-file>.sigstore.json" \
|
||||||
|
<checksums-file>
|
||||||
|
|
||||||
|
# Verify Docker image
|
||||||
|
cosign verify \
|
||||||
|
--certificate-identity-regexp "https://github.com/lukaszraczylo/semver-generator/.*" \
|
||||||
|
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
|
||||||
|
ghcr.io/lukaszraczylo/semver-generator:latest
|
||||||
|
```
|
||||||
|
|
||||||
**Docker supported architectures:**
|
**Docker supported architectures:**
|
||||||
Linux/arm64, Linux/amd64
|
Linux/arm64, Linux/amd64
|
||||||
|
|
||||||
@@ -172,6 +208,36 @@ to generate the appropriate release in format `1.3.37-rc.1` and counting up unti
|
|||||||
- add-rc
|
- add-rc
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Tag prefix stripping
|
||||||
|
|
||||||
|
When using the `-e` (existing tags) flag, the semver-generator needs to parse existing git tags to determine the current version. Tags often include prefixes that need to be stripped before version parsing.
|
||||||
|
|
||||||
|
**Automatic `v` prefix stripping:**
|
||||||
|
The `v` prefix is always stripped automatically from tags. For example:
|
||||||
|
- `v1.2.3` → parsed as `1.2.3`
|
||||||
|
- `v0.5.0` → parsed as `0.5.0`
|
||||||
|
|
||||||
|
**Custom prefixes for monorepos:**
|
||||||
|
In monorepo setups where different components have their own versioned tags, you can configure additional prefixes to strip:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
tag_prefixes:
|
||||||
|
- "app-"
|
||||||
|
- "infra-"
|
||||||
|
- "api-"
|
||||||
|
- "frontend-"
|
||||||
|
```
|
||||||
|
|
||||||
|
With this configuration:
|
||||||
|
- `app-1.2.3` → parsed as `1.2.3`
|
||||||
|
- `infra-0.5.0` → parsed as `0.5.0`
|
||||||
|
- `api-2.0.0-rc.1` → parsed as `2.0.0-rc.1` (release candidate)
|
||||||
|
|
||||||
|
This is particularly useful when:
|
||||||
|
- You have multiple services/components in a single repository
|
||||||
|
- Your CI/CD creates tags with component prefixes
|
||||||
|
- You want to track versions separately for different parts of your codebase
|
||||||
|
|
||||||
#### Example configuration
|
#### Example configuration
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -186,6 +252,10 @@ blacklist:
|
|||||||
- "Merge pull request"
|
- "Merge pull request"
|
||||||
- "feature/"
|
- "feature/"
|
||||||
- "feature:"
|
- "feature:"
|
||||||
|
tag_prefixes:
|
||||||
|
- "app-"
|
||||||
|
- "infra-"
|
||||||
|
- "service-"
|
||||||
wording:
|
wording:
|
||||||
patch:
|
patch:
|
||||||
- update
|
- update
|
||||||
@@ -205,10 +275,23 @@ wording:
|
|||||||
* `force`: sets the "starting" version, you don't need to specify this section as the default is always `0`
|
* `force`: sets the "starting" version, you don't need to specify this section as the default is always `0`
|
||||||
* `force.commit`: allows you to set commit hash from which the calculations should start
|
* `force.commit`: allows you to set commit hash from which the calculations should start
|
||||||
* `blacklist`: terms to ignore when processing commits. Any commit containing these terms will be skipped in version calculations. Useful for ignoring merge commits, feature branch names, and other unwanted triggers.
|
* `blacklist`: terms to ignore when processing commits. Any commit containing these terms will be skipped in version calculations. Useful for ignoring merge commits, feature branch names, and other unwanted triggers.
|
||||||
|
* `tag_prefixes`: prefixes to strip from existing tags before parsing version numbers. Useful for monorepos where tags are prefixed with component names (e.g., `app-1.2.3`, `infra-0.5.0`). The `v` prefix is always stripped automatically.
|
||||||
* `wording`: words the program should look for in the git commits to increment (patch|minor|major)
|
* `wording`: words the program should look for in the git commits to increment (patch|minor|major)
|
||||||
|
|
||||||
### Good to know
|
### Good to knows
|
||||||
|
|
||||||
* Word matching uses fuzzy search AND is case INSENSITIVE
|
* Word matching uses fuzzy search AND is case INSENSITIVE
|
||||||
* I do not recommend using common words ( like "the" from the example configuration )
|
* I do not recommend using common words ( like "the" from the example configuration )
|
||||||
* You can specify env variable `LOG_LEVEL=debug` to see what exactly happens during the calculations
|
* You can specify env variable `LOG_LEVEL=debug` to see what exactly happens during the calculations
|
||||||
|
|
||||||
|
### Telemetry
|
||||||
|
|
||||||
|
On startup this binary sends a single anonymous adoption ping — project name,
|
||||||
|
version, timestamp; no identifiers, no commit content, no repository data.
|
||||||
|
Fire-and-forget with a 2-second timeout; cannot block startup or panic.
|
||||||
|
|
||||||
|
See **[oss-telemetry — Disabling telemetry](https://github.com/lukaszraczylo/oss-telemetry#disabling-telemetry)**
|
||||||
|
for the exact wire format, source, and full opt-out documentation.
|
||||||
|
|
||||||
|
Quick opt-out: set any of `DO_NOT_TRACK=1`, `OSS_TELEMETRY_DISABLED=1`,
|
||||||
|
or `SEMVER_GENERATOR_DISABLE_TELEMETRY=1`.
|
||||||
|
|||||||
+1
-1
@@ -36,4 +36,4 @@ outputs:
|
|||||||
description: "Calculated semantic version"
|
description: "Calculated semantic version"
|
||||||
runs:
|
runs:
|
||||||
using: "docker"
|
using: "docker"
|
||||||
image: "docker://ghcr.io/lukaszraczylo/semver-generator:latest"
|
image: "docker://ghcr.io/lukaszraczylo/semver-generator:1.17.3"
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/lukaszraczylo/semver-generator/cmd/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
// These functions are now in the utils package
|
|
||||||
// They are kept here as stubs for backward compatibility
|
|
||||||
|
|
||||||
func updatePackage() bool {
|
|
||||||
return utils.UpdatePackage()
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkLatestRelease() (string, bool) {
|
|
||||||
return utils.CheckLatestRelease()
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/lukaszraczylo/semver-generator/cmd/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_checkLatestRelease(t *testing.T) {
|
|
||||||
utils.InitLogger(true)
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
want string
|
|
||||||
want1 bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Check latest release",
|
|
||||||
want1: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
_, got1 := checkLatestRelease()
|
|
||||||
if got1 != tt.want1 {
|
|
||||||
t.Errorf("checkLatestRelease() got1 = %v, want %v", got1, tt.want1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_updatePackage(t *testing.T) {
|
|
||||||
utils.InitLogger(true)
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("Skipping test in short / CI mode")
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Run autoupdater",
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if got := updatePackage(); got != tt.want {
|
|
||||||
t.Errorf("updatePackage() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+7
-2
@@ -121,11 +121,15 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List commits
|
// List commits
|
||||||
utils.ListCommits(&repo.GitRepo)
|
if _, err := utils.ListCommits(&repo.GitRepo); err != nil {
|
||||||
|
utils.Error("Unable to list commits", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// List existing tags if needed
|
// List existing tags if needed
|
||||||
if params.varExisting || repo.Config.Force.Existing {
|
if params.varExisting || repo.Config.Force.Existing {
|
||||||
utils.ListExistingTags(&repo.GitRepo)
|
utils.ListExistingTags(&repo.GitRepo, repo.Config.TagPrefixes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply forced versioning
|
// Apply forced versioning
|
||||||
@@ -140,6 +144,7 @@ func main() {
|
|||||||
repo.Semver,
|
repo.Semver,
|
||||||
params.varExisting || repo.Config.Force.Existing,
|
params.varExisting || repo.Config.Force.Existing,
|
||||||
params.varStrict || repo.Config.Force.Strict,
|
params.varStrict || repo.Config.Force.Strict,
|
||||||
|
repo.Config.TagPrefixes,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Print semantic version
|
// Print semantic version
|
||||||
|
|||||||
+39
-18
@@ -267,7 +267,7 @@ func (suite *Tests) Test_checkMatches() {
|
|||||||
if tt.name == "No match" {
|
if tt.name == "No match" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// For other test cases, match if the needle is in the haystack
|
// For other test cases, match if the needle is in the haystack
|
||||||
for _, h := range haystack {
|
for _, h := range haystack {
|
||||||
if strings.Contains(h, needle) || strings.Contains(needle, h) {
|
if strings.Contains(h, needle) || strings.Contains(needle, h) {
|
||||||
@@ -276,7 +276,7 @@ func (suite *Tests) Test_checkMatches() {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
got := utils.CheckMatches(tt.args.content, tt.args.targets, tt.blacklist)
|
got := utils.CheckMatches(tt.args.content, tt.args.targets, tt.blacklist)
|
||||||
assertObj.Equal(tt.want, got, "Unexpected result in "+tt.name)
|
assertObj.Equal(tt.want, got, "Unexpected result in "+tt.name)
|
||||||
})
|
})
|
||||||
@@ -285,7 +285,8 @@ func (suite *Tests) Test_checkMatches() {
|
|||||||
|
|
||||||
func (suite *Tests) Test_parseExistingSemver() {
|
func (suite *Tests) Test_parseExistingSemver() {
|
||||||
type args struct {
|
type args struct {
|
||||||
tagName string
|
tagName string
|
||||||
|
prefixes []string
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -296,7 +297,8 @@ func (suite *Tests) Test_parseExistingSemver() {
|
|||||||
{
|
{
|
||||||
name: "Test parsing existing semver",
|
name: "Test parsing existing semver",
|
||||||
args: args{
|
args: args{
|
||||||
tagName: "1.2.3",
|
tagName: "1.2.3",
|
||||||
|
prefixes: []string{},
|
||||||
},
|
},
|
||||||
currentSemver: utils.SemVer{Major: 1, Minor: 1, Patch: 1},
|
currentSemver: utils.SemVer{Major: 1, Minor: 1, Patch: 1},
|
||||||
wantSemanticVersion: utils.SemVer{
|
wantSemanticVersion: utils.SemVer{
|
||||||
@@ -308,7 +310,8 @@ func (suite *Tests) Test_parseExistingSemver() {
|
|||||||
{
|
{
|
||||||
name: "Test parsing existing semver with v",
|
name: "Test parsing existing semver with v",
|
||||||
args: args{
|
args: args{
|
||||||
tagName: "v1.2.3",
|
tagName: "v1.2.3",
|
||||||
|
prefixes: []string{"v"},
|
||||||
},
|
},
|
||||||
currentSemver: utils.SemVer{Major: 1, Minor: 1, Patch: 1},
|
currentSemver: utils.SemVer{Major: 1, Minor: 1, Patch: 1},
|
||||||
wantSemanticVersion: utils.SemVer{
|
wantSemanticVersion: utils.SemVer{
|
||||||
@@ -320,7 +323,8 @@ func (suite *Tests) Test_parseExistingSemver() {
|
|||||||
{
|
{
|
||||||
name: "Test parsing existing semver with rc",
|
name: "Test parsing existing semver with rc",
|
||||||
args: args{
|
args: args{
|
||||||
tagName: "1.2.5-rc.7",
|
tagName: "1.2.5-rc.7",
|
||||||
|
prefixes: []string{},
|
||||||
},
|
},
|
||||||
currentSemver: utils.SemVer{Major: 1, Minor: 1, Patch: 1},
|
currentSemver: utils.SemVer{Major: 1, Minor: 1, Patch: 1},
|
||||||
wantSemanticVersion: utils.SemVer{
|
wantSemanticVersion: utils.SemVer{
|
||||||
@@ -331,10 +335,25 @@ func (suite *Tests) Test_parseExistingSemver() {
|
|||||||
EnableReleaseCandidate: true,
|
EnableReleaseCandidate: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Test parsing prefixed tag without rc",
|
||||||
|
args: args{
|
||||||
|
tagName: "app-0.0.16",
|
||||||
|
prefixes: []string{"app-", "infra-"},
|
||||||
|
},
|
||||||
|
currentSemver: utils.SemVer{Major: 1, Minor: 1, Patch: 1},
|
||||||
|
wantSemanticVersion: utils.SemVer{
|
||||||
|
Major: 0,
|
||||||
|
Minor: 0,
|
||||||
|
Patch: 16,
|
||||||
|
EnableReleaseCandidate: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Test invalid semver format",
|
name: "Test invalid semver format",
|
||||||
args: args{
|
args: args{
|
||||||
tagName: "invalid",
|
tagName: "invalid",
|
||||||
|
prefixes: []string{},
|
||||||
},
|
},
|
||||||
currentSemver: utils.SemVer{Major: 2, Minor: 3, Patch: 4},
|
currentSemver: utils.SemVer{Major: 2, Minor: 3, Patch: 4},
|
||||||
wantSemanticVersion: utils.SemVer{
|
wantSemanticVersion: utils.SemVer{
|
||||||
@@ -346,7 +365,8 @@ func (suite *Tests) Test_parseExistingSemver() {
|
|||||||
{
|
{
|
||||||
name: "Test partial semver",
|
name: "Test partial semver",
|
||||||
args: args{
|
args: args{
|
||||||
tagName: "1.2",
|
tagName: "1.2",
|
||||||
|
prefixes: []string{},
|
||||||
},
|
},
|
||||||
currentSemver: utils.SemVer{Major: 2, Minor: 3, Patch: 4},
|
currentSemver: utils.SemVer{Major: 2, Minor: 3, Patch: 4},
|
||||||
wantSemanticVersion: utils.SemVer{
|
wantSemanticVersion: utils.SemVer{
|
||||||
@@ -358,7 +378,8 @@ func (suite *Tests) Test_parseExistingSemver() {
|
|||||||
{
|
{
|
||||||
name: "Test empty tag",
|
name: "Test empty tag",
|
||||||
args: args{
|
args: args{
|
||||||
tagName: "",
|
tagName: "",
|
||||||
|
prefixes: []string{},
|
||||||
},
|
},
|
||||||
currentSemver: utils.SemVer{Major: 2, Minor: 3, Patch: 4},
|
currentSemver: utils.SemVer{Major: 2, Minor: 3, Patch: 4},
|
||||||
wantSemanticVersion: utils.SemVer{
|
wantSemanticVersion: utils.SemVer{
|
||||||
@@ -370,7 +391,7 @@ func (suite *Tests) Test_parseExistingSemver() {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
suite.T().Run(tt.name, func(t *testing.T) {
|
suite.T().Run(tt.name, func(t *testing.T) {
|
||||||
got := utils.ParseExistingSemver(tt.args.tagName, tt.currentSemver)
|
got := utils.ParseExistingSemver(tt.args.tagName, tt.currentSemver, tt.args.prefixes)
|
||||||
assertObj.Equal(tt.wantSemanticVersion.Major, got.Major, "Unexpected MAJOR semver result in "+tt.name)
|
assertObj.Equal(tt.wantSemanticVersion.Major, got.Major, "Unexpected MAJOR semver result in "+tt.name)
|
||||||
assertObj.Equal(tt.wantSemanticVersion.Minor, got.Minor, "Unexpected MINOR semver result in "+tt.name)
|
assertObj.Equal(tt.wantSemanticVersion.Minor, got.Minor, "Unexpected MINOR semver result in "+tt.name)
|
||||||
assertObj.Equal(tt.wantSemanticVersion.Patch, got.Patch, "Unexpected PATCH semver result in "+tt.name)
|
assertObj.Equal(tt.wantSemanticVersion.Patch, got.Patch, "Unexpected PATCH semver result in "+tt.name)
|
||||||
@@ -382,10 +403,10 @@ func (suite *Tests) Test_parseExistingSemver() {
|
|||||||
|
|
||||||
func (suite *Tests) TestSetup_ListCommits() {
|
func (suite *Tests) TestSetup_ListCommits() {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
RepositoryName string
|
RepositoryName string
|
||||||
RepositoryBranch string
|
RepositoryBranch string
|
||||||
LocalConfigFile string
|
LocalConfigFile string
|
||||||
GitRepo utils.GitRepository
|
GitRepo utils.GitRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@@ -441,23 +462,23 @@ func (suite *Tests) TestSetup_ListCommits() {
|
|||||||
if tt.name == "List commits from existing repository" {
|
if tt.name == "List commits from existing repository" {
|
||||||
t.Skip("Skipping test that requires repository access")
|
t.Skip("Skipping test that requires repository access")
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &Setup{
|
s := &Setup{
|
||||||
RepositoryName: tt.fields.RepositoryName,
|
RepositoryName: tt.fields.RepositoryName,
|
||||||
RepositoryBranch: tt.fields.RepositoryBranch,
|
RepositoryBranch: tt.fields.RepositoryBranch,
|
||||||
GitRepo: tt.fields.GitRepo,
|
GitRepo: tt.fields.GitRepo,
|
||||||
}
|
}
|
||||||
|
|
||||||
config, _ := utils.ReadConfig(tt.fields.LocalConfigFile)
|
config, _ := utils.ReadConfig(tt.fields.LocalConfigFile)
|
||||||
s.Config = config
|
s.Config = config
|
||||||
|
|
||||||
err := utils.PrepareRepository(&s.GitRepo)
|
err := utils.PrepareRepository(&s.GitRepo)
|
||||||
if err != nil && !tt.wantErr {
|
if err != nil && !tt.wantErr {
|
||||||
if tt.name != "List commits starting with certain hash" {
|
if tt.name != "List commits starting with certain hash" {
|
||||||
t.Fatalf("Failed to prepare repository: %v", err)
|
t.Fatalf("Failed to prepare repository: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
listOfCommits, err := utils.ListCommits(&s.GitRepo)
|
listOfCommits, err := utils.ListCommits(&s.GitRepo)
|
||||||
if !tt.wantErr {
|
if !tt.wantErr {
|
||||||
|
|||||||
+3
-3
@@ -30,13 +30,13 @@ func TestExecute(t *testing.T) {
|
|||||||
Short: "Test command",
|
Short: "Test command",
|
||||||
Run: func(cmd *cobra.Command, args []string) {},
|
Run: func(cmd *cobra.Command, args []string) {},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all the required flags to the test command
|
// Add all the required flags to the test command
|
||||||
testCmd.Flags().Bool("version", false, "Print version information")
|
testCmd.Flags().Bool("version", false, "Print version information")
|
||||||
testCmd.Flags().String("repository", "test-repo", "Repository URL")
|
testCmd.Flags().String("repository", "test-repo", "Repository URL")
|
||||||
testCmd.Flags().String("branch", "test-branch", "Repository branch")
|
testCmd.Flags().String("branch", "test-branch", "Repository branch")
|
||||||
testCmd.Flags().String("config", "test-config", "Config file path")
|
testCmd.Flags().String("config", "test-config", "Config file path")
|
||||||
|
|
||||||
rootCmd = testCmd
|
rootCmd = testCmd
|
||||||
|
|
||||||
// Execute should not panic
|
// Execute should not panic
|
||||||
@@ -82,4 +82,4 @@ func TestSetupCobra(t *testing.T) {
|
|||||||
assertions.Equal(t, "test-branch", testRepo.RepositoryBranch, "Repository branch should be set")
|
assertions.Equal(t, "test-branch", testRepo.RepositoryBranch, "Repository branch should be set")
|
||||||
assertions.Equal(t, "test-config", testRepo.LocalConfigFile, "Config file should be set")
|
assertions.Equal(t, "test-config", testRepo.LocalConfigFile, "Config file should be set")
|
||||||
assertions.True(t, testRepo.UseLocal, "UseLocal should be set to true")
|
assertions.True(t, testRepo.UseLocal, "UseLocal should be set to true")
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-12
@@ -26,26 +26,36 @@ type Force struct {
|
|||||||
|
|
||||||
// Config represents the application configuration
|
// Config represents the application configuration
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Wording Wording
|
Wording Wording
|
||||||
Force Force
|
Force Force
|
||||||
Blacklist []string
|
Blacklist []string
|
||||||
|
TagPrefixes []string // Prefixes to strip from tags before parsing (e.g., "app-", "infra-", "v")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadConfig reads the configuration from a file
|
// ReadConfig reads the configuration from a file
|
||||||
func ReadConfig(file string) (*Config, error) {
|
func ReadConfig(file string) (*Config, error) {
|
||||||
config := &Config{}
|
config := &Config{}
|
||||||
|
|
||||||
viper.SetConfigFile(file)
|
viper.SetConfigFile(file)
|
||||||
err := viper.ReadInConfig()
|
err := viper.ReadInConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("fatal error config file: %s", err)
|
err = fmt.Errorf("fatal error config file: %s", err)
|
||||||
return config, err
|
return config, err
|
||||||
}
|
}
|
||||||
|
|
||||||
viper.UnmarshalKey("wording", &config.Wording)
|
if err := viper.UnmarshalKey("wording", &config.Wording); err != nil {
|
||||||
viper.UnmarshalKey("force", &config.Force)
|
return config, fmt.Errorf("error parsing wording config: %w", err)
|
||||||
viper.UnmarshalKey("blacklist", &config.Blacklist)
|
}
|
||||||
|
if err := viper.UnmarshalKey("force", &config.Force); err != nil {
|
||||||
|
return config, fmt.Errorf("error parsing force config: %w", err)
|
||||||
|
}
|
||||||
|
if err := viper.UnmarshalKey("blacklist", &config.Blacklist); err != nil {
|
||||||
|
return config, fmt.Errorf("error parsing blacklist config: %w", err)
|
||||||
|
}
|
||||||
|
if err := viper.UnmarshalKey("tag_prefixes", &config.TagPrefixes); err != nil {
|
||||||
|
return config, fmt.Errorf("error parsing tag_prefixes config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,14 +65,14 @@ func ApplyForcedVersioning(force Force, semver *SemVer) {
|
|||||||
Debug("Forced versioning (MAJOR)", map[string]interface{}{"major": force.Major})
|
Debug("Forced versioning (MAJOR)", map[string]interface{}{"major": force.Major})
|
||||||
semver.Major = force.Major
|
semver.Major = force.Major
|
||||||
}
|
}
|
||||||
|
|
||||||
if force.Minor > 0 {
|
if force.Minor > 0 {
|
||||||
Debug("Forced versioning (MINOR)", map[string]interface{}{"minor": force.Minor})
|
Debug("Forced versioning (MINOR)", map[string]interface{}{"minor": force.Minor})
|
||||||
semver.Minor = force.Minor
|
semver.Minor = force.Minor
|
||||||
}
|
}
|
||||||
|
|
||||||
if force.Patch > 0 {
|
if force.Patch > 0 {
|
||||||
Debug("Forced versioning (PATCH)", map[string]interface{}{"patch": force.Patch})
|
Debug("Forced versioning (PATCH)", map[string]interface{}{"patch": force.Patch})
|
||||||
semver.Patch = force.Patch
|
semver.Patch = force.Patch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,4 +198,4 @@ wording:
|
|||||||
// Test reading a non-existent config
|
// Test reading a non-existent config
|
||||||
_, err = ReadConfig("non-existent-file.yaml")
|
_, err = ReadConfig("non-existent-file.yaml")
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-39
@@ -29,14 +29,14 @@ type TagDetails struct {
|
|||||||
|
|
||||||
// GitRepository represents a git repository
|
// GitRepository represents a git repository
|
||||||
type GitRepository struct {
|
type GitRepository struct {
|
||||||
Handler *git.Repository
|
Handler *git.Repository
|
||||||
Name string
|
Name string
|
||||||
Branch string
|
Branch string
|
||||||
LocalPath string
|
LocalPath string
|
||||||
UseLocal bool
|
UseLocal bool
|
||||||
Commits []CommitDetails
|
Commits []CommitDetails
|
||||||
Tags []TagDetails
|
Tags []TagDetails
|
||||||
StartCommit string
|
StartCommit string
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareRepository prepares the git repository for use
|
// PrepareRepository prepares the git repository for use
|
||||||
@@ -47,15 +47,15 @@ func PrepareRepository(repo *GitRepository) error {
|
|||||||
u, err := url.Parse(repo.Name)
|
u, err := url.Parse(repo.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error("Unable to parse repository URL", map[string]interface{}{
|
Error("Unable to parse repository URL", map[string]interface{}{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
"url": repo.Name,
|
"url": repo.Name,
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.LocalPath = fmt.Sprintf("/tmp/semver/%s/%s", u.Path, repo.Branch)
|
repo.LocalPath = fmt.Sprintf("/tmp/semver/%s/%s", u.Path, repo.Branch)
|
||||||
os.RemoveAll(repo.LocalPath)
|
_ = os.RemoveAll(repo.LocalPath) // Ignore error - directory may not exist
|
||||||
|
|
||||||
repo.Handler, err = git.PlainClone(repo.LocalPath, false, &git.CloneOptions{
|
repo.Handler, err = git.PlainClone(repo.LocalPath, false, &git.CloneOptions{
|
||||||
URL: repo.Name,
|
URL: repo.Name,
|
||||||
ReferenceName: plumbing.NewBranchReferenceName(repo.Branch),
|
ReferenceName: plumbing.NewBranchReferenceName(repo.Branch),
|
||||||
@@ -66,11 +66,11 @@ func PrepareRepository(repo *GitRepository) error {
|
|||||||
},
|
},
|
||||||
Tags: git.AllTags,
|
Tags: git.AllTags,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error("Unable to clone repository", map[string]interface{}{
|
Error("Unable to clone repository", map[string]interface{}{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
"url": repo.Name,
|
"url": repo.Name,
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -79,14 +79,20 @@ func PrepareRepository(repo *GitRepository) error {
|
|||||||
repo.Handler, err = git.PlainOpen(repo.LocalPath)
|
repo.Handler, err = git.PlainOpen(repo.LocalPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error("Unable to open local repository", map[string]interface{}{
|
Error("Unable to open local repository", map[string]interface{}{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
"path": repo.LocalPath,
|
"path": repo.LocalPath,
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Chdir(repo.LocalPath)
|
if err := os.Chdir(repo.LocalPath); err != nil {
|
||||||
|
Error("Unable to change directory", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"path": repo.LocalPath,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,14 +111,14 @@ func ListCommits(repo *GitRepository) ([]CommitDetails, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return []CommitDetails{}, err
|
return []CommitDetails{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
commitsList, err := repo.Handler.Log(&git.LogOptions{From: ref.Hash()})
|
commitsList, err := repo.Handler.Log(&git.LogOptions{From: ref.Hash()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []CommitDetails{}, err
|
return []CommitDetails{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var tmpResults []CommitDetails
|
var tmpResults []CommitDetails
|
||||||
commitsList.ForEach(func(c *object.Commit) error {
|
if err := commitsList.ForEach(func(c *object.Commit) error {
|
||||||
tmpResults = append(tmpResults, CommitDetails{
|
tmpResults = append(tmpResults, CommitDetails{
|
||||||
Hash: c.Hash.String(),
|
Hash: c.Hash.String(),
|
||||||
Author: c.Author.String(),
|
Author: c.Author.String(),
|
||||||
@@ -123,22 +129,31 @@ func ListCommits(repo *GitRepository) ([]CommitDetails, error) {
|
|||||||
return tmpResults[i].Timestamp.Unix() < tmpResults[j].Timestamp.Unix()
|
return tmpResults[i].Timestamp.Unix() < tmpResults[j].Timestamp.Unix()
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
return []CommitDetails{}, err
|
||||||
|
}
|
||||||
|
|
||||||
Debug("Listing commits", map[string]interface{}{"commits": tmpResults})
|
Debug("Listing commits", map[string]interface{}{"commits": tmpResults})
|
||||||
|
|
||||||
// Filter commits starting from the specified commit if provided
|
// Filter commits starting after the specified commit if provided
|
||||||
if repo.StartCommit != "" {
|
if repo.StartCommit != "" {
|
||||||
|
found := false
|
||||||
for commitId, cmt := range tmpResults {
|
for commitId, cmt := range tmpResults {
|
||||||
if cmt.Hash == repo.StartCommit {
|
if cmt.Hash == repo.StartCommit {
|
||||||
Debug("Found commit match", map[string]interface{}{
|
Debug("Found commit match", map[string]interface{}{
|
||||||
"commit": cmt.Hash,
|
"commit": cmt.Hash,
|
||||||
"index": commitId,
|
"index": commitId,
|
||||||
})
|
})
|
||||||
repo.Commits = tmpResults[commitId:]
|
// Start from the commit AFTER the specified one
|
||||||
|
repo.Commits = tmpResults[commitId+1:]
|
||||||
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !found {
|
||||||
|
// If specified commit not found, use all commits
|
||||||
|
repo.Commits = tmpResults
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
repo.Commits = tmpResults
|
repo.Commits = tmpResults
|
||||||
}
|
}
|
||||||
@@ -148,34 +163,50 @@ func ListCommits(repo *GitRepository) ([]CommitDetails, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListExistingTags lists all tags in the repository
|
// ListExistingTags lists all tags in the repository
|
||||||
func ListExistingTags(repo *GitRepository) {
|
// ListExistingTags lists all tags in the repository.
|
||||||
|
// Tags that don't parse as proper semver (rolling tags like "v1" or "latest")
|
||||||
|
// are skipped so they can't out-rank real semver tags pointing to the same
|
||||||
|
// commit during latest-tag selection.
|
||||||
|
func ListExistingTags(repo *GitRepository, tagPrefixes []string) {
|
||||||
Debug("Listing existing tags", nil)
|
Debug("Listing existing tags", nil)
|
||||||
|
|
||||||
// Check if Handler is nil to avoid panic
|
|
||||||
if repo.Handler == nil {
|
if repo.Handler == nil {
|
||||||
Debug("Repository handler is nil, skipping tag listing", nil)
|
Debug("Repository handler is nil, skipping tag listing", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
refs, err := repo.Handler.Tags()
|
refs, err := repo.Handler.Tags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error("Unable to list tags", map[string]interface{}{"error": err.Error()})
|
Error("Unable to list tags", map[string]interface{}{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := refs.ForEach(func(ref *plumbing.Reference) error {
|
if err := refs.ForEach(func(ref *plumbing.Reference) error {
|
||||||
|
tagName := ref.Name().Short()
|
||||||
|
|
||||||
|
if !IsParseableSemverTag(tagName, tagPrefixes) {
|
||||||
|
Debug("Skipping non-semver tag", map[string]interface{}{"tag": tagName})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
commitHash := ref.Hash().String()
|
||||||
|
tagObj, err := repo.Handler.TagObject(ref.Hash())
|
||||||
|
if err == nil {
|
||||||
|
commitHash = tagObj.Target.String()
|
||||||
|
}
|
||||||
|
|
||||||
repo.Tags = append(repo.Tags, TagDetails{
|
repo.Tags = append(repo.Tags, TagDetails{
|
||||||
Name: ref.Name().Short(),
|
Name: tagName,
|
||||||
Hash: ref.Hash().String(),
|
Hash: commitHash,
|
||||||
})
|
})
|
||||||
|
|
||||||
Debug("Found tag", map[string]interface{}{
|
Debug("Found tag", map[string]interface{}{
|
||||||
"tag": ref.Name().Short(),
|
"tag": tagName,
|
||||||
"hash": ref.Hash().String(),
|
"hash": commitHash,
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
Error("Error iterating tags", map[string]interface{}{"error": err.Error()})
|
Error("Error iterating tags", map[string]interface{}{"error": err.Error()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-14
@@ -64,7 +64,7 @@ func TestListCommits(t *testing.T) {
|
|||||||
t.Run("Test commit filtering logic", func(t *testing.T) {
|
t.Run("Test commit filtering logic", func(t *testing.T) {
|
||||||
// Create a test repository with predefined commits
|
// Create a test repository with predefined commits
|
||||||
repo := &GitRepository{}
|
repo := &GitRepository{}
|
||||||
|
|
||||||
// Manually populate the commits for testing
|
// Manually populate the commits for testing
|
||||||
repo.Commits = []CommitDetails{
|
repo.Commits = []CommitDetails{
|
||||||
{
|
{
|
||||||
@@ -83,7 +83,7 @@ func TestListCommits(t *testing.T) {
|
|||||||
|
|
||||||
// Test with StartCommit specified
|
// Test with StartCommit specified
|
||||||
repo.StartCommit = "def456"
|
repo.StartCommit = "def456"
|
||||||
|
|
||||||
// Instead of calling ListCommits which would try to use the nil Handler,
|
// Instead of calling ListCommits which would try to use the nil Handler,
|
||||||
// we'll just test the filtering logic directly
|
// we'll just test the filtering logic directly
|
||||||
if repo.StartCommit != "" {
|
if repo.StartCommit != "" {
|
||||||
@@ -94,19 +94,19 @@ func TestListCommits(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the filtering worked correctly
|
// Verify the filtering worked correctly
|
||||||
assert.Len(t, repo.Commits, 1, "Should filter commits starting from specified hash")
|
assert.Len(t, repo.Commits, 1, "Should filter commits starting from specified hash")
|
||||||
assert.Equal(t, "def456", repo.Commits[0].Hash, "Commit hash should match")
|
assert.Equal(t, "def456", repo.Commits[0].Hash, "Commit hash should match")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Test with nil Handler", func(t *testing.T) {
|
t.Run("Test with nil Handler", func(t *testing.T) {
|
||||||
// Create a test repository with nil Handler
|
// Create a test repository with nil Handler
|
||||||
repo := &GitRepository{}
|
repo := &GitRepository{}
|
||||||
|
|
||||||
// Now we can safely call ListCommits since we've added a nil check
|
// Now we can safely call ListCommits since we've added a nil check
|
||||||
commits, err := ListCommits(repo)
|
commits, err := ListCommits(repo)
|
||||||
|
|
||||||
// Verify the function returns without error
|
// Verify the function returns without error
|
||||||
assert.NoError(t, err, "Should not error with nil Handler")
|
assert.NoError(t, err, "Should not error with nil Handler")
|
||||||
assert.Empty(t, commits, "Should return empty commits with nil Handler")
|
assert.Empty(t, commits, "Should return empty commits with nil Handler")
|
||||||
@@ -120,10 +120,10 @@ func TestListExistingTags(t *testing.T) {
|
|||||||
t.Run("Test tag processing", func(t *testing.T) {
|
t.Run("Test tag processing", func(t *testing.T) {
|
||||||
// Create a test repository
|
// Create a test repository
|
||||||
repo := &GitRepository{}
|
repo := &GitRepository{}
|
||||||
|
|
||||||
// Since we can't test the actual git operations, we'll test the function's behavior
|
// Since we can't test the actual git operations, we'll test the function's behavior
|
||||||
// by manually setting up the repository state
|
// by manually setting up the repository state
|
||||||
|
|
||||||
// Manually add tags to verify they're processed correctly
|
// Manually add tags to verify they're processed correctly
|
||||||
repo.Tags = []TagDetails{
|
repo.Tags = []TagDetails{
|
||||||
{
|
{
|
||||||
@@ -131,20 +131,20 @@ func TestListExistingTags(t *testing.T) {
|
|||||||
Hash: "abc123",
|
Hash: "abc123",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Len(t, repo.Tags, 1, "Should have 1 tag")
|
assert.Len(t, repo.Tags, 1, "Should have 1 tag")
|
||||||
assert.Equal(t, "v1.0.0", repo.Tags[0].Name, "Tag name should match")
|
assert.Equal(t, "v1.0.0", repo.Tags[0].Name, "Tag name should match")
|
||||||
assert.Equal(t, "abc123", repo.Tags[0].Hash, "Tag hash should match")
|
assert.Equal(t, "abc123", repo.Tags[0].Hash, "Tag hash should match")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Test with nil Handler", func(t *testing.T) {
|
t.Run("Test with nil Handler", func(t *testing.T) {
|
||||||
// Create a test repository with nil Handler
|
// Create a test repository with nil Handler
|
||||||
repo := &GitRepository{}
|
repo := &GitRepository{}
|
||||||
|
|
||||||
// Now we can safely call ListExistingTags since we've added a nil check
|
// Now we can safely call ListExistingTags since we've added a nil check
|
||||||
ListExistingTags(repo)
|
ListExistingTags(repo, nil)
|
||||||
|
|
||||||
// Verify no tags were added
|
// Verify no tags were added
|
||||||
assert.Empty(t, repo.Tags, "Should have no tags after calling with nil Handler")
|
assert.Empty(t, repo.Tags, "Should have no tags after calling with nil Handler")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-89
@@ -34,14 +34,6 @@ type ReleaseAsset struct {
|
|||||||
BrowserDownloadURL string `json:"browser_download_url"`
|
BrowserDownloadURL string `json:"browser_download_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateInfo contains information about an available update
|
|
||||||
type UpdateInfo struct {
|
|
||||||
CurrentVersion string
|
|
||||||
LatestVersion string
|
|
||||||
ReleaseURL string
|
|
||||||
DownloadURL string
|
|
||||||
}
|
|
||||||
|
|
||||||
// httpClient is the HTTP client used for requests (allows mocking in tests)
|
// httpClient is the HTTP client used for requests (allows mocking in tests)
|
||||||
var httpClient = &http.Client{
|
var httpClient = &http.Client{
|
||||||
Timeout: requestTimeout,
|
Timeout: requestTimeout,
|
||||||
@@ -60,30 +52,6 @@ func CheckLatestRelease() (string, bool) {
|
|||||||
return version, true
|
return version, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckForUpdate checks if a newer version is available
|
|
||||||
// Returns UpdateInfo if an update is available, nil otherwise
|
|
||||||
func CheckForUpdate(currentVersion string) *UpdateInfo {
|
|
||||||
release, err := fetchLatestRelease(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
latestVersion := normalizeVersion(release.TagName)
|
|
||||||
current := normalizeVersion(currentVersion)
|
|
||||||
|
|
||||||
if isNewerVersion(latestVersion, current) {
|
|
||||||
downloadURL := findBinaryAsset(release.Assets)
|
|
||||||
return &UpdateInfo{
|
|
||||||
CurrentVersion: current,
|
|
||||||
LatestVersion: latestVersion,
|
|
||||||
ReleaseURL: release.HTMLURL,
|
|
||||||
DownloadURL: downloadURL,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdatePackage downloads and installs the latest version
|
// UpdatePackage downloads and installs the latest version
|
||||||
func UpdatePackage() bool {
|
func UpdatePackage() bool {
|
||||||
Info("Checking for updates", nil)
|
Info("Checking for updates", nil)
|
||||||
@@ -209,7 +177,7 @@ func downloadBinary(url string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create temp file
|
// Create temp file
|
||||||
tempFile, err := os.CreateTemp("", "semver-gen-update-*")
|
tempFile, err := os.CreateTemp("", "semver-generator-update-*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -219,30 +187,33 @@ func downloadBinary(url string) (string, error) {
|
|||||||
if strings.HasSuffix(url, ".tar.gz") {
|
if strings.HasSuffix(url, ".tar.gz") {
|
||||||
// For tar.gz, we need to extract the binary
|
// For tar.gz, we need to extract the binary
|
||||||
if err := extractTarGz(resp.Body, tempFile); err != nil {
|
if err := extractTarGz(resp.Body, tempFile); err != nil {
|
||||||
tempFile.Close()
|
_ = tempFile.Close()
|
||||||
os.Remove(tempPath)
|
_ = os.Remove(tempPath)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Direct binary download
|
// Direct binary download
|
||||||
if _, err := io.Copy(tempFile, resp.Body); err != nil {
|
if _, err := io.Copy(tempFile, resp.Body); err != nil {
|
||||||
tempFile.Close()
|
_ = tempFile.Close()
|
||||||
os.Remove(tempPath)
|
_ = os.Remove(tempPath)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tempFile.Close()
|
if err := tempFile.Close(); err != nil {
|
||||||
|
_ = os.Remove(tempPath)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
return tempPath, nil
|
return tempPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractTarGz extracts the semver-gen binary from a tar.gz archive
|
// extractTarGz extracts the semver-generator binary from a tar.gz archive
|
||||||
func extractTarGz(r io.Reader, destFile *os.File) error {
|
func extractTarGz(r io.Reader, destFile *os.File) error {
|
||||||
// For simplicity, we'll download the whole archive to a temp file first,
|
// For simplicity, we'll download the whole archive to a temp file first,
|
||||||
// then use tar command to extract. This avoids adding archive/tar dependency.
|
// then use tar command to extract. This avoids adding archive/tar dependency.
|
||||||
|
|
||||||
// Create temp archive file
|
// Create temp archive file
|
||||||
archiveFile, err := os.CreateTemp("", "semver-gen-archive-*.tar.gz")
|
archiveFile, err := os.CreateTemp("", "semver-generator-archive-*.tar.gz")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -250,13 +221,15 @@ func extractTarGz(r io.Reader, destFile *os.File) error {
|
|||||||
defer os.Remove(archivePath)
|
defer os.Remove(archivePath)
|
||||||
|
|
||||||
if _, err := io.Copy(archiveFile, r); err != nil {
|
if _, err := io.Copy(archiveFile, r); err != nil {
|
||||||
archiveFile.Close()
|
_ = archiveFile.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := archiveFile.Close(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
archiveFile.Close()
|
|
||||||
|
|
||||||
// Extract using tar command
|
// Extract using tar command
|
||||||
extractDir, err := os.MkdirTemp("", "semver-gen-extract-*")
|
extractDir, err := os.MkdirTemp("", "semver-generator-extract-*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -268,22 +241,34 @@ func extractTarGz(r io.Reader, destFile *os.File) error {
|
|||||||
return fmt.Errorf("failed to extract archive: %w", err)
|
return fmt.Errorf("failed to extract archive: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the semver-gen binary in the extracted files
|
// Find the binary in the extracted files
|
||||||
|
// Support both new name (semver-generator) and old name (semver-gen) for backwards compatibility
|
||||||
binaryPath := ""
|
binaryPath := ""
|
||||||
entries, err := os.ReadDir(extractDir)
|
entries, err := os.ReadDir(extractDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First try to find semver-generator (new name)
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if entry.Name() == "semver-gen" || strings.HasPrefix(entry.Name(), "semver-gen") && !strings.Contains(entry.Name(), ".") {
|
if entry.Name() == "semver-generator" {
|
||||||
binaryPath = fmt.Sprintf("%s/%s", extractDir, entry.Name())
|
binaryPath = fmt.Sprintf("%s/%s", extractDir, entry.Name())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback to semver-gen (old name) for older releases
|
||||||
if binaryPath == "" {
|
if binaryPath == "" {
|
||||||
return fmt.Errorf("semver-gen binary not found in archive")
|
for _, entry := range entries {
|
||||||
|
if entry.Name() == "semver-gen" {
|
||||||
|
binaryPath = fmt.Sprintf("%s/%s", extractDir, entry.Name())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if binaryPath == "" {
|
||||||
|
return fmt.Errorf("binary not found in archive (looked for semver-generator and semver-gen)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the binary to the destination
|
// Copy the binary to the destination
|
||||||
@@ -324,6 +309,7 @@ var runCommandFunc = func(cmdStr string) error {
|
|||||||
// replaceBinary replaces the current binary with the new one
|
// replaceBinary replaces the current binary with the new one
|
||||||
func replaceBinary(newBinary, currentBinary string) error {
|
func replaceBinary(newBinary, currentBinary string) error {
|
||||||
// Make the new binary executable
|
// Make the new binary executable
|
||||||
|
// #nosec G302 -- 0755 is required for executable binaries
|
||||||
if err := os.Chmod(newBinary, 0755); err != nil {
|
if err := os.Chmod(newBinary, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -338,13 +324,17 @@ func replaceBinary(newBinary, currentBinary string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// copyFile copies a file from src to dst
|
// copyFile copies a file from src to dst
|
||||||
|
// Note: This function is only called internally with controlled paths from
|
||||||
|
// os.CreateTemp and os.Executable, not with user-supplied paths.
|
||||||
func copyFile(src, dst string) error {
|
func copyFile(src, dst string) error {
|
||||||
|
// #nosec G304 -- src is from os.CreateTemp, not user input
|
||||||
srcFile, err := os.Open(src)
|
srcFile, err := os.Open(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer srcFile.Close()
|
defer srcFile.Close()
|
||||||
|
|
||||||
|
// #nosec G304 -- dst is from os.Executable, not user input
|
||||||
dstFile, err := os.Create(dst)
|
dstFile, err := os.Create(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -356,6 +346,7 @@ func copyFile(src, dst string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make executable
|
// Make executable
|
||||||
|
// #nosec G302 -- 0755 is required for executable binaries
|
||||||
return os.Chmod(dst, 0755)
|
return os.Chmod(dst, 0755)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,46 +357,3 @@ func normalizeVersion(v string) string {
|
|||||||
v = strings.TrimPrefix(v, "V")
|
v = strings.TrimPrefix(v, "V")
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// isNewerVersion compares two semver-like versions
|
|
||||||
// Returns true if latest is newer than current
|
|
||||||
func isNewerVersion(latest, current string) bool {
|
|
||||||
latestParts := parseVersionParts(latest)
|
|
||||||
currentParts := parseVersionParts(current)
|
|
||||||
|
|
||||||
for i := 0; i < len(latestParts) && i < len(currentParts); i++ {
|
|
||||||
if latestParts[i] > currentParts[i] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if latestParts[i] < currentParts[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return len(latestParts) > len(currentParts)
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseVersionParts splits a version string into numeric parts
|
|
||||||
func parseVersionParts(v string) []int {
|
|
||||||
// Remove any suffix like -beta, -rc1, etc.
|
|
||||||
if idx := strings.IndexAny(v, "-+"); idx != -1 {
|
|
||||||
v = v[:idx]
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(v, ".")
|
|
||||||
result := make([]int, 0, len(parts))
|
|
||||||
|
|
||||||
for _, p := range parts {
|
|
||||||
var num int
|
|
||||||
fmt.Sscanf(p, "%d", &num)
|
|
||||||
result = append(result, num)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatUpdateMessage formats a user-friendly update notification
|
|
||||||
func (u *UpdateInfo) FormatUpdateMessage() string {
|
|
||||||
return fmt.Sprintf("New version available: %s (current: %s) - %s",
|
|
||||||
u.LatestVersion, u.CurrentVersion, u.ReleaseURL)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -30,57 +30,6 @@ func TestNormalizeVersion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseVersionParts(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
input string
|
|
||||||
expected []int
|
|
||||||
}{
|
|
||||||
{"1.0.0", []int{1, 0, 0}},
|
|
||||||
{"2.1.3", []int{2, 1, 3}},
|
|
||||||
{"1.0", []int{1, 0}},
|
|
||||||
{"10.20.30", []int{10, 20, 30}},
|
|
||||||
{"1.0.0-beta", []int{1, 0, 0}},
|
|
||||||
{"1.0.0-rc1", []int{1, 0, 0}},
|
|
||||||
{"1.0.0+build123", []int{1, 0, 0}},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.input, func(t *testing.T) {
|
|
||||||
result := parseVersionParts(tt.input)
|
|
||||||
assert.Equal(t, tt.expected, result)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsNewerVersion(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
latest string
|
|
||||||
current string
|
|
||||||
expected bool
|
|
||||||
}{
|
|
||||||
{"major version bump", "2.0.0", "1.0.0", true},
|
|
||||||
{"minor version bump", "1.1.0", "1.0.0", true},
|
|
||||||
{"patch version bump", "1.0.1", "1.0.0", true},
|
|
||||||
{"same version", "1.0.0", "1.0.0", false},
|
|
||||||
{"current is newer major", "1.0.0", "2.0.0", false},
|
|
||||||
{"current is newer minor", "1.0.0", "1.1.0", false},
|
|
||||||
{"current is newer patch", "1.0.0", "1.0.1", false},
|
|
||||||
{"multi-digit versions", "1.10.0", "1.9.0", true},
|
|
||||||
{"longer version is newer", "1.0.1", "1.0", true},
|
|
||||||
{"shorter version is older", "1.0", "1.0.1", false},
|
|
||||||
{"complex comparison", "2.1.3", "2.1.2", true},
|
|
||||||
{"real world example", "0.2.0", "0.1.0", true},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
result := isNewerVersion(tt.latest, tt.current)
|
|
||||||
assert.Equal(t, tt.expected, result)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFindBinaryAsset(t *testing.T) {
|
func TestFindBinaryAsset(t *testing.T) {
|
||||||
assets := []ReleaseAsset{
|
assets := []ReleaseAsset{
|
||||||
{Name: "semver-gen-1.0.0-linux-amd64.tar.gz", BrowserDownloadURL: "https://example.com/linux-amd64.tar.gz"},
|
{Name: "semver-gen-1.0.0-linux-amd64.tar.gz", BrowserDownloadURL: "https://example.com/linux-amd64.tar.gz"},
|
||||||
@@ -102,19 +51,6 @@ func TestFindBinaryAssetEmpty(t *testing.T) {
|
|||||||
assert.Empty(t, url, "Should return empty string when no assets")
|
assert.Empty(t, url, "Should return empty string when no assets")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateInfo_FormatUpdateMessage(t *testing.T) {
|
|
||||||
info := &UpdateInfo{
|
|
||||||
CurrentVersion: "1.0.0",
|
|
||||||
LatestVersion: "2.0.0",
|
|
||||||
ReleaseURL: "https://github.com/lukaszraczylo/semver-generator/releases/tag/v2.0.0",
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := info.FormatUpdateMessage()
|
|
||||||
assert.Contains(t, msg, "2.0.0")
|
|
||||||
assert.Contains(t, msg, "1.0.0")
|
|
||||||
assert.Contains(t, msg, "https://github.com/lukaszraczylo/semver-generator/releases/tag/v2.0.0")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckLatestRelease(t *testing.T) {
|
func TestCheckLatestRelease(t *testing.T) {
|
||||||
// Initialize logger
|
// Initialize logger
|
||||||
InitLogger(false)
|
InitLogger(false)
|
||||||
@@ -141,22 +77,6 @@ func TestCheckLatestRelease(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckForUpdate(t *testing.T) {
|
|
||||||
InitLogger(false)
|
|
||||||
|
|
||||||
// Test with a very old version - should show update available if network works
|
|
||||||
info := CheckForUpdate("0.0.1")
|
|
||||||
// This will either return update info or nil depending on network
|
|
||||||
if info != nil {
|
|
||||||
assert.NotEmpty(t, info.LatestVersion)
|
|
||||||
assert.Equal(t, "0.0.1", info.CurrentVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test with a very new version - should not show update
|
|
||||||
info = CheckForUpdate("999.999.999")
|
|
||||||
assert.Nil(t, info, "Should not show update for future version")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFetchLatestReleaseError(t *testing.T) {
|
func TestFetchLatestReleaseError(t *testing.T) {
|
||||||
InitLogger(false)
|
InitLogger(false)
|
||||||
|
|
||||||
|
|||||||
@@ -56,4 +56,4 @@ func Critical(message string, pairs map[string]interface{}) {
|
|||||||
Pairs: pairs,
|
Pairs: pairs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInitLogger(t *testing.T) {
|
func TestInitLogger(t *testing.T) {
|
||||||
// Test with debug mode enabled
|
// Test with debug mode enabled
|
||||||
logger := InitLogger(true)
|
logger := InitLogger(true)
|
||||||
@@ -25,10 +26,10 @@ func TestLoggingFunctions(t *testing.T) {
|
|||||||
Debug("Debug message", map[string]interface{}{"key": "value"})
|
Debug("Debug message", map[string]interface{}{"key": "value"})
|
||||||
Info("Info message", map[string]interface{}{"key": "value"})
|
Info("Info message", map[string]interface{}{"key": "value"})
|
||||||
Error("Error message", map[string]interface{}{"key": "value"})
|
Error("Error message", map[string]interface{}{"key": "value"})
|
||||||
|
|
||||||
// Skip testing Critical as it might call os.Exit
|
// Skip testing Critical as it might call os.Exit
|
||||||
// Critical("Critical message", map[string]interface{}{"key": "value"})
|
// Critical("Critical message", map[string]interface{}{"key": "value"})
|
||||||
|
|
||||||
// Test passes if we get here without panicking
|
// Test passes if we get here without panicking
|
||||||
assert.True(t, true)
|
assert.True(t, true)
|
||||||
}
|
}
|
||||||
@@ -43,10 +44,10 @@ func TestLoggingWithNilLogger(t *testing.T) {
|
|||||||
Debug("Debug message", map[string]interface{}{"key": "value"})
|
Debug("Debug message", map[string]interface{}{"key": "value"})
|
||||||
Info("Info message", map[string]interface{}{"key": "value"})
|
Info("Info message", map[string]interface{}{"key": "value"})
|
||||||
Error("Error message", map[string]interface{}{"key": "value"})
|
Error("Error message", map[string]interface{}{"key": "value"})
|
||||||
|
|
||||||
// Skip testing Critical as it might call os.Exit
|
// Skip testing Critical as it might call os.Exit
|
||||||
// Critical("Critical message", map[string]interface{}{"key": "value"})
|
// Critical("Critical message", map[string]interface{}{"key": "value"})
|
||||||
|
|
||||||
// Test passes if we get here without panicking
|
// Test passes if we get here without panicking
|
||||||
assert.True(t, true)
|
assert.True(t, true)
|
||||||
}
|
}
|
||||||
@@ -56,15 +57,15 @@ func TestCriticalNilLogger(t *testing.T) {
|
|||||||
// Save original logger and restore after test
|
// Save original logger and restore after test
|
||||||
originalLogger := Logger
|
originalLogger := Logger
|
||||||
defer func() { Logger = originalLogger }()
|
defer func() { Logger = originalLogger }()
|
||||||
|
|
||||||
// Set logger to nil
|
// Set logger to nil
|
||||||
Logger = nil
|
Logger = nil
|
||||||
|
|
||||||
// This should not panic
|
// This should not panic
|
||||||
Critical("Critical message", map[string]interface{}{"key": "value"})
|
Critical("Critical message", map[string]interface{}{"key": "value"})
|
||||||
|
|
||||||
// Test passes if we get here without panicking
|
// Test passes if we get here without panicking
|
||||||
assert.True(t, true)
|
assert.True(t, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: We don't test Critical with an actual logger because it calls os.Exit
|
// Note: We don't test Critical with an actual logger because it calls os.Exit
|
||||||
|
|||||||
+37
-21
@@ -13,29 +13,45 @@ func CalculateSemver(
|
|||||||
initialSemver SemVer,
|
initialSemver SemVer,
|
||||||
respectExisting bool,
|
respectExisting bool,
|
||||||
strictMode bool,
|
strictMode bool,
|
||||||
|
tagPrefixes []string,
|
||||||
) SemVer {
|
) SemVer {
|
||||||
semver := initialSemver
|
semver := initialSemver
|
||||||
|
startIndex := 0
|
||||||
|
|
||||||
for _, commit := range commits {
|
// If respecting existing tags, find the latest tagged commit and start from there
|
||||||
// Check for existing tags if enabled
|
if respectExisting && len(tags) > 0 {
|
||||||
if respectExisting {
|
latestTagIndex := -1
|
||||||
for _, tagHash := range tags {
|
var latestTagName string
|
||||||
if commit.Hash == tagHash.Hash {
|
|
||||||
Debug("Found existing tag", map[string]interface{}{
|
// Find the latest tagged commit (highest index since commits are oldest-first)
|
||||||
"tag": tagHash.Name,
|
for i, commit := range commits {
|
||||||
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
for _, tag := range tags {
|
||||||
})
|
if commit.Hash == tag.Hash {
|
||||||
semver = ParseExistingSemver(tagHash.Name, semver)
|
if i > latestTagIndex {
|
||||||
continue
|
latestTagIndex = i
|
||||||
|
latestTagName = tag.Name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we found a tagged commit, use its version and start processing after it
|
||||||
|
if latestTagIndex >= 0 {
|
||||||
|
Debug("Found latest existing tag", map[string]interface{}{
|
||||||
|
"tag": latestTagName,
|
||||||
|
"commit": strings.TrimSuffix(commits[latestTagIndex].Message, "\n"),
|
||||||
|
})
|
||||||
|
semver = ParseExistingSemver(latestTagName, semver, tagPrefixes)
|
||||||
|
startIndex = latestTagIndex + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, commit := range commits[startIndex:] {
|
||||||
// In non-strict mode, increment patch by default
|
// In non-strict mode, increment patch by default
|
||||||
if !strictMode {
|
if !strictMode {
|
||||||
semver.Patch++
|
semver.Patch++
|
||||||
Debug("Incrementing patch (DEFAULT)", map[string]interface{}{
|
Debug("Incrementing patch (DEFAULT)", map[string]interface{}{
|
||||||
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
||||||
"semver": FormatSemver(semver),
|
"semver": FormatSemver(semver),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -55,44 +71,44 @@ func CalculateSemver(
|
|||||||
semver.EnableReleaseCandidate = false
|
semver.EnableReleaseCandidate = false
|
||||||
semver.Release = 0
|
semver.Release = 0
|
||||||
Debug("Incrementing major (WORDING)", map[string]interface{}{
|
Debug("Incrementing major (WORDING)", map[string]interface{}{
|
||||||
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
||||||
"semver": FormatSemver(semver),
|
"semver": FormatSemver(semver),
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if matchMinor {
|
if matchMinor {
|
||||||
semver.Minor++
|
semver.Minor++
|
||||||
semver.Patch = 1
|
semver.Patch = 1
|
||||||
semver.EnableReleaseCandidate = false
|
semver.EnableReleaseCandidate = false
|
||||||
semver.Release = 0
|
semver.Release = 0
|
||||||
Debug("Incrementing minor (WORDING)", map[string]interface{}{
|
Debug("Incrementing minor (WORDING)", map[string]interface{}{
|
||||||
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
||||||
"semver": FormatSemver(semver),
|
"semver": FormatSemver(semver),
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if matchReleaseCandidate {
|
if matchReleaseCandidate {
|
||||||
semver.Release++
|
semver.Release++
|
||||||
semver.Patch = 1
|
semver.Patch = 1
|
||||||
semver.EnableReleaseCandidate = true
|
semver.EnableReleaseCandidate = true
|
||||||
Debug("Incrementing release candidate (WORDING)", map[string]interface{}{
|
Debug("Incrementing release candidate (WORDING)", map[string]interface{}{
|
||||||
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
||||||
"semver": FormatSemver(semver),
|
"semver": FormatSemver(semver),
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if matchPatch {
|
if matchPatch {
|
||||||
semver.Patch++
|
semver.Patch++
|
||||||
Debug("Incrementing patch (WORDING)", map[string]interface{}{
|
Debug("Incrementing patch (WORDING)", map[string]interface{}{
|
||||||
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
||||||
"semver": FormatSemver(semver),
|
"semver": FormatSemver(semver),
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return semver
|
return semver
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-11
@@ -19,7 +19,7 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
// More sophisticated mock implementation for testing
|
// More sophisticated mock implementation for testing
|
||||||
for _, h := range haystack {
|
for _, h := range haystack {
|
||||||
// Check for substring match to better simulate fuzzy search
|
// Check for substring match to better simulate fuzzy search
|
||||||
if h == needle || (len(h) >= 3 && len(needle) >= 3 &&
|
if h == needle || (len(h) >= 3 && len(needle) >= 3 &&
|
||||||
(h[:3] == needle[:3] || h[len(h)-3:] == needle[len(needle)-3:])) {
|
(h[:3] == needle[:3] || h[len(h)-3:] == needle[len(needle)-3:])) {
|
||||||
return []string{h}
|
return []string{h}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
|
|
||||||
// Test data
|
// Test data
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
// Common wording and blacklist for all tests
|
// Common wording and blacklist for all tests
|
||||||
wording := Wording{
|
wording := Wording{
|
||||||
Patch: []string{"update", "fix", "initial"},
|
Patch: []string{"update", "fix", "initial"},
|
||||||
@@ -49,6 +49,7 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
initialSemver SemVer
|
initialSemver SemVer
|
||||||
respectExisting bool
|
respectExisting bool
|
||||||
strictMode bool
|
strictMode bool
|
||||||
|
tagPrefixes []string
|
||||||
want SemVer
|
want SemVer
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -76,11 +77,12 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
initialSemver: SemVer{},
|
initialSemver: SemVer{},
|
||||||
respectExisting: true,
|
respectExisting: true,
|
||||||
strictMode: false,
|
strictMode: false,
|
||||||
|
tagPrefixes: []string{},
|
||||||
want: SemVer{
|
want: SemVer{
|
||||||
Major: 2,
|
Major: 2,
|
||||||
Minor: 0,
|
Minor: 0,
|
||||||
Patch: 1, // Initial tag 2.0.0 + one patch increment
|
Patch: 1, // Initial tag 2.0.0 + one patch increment
|
||||||
Release: 1,
|
Release: 1,
|
||||||
EnableReleaseCandidate: true,
|
EnableReleaseCandidate: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -109,11 +111,12 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
initialSemver: SemVer{},
|
initialSemver: SemVer{},
|
||||||
respectExisting: true,
|
respectExisting: true,
|
||||||
strictMode: true,
|
strictMode: true,
|
||||||
|
tagPrefixes: []string{},
|
||||||
want: SemVer{
|
want: SemVer{
|
||||||
Major: 2,
|
Major: 2,
|
||||||
Minor: 0,
|
Minor: 0,
|
||||||
Patch: 1, // Initial tag 2.0.0 + patch from "update" keyword
|
Patch: 1, // Initial tag 2.0.0 + patch from "update" keyword
|
||||||
Release: 1,
|
Release: 1,
|
||||||
EnableReleaseCandidate: true,
|
EnableReleaseCandidate: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -142,6 +145,7 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
initialSemver: SemVer{},
|
initialSemver: SemVer{},
|
||||||
respectExisting: false,
|
respectExisting: false,
|
||||||
strictMode: false,
|
strictMode: false,
|
||||||
|
tagPrefixes: []string{},
|
||||||
want: SemVer{
|
want: SemVer{
|
||||||
Major: 0,
|
Major: 0,
|
||||||
Minor: 1,
|
Minor: 1,
|
||||||
@@ -173,6 +177,7 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
initialSemver: SemVer{Major: 1},
|
initialSemver: SemVer{Major: 1},
|
||||||
respectExisting: false,
|
respectExisting: false,
|
||||||
strictMode: true,
|
strictMode: true,
|
||||||
|
tagPrefixes: []string{},
|
||||||
want: SemVer{
|
want: SemVer{
|
||||||
Major: 1,
|
Major: 1,
|
||||||
Minor: 1,
|
Minor: 1,
|
||||||
@@ -199,6 +204,7 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
initialSemver: SemVer{},
|
initialSemver: SemVer{},
|
||||||
respectExisting: false,
|
respectExisting: false,
|
||||||
strictMode: false,
|
strictMode: false,
|
||||||
|
tagPrefixes: []string{},
|
||||||
want: SemVer{
|
want: SemVer{
|
||||||
Major: 0,
|
Major: 0,
|
||||||
Minor: 0,
|
Minor: 0,
|
||||||
@@ -225,6 +231,7 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
initialSemver: SemVer{},
|
initialSemver: SemVer{},
|
||||||
respectExisting: false,
|
respectExisting: false,
|
||||||
strictMode: false,
|
strictMode: false,
|
||||||
|
tagPrefixes: []string{},
|
||||||
want: SemVer{
|
want: SemVer{
|
||||||
Major: 0,
|
Major: 0,
|
||||||
Minor: 0,
|
Minor: 0,
|
||||||
@@ -233,6 +240,39 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
EnableReleaseCandidate: true,
|
EnableReleaseCandidate: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "With prefixed tags should not be RC",
|
||||||
|
commits: []CommitDetails{
|
||||||
|
{
|
||||||
|
Hash: "commit1",
|
||||||
|
Message: "tagged commit",
|
||||||
|
Timestamp: now.Add(-3 * time.Hour),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Hash: "commit2",
|
||||||
|
Message: "another commit",
|
||||||
|
Timestamp: now.Add(-2 * time.Hour),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tags: []TagDetails{
|
||||||
|
{
|
||||||
|
Name: "app-0.0.16",
|
||||||
|
Hash: "commit1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wording: wording,
|
||||||
|
blacklist: blacklist,
|
||||||
|
initialSemver: SemVer{},
|
||||||
|
respectExisting: true,
|
||||||
|
strictMode: true, // Use strict mode for predictable results
|
||||||
|
tagPrefixes: []string{"app-", "infra-"},
|
||||||
|
want: SemVer{
|
||||||
|
Major: 0,
|
||||||
|
Minor: 0,
|
||||||
|
Patch: 16, // From tag, no additional increments in strict mode
|
||||||
|
EnableReleaseCandidate: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@@ -245,6 +285,7 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
tt.initialSemver,
|
tt.initialSemver,
|
||||||
tt.respectExisting,
|
tt.respectExisting,
|
||||||
tt.strictMode,
|
tt.strictMode,
|
||||||
|
tt.tagPrefixes,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert.Equal(t, tt.want.Major, got.Major, "Major version mismatch")
|
assert.Equal(t, tt.want.Major, got.Major, "Major version mismatch")
|
||||||
@@ -254,4 +295,4 @@ func TestCalculateSemver(t *testing.T) {
|
|||||||
assert.Equal(t, tt.want.EnableReleaseCandidate, got.EnableReleaseCandidate, "EnableReleaseCandidate mismatch")
|
assert.Equal(t, tt.want.EnableReleaseCandidate, got.EnableReleaseCandidate, "EnableReleaseCandidate mismatch")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+95
-22
@@ -51,52 +51,125 @@ func FormatSemver(semver SemVer) string {
|
|||||||
|
|
||||||
var extractNumber = regexp.MustCompile("[0-9]+")
|
var extractNumber = regexp.MustCompile("[0-9]+")
|
||||||
|
|
||||||
|
// StripTagPrefix removes configured prefixes from a tag name
|
||||||
|
// The "v" prefix is always stripped by default (e.g., v1.2.3 -> 1.2.3)
|
||||||
|
func StripTagPrefix(tagName string, prefixes []string) string {
|
||||||
|
result := tagName
|
||||||
|
|
||||||
|
// Always strip "v" prefix by default
|
||||||
|
if strings.HasPrefix(result, "v") && len(result) > 1 {
|
||||||
|
// Only strip if followed by a digit (to avoid stripping "version-1.0.0")
|
||||||
|
if result[1] >= '0' && result[1] <= '9' {
|
||||||
|
result = result[1:]
|
||||||
|
Debug("Stripped default 'v' prefix from tag", map[string]interface{}{
|
||||||
|
"original": tagName,
|
||||||
|
"result": result,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then strip any user-configured prefixes
|
||||||
|
for _, prefix := range prefixes {
|
||||||
|
if strings.HasPrefix(result, prefix) {
|
||||||
|
result = strings.TrimPrefix(result, prefix)
|
||||||
|
Debug("Stripped prefix from tag", map[string]interface{}{
|
||||||
|
"original": tagName,
|
||||||
|
"prefix": prefix,
|
||||||
|
"result": result,
|
||||||
|
})
|
||||||
|
break // Only strip one prefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsParseableSemverTag reports whether tagName looks like a proper semver tag
|
||||||
|
// (X.Y.Z, optionally vX.Y.Z, optionally with -rc.N suffix) after configured
|
||||||
|
// prefixes are stripped. Rolling tags like "v1" or "latest" return false so the
|
||||||
|
// calculator can skip them when picking the latest existing tag — preventing a
|
||||||
|
// rolling tag tied to the same commit as a real semver tag from "winning" the
|
||||||
|
// alphabetical iteration in go-git and resetting the baseline to 0.0.0.
|
||||||
|
func IsParseableSemverTag(tagName string, prefixes []string) bool {
|
||||||
|
clean := StripTagPrefix(tagName, prefixes)
|
||||||
|
if idx := strings.Index(clean, "-rc."); idx != -1 {
|
||||||
|
clean = clean[:idx]
|
||||||
|
}
|
||||||
|
parts := strings.Split(clean, ".")
|
||||||
|
if len(parts) < 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, p := range parts[:3] {
|
||||||
|
if len(extractNumber.FindAllString(p, -1)) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// ParseExistingSemver parses a semantic version from a tag name
|
// ParseExistingSemver parses a semantic version from a tag name
|
||||||
func ParseExistingSemver(tagName string, currentSemver SemVer) SemVer {
|
func ParseExistingSemver(tagName string, currentSemver SemVer, prefixes []string) SemVer {
|
||||||
Debug("Parsing existing semver", map[string]interface{}{"tag": tagName})
|
Debug("Parsing existing semver", map[string]interface{}{"tag": tagName})
|
||||||
|
|
||||||
tagNameParts := strings.Split(tagName, ".")
|
// Strip configured prefixes before parsing
|
||||||
|
cleanTagName := StripTagPrefix(tagName, prefixes)
|
||||||
|
|
||||||
|
// Check for release candidate pattern (-rc.X) before splitting
|
||||||
|
isReleaseCandidate := false
|
||||||
|
rcVersion := 0
|
||||||
|
if idx := strings.Index(cleanTagName, "-rc."); idx != -1 {
|
||||||
|
isReleaseCandidate = true
|
||||||
|
rcPart := cleanTagName[idx+4:] // Get everything after "-rc."
|
||||||
|
rcMatches := extractNumber.FindAllString(rcPart, 1)
|
||||||
|
if len(rcMatches) > 0 {
|
||||||
|
rcVersion, _ = strconv.Atoi(rcMatches[0])
|
||||||
|
}
|
||||||
|
// Remove the RC suffix for version parsing
|
||||||
|
cleanTagName = cleanTagName[:idx]
|
||||||
|
Debug("Detected release candidate", map[string]interface{}{
|
||||||
|
"rc_version": rcVersion,
|
||||||
|
"clean_tag_name": cleanTagName,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
tagNameParts := strings.Split(cleanTagName, ".")
|
||||||
if len(tagNameParts) < 3 {
|
if len(tagNameParts) < 3 {
|
||||||
Debug("Unable to parse incompatible semver (non x.y.z)", map[string]interface{}{"tag": tagName})
|
Debug("Unable to parse incompatible semver (non x.y.z)", map[string]interface{}{"tag": tagName})
|
||||||
return currentSemver
|
return currentSemver
|
||||||
}
|
}
|
||||||
|
|
||||||
semanticVersion := SemVer{}
|
semanticVersion := SemVer{}
|
||||||
|
|
||||||
// Extract major version
|
// Extract major version
|
||||||
majorMatches := extractNumber.FindAllString(tagNameParts[0], -1)
|
majorMatches := extractNumber.FindAllString(tagNameParts[0], -1)
|
||||||
if len(majorMatches) > 0 {
|
if len(majorMatches) > 0 {
|
||||||
semanticVersion.Major, _ = strconv.Atoi(majorMatches[0])
|
semanticVersion.Major, _ = strconv.Atoi(majorMatches[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract minor version
|
// Extract minor version
|
||||||
minorMatches := extractNumber.FindAllString(tagNameParts[1], -1)
|
minorMatches := extractNumber.FindAllString(tagNameParts[1], -1)
|
||||||
if len(minorMatches) > 0 {
|
if len(minorMatches) > 0 {
|
||||||
semanticVersion.Minor, _ = strconv.Atoi(minorMatches[0])
|
semanticVersion.Minor, _ = strconv.Atoi(minorMatches[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract patch version
|
// Extract patch version
|
||||||
patchMatches := extractNumber.FindAllString(tagNameParts[2], -1)
|
patchMatches := extractNumber.FindAllString(tagNameParts[2], -1)
|
||||||
if len(patchMatches) > 0 {
|
if len(patchMatches) > 0 {
|
||||||
semanticVersion.Patch, _ = strconv.Atoi(patchMatches[0])
|
semanticVersion.Patch, _ = strconv.Atoi(patchMatches[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract release candidate version if present
|
// Set release candidate if detected
|
||||||
if len(tagNameParts) > 3 {
|
if isReleaseCandidate {
|
||||||
releaseMatches := extractNumber.FindAllString(tagNameParts[3], -1)
|
semanticVersion.Release = rcVersion
|
||||||
if len(releaseMatches) > 0 {
|
semanticVersion.EnableReleaseCandidate = true
|
||||||
semanticVersion.Release, _ = strconv.Atoi(releaseMatches[0])
|
|
||||||
semanticVersion.EnableReleaseCandidate = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return semanticVersion
|
return semanticVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckMatches checks if any of the targets match the content
|
// CheckMatches checks if any of the targets match the content
|
||||||
func CheckMatches(content []string, targets []string, blacklist []string) bool {
|
func CheckMatches(content []string, targets []string, blacklist []string) bool {
|
||||||
contentStr := strings.Join(content, " ")
|
contentStr := strings.Join(content, " ")
|
||||||
|
|
||||||
// First check if any target matches
|
// First check if any target matches
|
||||||
hasMatch := false
|
hasMatch := false
|
||||||
for _, tgt := range targets {
|
for _, tgt := range targets {
|
||||||
@@ -104,8 +177,8 @@ func CheckMatches(content []string, targets []string, blacklist []string) bool {
|
|||||||
if len(matches) > 0 {
|
if len(matches) > 0 {
|
||||||
hasMatch = true
|
hasMatch = true
|
||||||
Debug("Found match", map[string]interface{}{
|
Debug("Found match", map[string]interface{}{
|
||||||
"target": tgt,
|
"target": tgt,
|
||||||
"match": strings.Join(matches, ","),
|
"match": strings.Join(matches, ","),
|
||||||
"content": contentStr,
|
"content": contentStr,
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
@@ -117,14 +190,14 @@ func CheckMatches(content []string, targets []string, blacklist []string) bool {
|
|||||||
for _, blacklistTerm := range blacklist {
|
for _, blacklistTerm := range blacklist {
|
||||||
if strings.Contains(strings.ToLower(contentStr), strings.ToLower(blacklistTerm)) {
|
if strings.Contains(strings.ToLower(contentStr), strings.ToLower(blacklistTerm)) {
|
||||||
Debug("Blacklisted term detected, ignoring commit", map[string]interface{}{
|
Debug("Blacklisted term detected, ignoring commit", map[string]interface{}{
|
||||||
"content": contentStr,
|
"content": contentStr,
|
||||||
"blacklist_term": blacklistTerm,
|
"blacklist_term": blacklistTerm,
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasMatch
|
return hasMatch
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,4 +205,4 @@ func CheckMatches(content []string, targets []string, blacklist []string) bool {
|
|||||||
var FuzzyFind = func(needle string, haystack []string) []string {
|
var FuzzyFind = func(needle string, haystack []string) []string {
|
||||||
// This will be replaced with the actual implementation in main.go
|
// This will be replaced with the actual implementation in main.go
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+92
-11
@@ -58,15 +58,17 @@ func TestParseExistingSemver(t *testing.T) {
|
|||||||
InitLogger(false)
|
InitLogger(false)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
tagName string
|
tagName string
|
||||||
currentSemver SemVer
|
currentSemver SemVer
|
||||||
want SemVer
|
prefixes []string
|
||||||
|
want SemVer
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Standard semver",
|
name: "Standard semver",
|
||||||
tagName: "1.2.3",
|
tagName: "1.2.3",
|
||||||
currentSemver: SemVer{},
|
currentSemver: SemVer{},
|
||||||
|
prefixes: []string{},
|
||||||
want: SemVer{
|
want: SemVer{
|
||||||
Major: 1,
|
Major: 1,
|
||||||
Minor: 2,
|
Minor: 2,
|
||||||
@@ -74,9 +76,10 @@ func TestParseExistingSemver(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "With v prefix",
|
name: "With v prefix configured",
|
||||||
tagName: "v2.3.4",
|
tagName: "v2.3.4",
|
||||||
currentSemver: SemVer{},
|
currentSemver: SemVer{},
|
||||||
|
prefixes: []string{"v"},
|
||||||
want: SemVer{
|
want: SemVer{
|
||||||
Major: 2,
|
Major: 2,
|
||||||
Minor: 3,
|
Minor: 3,
|
||||||
@@ -84,9 +87,32 @@ func TestParseExistingSemver(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "With release candidate",
|
name: "With app- prefix configured",
|
||||||
tagName: "3.4.5-rc.2",
|
tagName: "app-1.2.3",
|
||||||
currentSemver: SemVer{},
|
currentSemver: SemVer{},
|
||||||
|
prefixes: []string{"app-", "infra-"},
|
||||||
|
want: SemVer{
|
||||||
|
Major: 1,
|
||||||
|
Minor: 2,
|
||||||
|
Patch: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "With prefix but not in config - should still parse numbers",
|
||||||
|
tagName: "v2.3.4",
|
||||||
|
currentSemver: SemVer{},
|
||||||
|
prefixes: []string{}, // v not in prefixes
|
||||||
|
want: SemVer{
|
||||||
|
Major: 2,
|
||||||
|
Minor: 3,
|
||||||
|
Patch: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "With release candidate",
|
||||||
|
tagName: "3.4.5-rc.2",
|
||||||
|
currentSemver: SemVer{},
|
||||||
|
prefixes: []string{},
|
||||||
want: SemVer{
|
want: SemVer{
|
||||||
Major: 3,
|
Major: 3,
|
||||||
Minor: 4,
|
Minor: 4,
|
||||||
@@ -95,6 +121,31 @@ func TestParseExistingSemver(t *testing.T) {
|
|||||||
EnableReleaseCandidate: true,
|
EnableReleaseCandidate: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "With prefix and release candidate",
|
||||||
|
tagName: "app-1.0.0-rc.3",
|
||||||
|
currentSemver: SemVer{},
|
||||||
|
prefixes: []string{"app-"},
|
||||||
|
want: SemVer{
|
||||||
|
Major: 1,
|
||||||
|
Minor: 0,
|
||||||
|
Patch: 0,
|
||||||
|
Release: 3,
|
||||||
|
EnableReleaseCandidate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Prefixed tag without RC should NOT be RC",
|
||||||
|
tagName: "app-0.0.16",
|
||||||
|
currentSemver: SemVer{},
|
||||||
|
prefixes: []string{"app-"},
|
||||||
|
want: SemVer{
|
||||||
|
Major: 0,
|
||||||
|
Minor: 0,
|
||||||
|
Patch: 16,
|
||||||
|
EnableReleaseCandidate: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Invalid format",
|
name: "Invalid format",
|
||||||
tagName: "not-a-semver",
|
tagName: "not-a-semver",
|
||||||
@@ -103,6 +154,7 @@ func TestParseExistingSemver(t *testing.T) {
|
|||||||
Minor: 1,
|
Minor: 1,
|
||||||
Patch: 1,
|
Patch: 1,
|
||||||
},
|
},
|
||||||
|
prefixes: []string{},
|
||||||
want: SemVer{
|
want: SemVer{
|
||||||
Major: 1,
|
Major: 1,
|
||||||
Minor: 1,
|
Minor: 1,
|
||||||
@@ -117,6 +169,7 @@ func TestParseExistingSemver(t *testing.T) {
|
|||||||
Minor: 5,
|
Minor: 5,
|
||||||
Patch: 5,
|
Patch: 5,
|
||||||
},
|
},
|
||||||
|
prefixes: []string{},
|
||||||
want: SemVer{
|
want: SemVer{
|
||||||
Major: 5,
|
Major: 5,
|
||||||
Minor: 5,
|
Minor: 5,
|
||||||
@@ -127,7 +180,7 @@ func TestParseExistingSemver(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := ParseExistingSemver(tt.tagName, tt.currentSemver)
|
got := ParseExistingSemver(tt.tagName, tt.currentSemver, tt.prefixes)
|
||||||
assert.Equal(t, tt.want.Major, got.Major, "Major version mismatch")
|
assert.Equal(t, tt.want.Major, got.Major, "Major version mismatch")
|
||||||
assert.Equal(t, tt.want.Minor, got.Minor, "Minor version mismatch")
|
assert.Equal(t, tt.want.Minor, got.Minor, "Minor version mismatch")
|
||||||
assert.Equal(t, tt.want.Patch, got.Patch, "Patch version mismatch")
|
assert.Equal(t, tt.want.Patch, got.Patch, "Patch version mismatch")
|
||||||
@@ -136,6 +189,34 @@ func TestParseExistingSemver(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func TestIsParseableSemverTag(t *testing.T) {
|
||||||
|
InitLogger(false)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
tag string
|
||||||
|
prefixes []string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{name: "plain x.y.z", tag: "1.2.3", want: true},
|
||||||
|
{name: "v prefix", tag: "v1.16.5", want: true},
|
||||||
|
{name: "v prefix with rc", tag: "v2.0.0-rc.3", want: true},
|
||||||
|
{name: "configured app- prefix", tag: "app-1.2.3", prefixes: []string{"app-"}, want: true},
|
||||||
|
|
||||||
|
{name: "rolling v1 tag", tag: "v1", want: false},
|
||||||
|
{name: "rolling latest tag", tag: "latest", want: false},
|
||||||
|
{name: "two-component", tag: "1.2", want: false},
|
||||||
|
{name: "empty", tag: "", want: false},
|
||||||
|
{name: "non-numeric major", tag: "vX.Y.Z", want: false},
|
||||||
|
{name: "just text", tag: "release-day", want: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tt.want, IsParseableSemverTag(tt.tag, tt.prefixes))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckMatches(t *testing.T) {
|
func TestCheckMatches(t *testing.T) {
|
||||||
// Initialize logger for tests
|
// Initialize logger for tests
|
||||||
@@ -196,4 +277,4 @@ func TestCheckMatches(t *testing.T) {
|
|||||||
assert.Equal(t, tt.want, got)
|
assert.Equal(t, tt.want, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-8
@@ -1,17 +1,10 @@
|
|||||||
version: 1
|
version: 1
|
||||||
force:
|
force:
|
||||||
major: 1
|
|
||||||
minor: 4
|
|
||||||
existing: true
|
existing: true
|
||||||
strict: false
|
strict: false
|
||||||
commit: 960207e4677476ad31a9f389f74eaf9f33d49613
|
|
||||||
wording:
|
wording:
|
||||||
patch:
|
|
||||||
- update
|
|
||||||
- initial
|
|
||||||
- fix
|
|
||||||
minor:
|
minor:
|
||||||
- change
|
- change
|
||||||
- improve
|
- improve
|
||||||
major:
|
major:
|
||||||
- breaking
|
- breaking
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ blacklist:
|
|||||||
- "Merge pull request"
|
- "Merge pull request"
|
||||||
- "feature/"
|
- "feature/"
|
||||||
- "feature:"
|
- "feature:"
|
||||||
|
tag_prefixes:
|
||||||
|
# Note: "v" prefix is stripped automatically, no need to include it here
|
||||||
|
- "app-"
|
||||||
|
- "infra-"
|
||||||
wording:
|
wording:
|
||||||
patch:
|
patch:
|
||||||
- update
|
- update
|
||||||
|
|||||||
+13
-8
@@ -157,10 +157,10 @@
|
|||||||
<div class="w-3 h-3 rounded-full bg-green-500"></div>
|
<div class="w-3 h-3 rounded-full bg-green-500"></div>
|
||||||
<span class="ml-2 text-gray-400 text-sm">terminal</span>
|
<span class="ml-2 text-gray-400 text-sm">terminal</span>
|
||||||
</div>
|
</div>
|
||||||
<pre class="text-gray-100 text-sm sm:text-base overflow-x-auto"><code><span class="text-gray-400">$</span> semver-gen generate -l
|
<pre class="text-gray-100 text-sm sm:text-base overflow-x-auto"><code><span class="text-gray-400">$</span> semver-generator generate -l
|
||||||
<span class="text-emerald-400">SEMVER</span> 1.5.2
|
<span class="text-emerald-400">SEMVER</span> 1.5.2
|
||||||
|
|
||||||
<span class="text-gray-400">$</span> semver-gen generate -r https://github.com/user/repo
|
<span class="text-gray-400">$</span> semver-generator generate -r https://github.com/user/repo
|
||||||
<span class="text-emerald-400">SEMVER</span> 2.3.0</code></pre>
|
<span class="text-emerald-400">SEMVER</span> 2.3.0</code></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -260,7 +260,7 @@
|
|||||||
<i class="fas fa-beer mr-2 text-amber-500"></i>
|
<i class="fas fa-beer mr-2 text-amber-500"></i>
|
||||||
Homebrew (macOS)
|
Homebrew (macOS)
|
||||||
</h3>
|
</h3>
|
||||||
<pre class="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto"><code>brew install --cask lukaszraczylo/taps/semver-gen</code></pre>
|
<pre class="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto"><code>brew install --cask lukaszraczylo/taps/semver-generator</code></pre>
|
||||||
</div>
|
</div>
|
||||||
<div class="glass p-6 rounded-xl">
|
<div class="glass p-6 rounded-xl">
|
||||||
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-3 flex items-center">
|
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-3 flex items-center">
|
||||||
@@ -295,19 +295,22 @@
|
|||||||
CLI Usage
|
CLI Usage
|
||||||
</h3>
|
</h3>
|
||||||
<pre class="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto mb-4"><code><span class="text-gray-400"># Local repository</span>
|
<pre class="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto mb-4"><code><span class="text-gray-400"># Local repository</span>
|
||||||
semver-gen generate -l
|
semver-generator generate -l
|
||||||
|
|
||||||
<span class="text-gray-400"># Remote repository</span>
|
<span class="text-gray-400"># Remote repository</span>
|
||||||
semver-gen generate -r https://github.com/user/repo
|
semver-generator generate -r https://github.com/user/repo
|
||||||
|
|
||||||
<span class="text-gray-400"># With custom config</span>
|
<span class="text-gray-400"># With custom config</span>
|
||||||
semver-gen generate -l -c semver.yaml
|
semver-generator generate -l -c semver.yaml
|
||||||
|
|
||||||
<span class="text-gray-400"># Strict mode (only exact matches)</span>
|
<span class="text-gray-400"># Strict mode (only exact matches)</span>
|
||||||
semver-gen generate -l -s
|
semver-generator generate -l -s
|
||||||
|
|
||||||
<span class="text-gray-400"># Respect existing tags</span>
|
<span class="text-gray-400"># Respect existing tags</span>
|
||||||
semver-gen generate -l -e</code></pre>
|
semver-generator generate -l -e
|
||||||
|
|
||||||
|
<span class="text-gray-400"># Self-update to latest version (no auth required)</span>
|
||||||
|
semver-generator -u</code></pre>
|
||||||
<div class="grid sm:grid-cols-2 gap-4 text-sm">
|
<div class="grid sm:grid-cols-2 gap-4 text-sm">
|
||||||
<div>
|
<div>
|
||||||
<h4 class="font-medium text-gray-900 dark:text-gray-100 mb-2">Flags</h4>
|
<h4 class="font-medium text-gray-900 dark:text-gray-100 mb-2">Flags</h4>
|
||||||
@@ -318,6 +321,8 @@ semver-gen generate -l -e</code></pre>
|
|||||||
<li><code class="text-emerald-600 dark:text-emerald-400">-s, --strict</code> Strict matching</li>
|
<li><code class="text-emerald-600 dark:text-emerald-400">-s, --strict</code> Strict matching</li>
|
||||||
<li><code class="text-emerald-600 dark:text-emerald-400">-e, --existing</code> Respect existing tags</li>
|
<li><code class="text-emerald-600 dark:text-emerald-400">-e, --existing</code> Respect existing tags</li>
|
||||||
<li><code class="text-emerald-600 dark:text-emerald-400">-d, --debug</code> Enable debug mode</li>
|
<li><code class="text-emerald-600 dark:text-emerald-400">-d, --debug</code> Enable debug mode</li>
|
||||||
|
<li><code class="text-emerald-600 dark:text-emerald-400">-u, --update</code> Self-update to latest version</li>
|
||||||
|
<li><code class="text-emerald-600 dark:text-emerald-400">-v, --version</code> Display current version</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+2
-2
@@ -60,11 +60,11 @@ if [[ ! -z "$INPUT_DEBUGMODE" ]]; then
|
|||||||
echo "----"
|
echo "----"
|
||||||
echo "FLAGS: $FLAGS"
|
echo "FLAGS: $FLAGS"
|
||||||
echo "----"
|
echo "----"
|
||||||
/go/src/app/semver-gen generate $FLAGS $*
|
/go/src/app/semver-generator generate $FLAGS $*
|
||||||
echo "----"
|
echo "----"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OUT_SEMVER_GEN=$(/go/src/app/semver-gen generate $FLAGS $*)
|
OUT_SEMVER_GEN=$(/go/src/app/semver-generator generate $FLAGS $*)
|
||||||
[ $? -eq 0 ] || exit 1
|
[ $? -eq 0 ] || exit 1
|
||||||
CLEAN_SEMVER=$(echo $OUT_SEMVER_GEN | sed -e 's|SEMVER ||g')
|
CLEAN_SEMVER=$(echo $OUT_SEMVER_GEN | sed -e 's|SEMVER ||g')
|
||||||
echo "semantic_version=$CLEAN_SEMVER" >> $GITHUB_OUTPUT
|
echo "semantic_version=$CLEAN_SEMVER" >> $GITHUB_OUTPUT
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
module github.com/lukaszraczylo/semver-generator
|
module github.com/lukaszraczylo/semver-generator
|
||||||
|
|
||||||
go 1.24.0
|
go 1.25.0
|
||||||
|
|
||||||
toolchain go1.24.6
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-git/go-git/v5 v5.16.4
|
github.com/go-git/go-git/v5 v5.19.1
|
||||||
github.com/lithammer/fuzzysearch v1.1.8
|
github.com/lithammer/fuzzysearch v1.1.8
|
||||||
github.com/lukaszraczylo/graphql-monitoring-proxy v0.41.20
|
github.com/lukaszraczylo/graphql-monitoring-proxy v0.45.1
|
||||||
|
github.com/lukaszraczylo/oss-telemetry v0.2.1
|
||||||
github.com/lukaszraczylo/pandati v0.0.29
|
github.com/lukaszraczylo/pandati v0.0.29
|
||||||
github.com/spf13/cobra v1.10.2
|
github.com/spf13/cobra v1.10.2
|
||||||
github.com/spf13/viper v1.21.0
|
github.com/spf13/viper v1.21.0
|
||||||
@@ -17,25 +16,25 @@ require (
|
|||||||
require (
|
require (
|
||||||
dario.cat/mergo v1.0.2 // indirect
|
dario.cat/mergo v1.0.2 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
github.com/ProtonMail/go-crypto v1.4.1 // indirect
|
||||||
github.com/cloudflare/circl v1.6.1 // indirect
|
github.com/cloudflare/circl v1.6.3 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
|
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
github.com/fsnotify/fsnotify v1.10.1 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.7.0 // indirect
|
github.com/go-git/go-billy/v5 v5.9.0 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.6 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.4.0 // indirect
|
github.com/kevinburke/ssh_config v1.6.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.3.1 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
github.com/pjbgf/sha1cd v0.6.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/rs/zerolog v1.33.0 // indirect
|
github.com/rs/zerolog v1.33.0 // indirect
|
||||||
github.com/sagikazarmark/locafero v0.12.0 // indirect
|
github.com/sagikazarmark/locafero v0.12.0 // indirect
|
||||||
@@ -52,11 +51,10 @@ require (
|
|||||||
github.com/wI2L/jsondiff v0.6.1 // indirect
|
github.com/wI2L/jsondiff v0.6.1 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
golang.org/x/crypto v0.45.0 // indirect
|
golang.org/x/crypto v0.51.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
golang.org/x/net v0.54.0 // indirect
|
||||||
golang.org/x/net v0.47.0 // indirect
|
golang.org/x/sys v0.44.0 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/text v0.37.0 // indirect
|
||||||
golang.org/x/text v0.31.0 // indirect
|
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
|||||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
github.com/ProtonMail/go-crypto v1.4.1 h1:9RfcZHqEQUvP8RzecWEUafnZVtEvrBVL9BiF67IQOfM=
|
||||||
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
github.com/ProtonMail/go-crypto v1.4.1/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=
|
github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=
|
||||||
@@ -27,22 +27,22 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc
|
|||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||||
github.com/go-git/go-billy/v5 v5.7.0 h1:83lBUJhGWhYp0ngzCMSgllhUSuoHP1iEWYjsPl9nwqM=
|
github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA=
|
||||||
github.com/go-git/go-billy/v5 v5.7.0/go.mod h1:/1IUejTKH8xipsAcdfcSAlUlo2J7lkYV8GTKxAT/L3E=
|
github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||||
github.com/go-git/go-git/v5 v5.16.4 h1:7ajIEZHZJULcyJebDLo99bGgS0jRrOxzZG4uCk2Yb2Y=
|
github.com/go-git/go-git/v5 v5.19.1 h1:nX27AnaU43/K5bKktKwgBmR9lawoYVe1Ckg0rgzzN00=
|
||||||
github.com/go-git/go-git/v5 v5.16.4/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
github.com/go-git/go-git/v5 v5.19.1/go.mod h1:Pb1v0c7/g8aGQJwx9Us09W85yGoyvSwuhEGMH7zjDKQ=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
|
||||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||||
@@ -52,8 +52,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
|
|||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
|
github.com/kevinburke/ssh_config v1.6.0 h1:J1FBfmuVosPHf5GRdltRLhPJtJpTlMdKTBjRgTaQBFY=
|
||||||
github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
|
github.com/kevinburke/ssh_config v1.6.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -65,8 +65,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
|
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
|
||||||
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
|
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
|
||||||
github.com/lukaszraczylo/graphql-monitoring-proxy v0.41.20 h1:554N+HD5cTY074Y0LrL82cYQNCG1qDV3QKULgdLovs0=
|
github.com/lukaszraczylo/graphql-monitoring-proxy v0.45.1 h1:NBRubpm7P+Z0iOgqPFAM6HHVPnUs8Qm1BZqpJBKL81Q=
|
||||||
github.com/lukaszraczylo/graphql-monitoring-proxy v0.41.20/go.mod h1:1FLcH7q+7cjUgQxyeVeF7ouBamGpcJZgqDF+j+cuFxI=
|
github.com/lukaszraczylo/graphql-monitoring-proxy v0.45.1/go.mod h1:oL4NfPtHhKcHUUzQpfAqMLUkQDLwkwqzAZFfyhZW3+0=
|
||||||
|
github.com/lukaszraczylo/oss-telemetry v0.2.1 h1:6ULyfzXplpdmIY/i01OPM1jeod9+L1RAhI0jtbVnJI0=
|
||||||
|
github.com/lukaszraczylo/oss-telemetry v0.2.1/go.mod h1:+Cn78qZo8rc3T9eZt0v3oICYRdd75wORtSidc8lNjDQ=
|
||||||
github.com/lukaszraczylo/pandati v0.0.29 h1:WUEWm1+hWjE5KJbIL8OctG00x2dk4XKGJSlrjhxZ55k=
|
github.com/lukaszraczylo/pandati v0.0.29 h1:WUEWm1+hWjE5KJbIL8OctG00x2dk4XKGJSlrjhxZ55k=
|
||||||
github.com/lukaszraczylo/pandati v0.0.29/go.mod h1:+DyTWKFaXd+jIfe7GW5w2S5PyTko/RXxMyOa+Vl713A=
|
github.com/lukaszraczylo/pandati v0.0.29/go.mod h1:+DyTWKFaXd+jIfe7GW5w2S5PyTko/RXxMyOa+Vl713A=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
@@ -78,10 +80,10 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
|||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
|
github.com/pjbgf/sha1cd v0.6.0 h1:3WJ8Wz8gvDz29quX1OcEmkAlUg9diU4GxJHqs0/XiwU=
|
||||||
github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
|
github.com/pjbgf/sha1cd v0.6.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
@@ -138,10 +140,10 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
|||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
|
||||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
@@ -149,8 +151,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -167,21 +169,21 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
|
||||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
|||||||
@@ -15,13 +15,21 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/lukaszraczylo/semver-generator/cmd"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
telemetry "github.com/lukaszraczylo/oss-telemetry"
|
||||||
|
"github.com/lukaszraczylo/semver-generator/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
PKG_VERSION string
|
PKG_VERSION string
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
telemetry.SendForModule("semver-generator", "github.com/lukaszraczylo/semver-generator", PKG_VERSION)
|
||||||
|
defer telemetry.Wait(2 * time.Second)
|
||||||
|
|
||||||
cmd.PKG_VERSION = PKG_VERSION
|
cmd.PKG_VERSION = PKG_VERSION
|
||||||
cmd.Execute()
|
cmd.Execute()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -30,4 +30,4 @@ func TestMain(t *testing.T) {
|
|||||||
|
|
||||||
// Verify that the version was set correctly
|
// Verify that the version was set correctly
|
||||||
assert.Equal(t, "test-version", cmd.PKG_VERSION, "PKG_VERSION should be set correctly")
|
assert.Equal(t, "test-version", cmd.PKG_VERSION, "PKG_VERSION should be set correctly")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user