mirror of
https://github.com/thegeeklab/url-parser.git
synced 2024-11-16 02:00:45 +00:00
Compare commits
101 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
69f5a478ef | ||
c00eea41f9 | |||
|
18a483485a | ||
6eb49d0691 | |||
d79274f428 | |||
|
6507c1dfa4 | ||
|
322d1b75b2 | ||
5d65ae5348 | |||
|
75a3f7dc4a | ||
|
7732914f1a | ||
|
776e809c52 | ||
|
4a02590ff2 | ||
|
8b66ceb9c4 | ||
9238878382 | |||
|
ae0cbaa654 | ||
|
9047fa86a4 | ||
|
441a10a33d | ||
|
3c053eef7d | ||
|
cf3d105310 | ||
|
70f0d4e5b3 | ||
9ff6cd2e6a | |||
|
d36d95846e | ||
|
5c8b9d9cd5 | ||
|
77d3c11da1 | ||
|
df1cb658f3 | ||
|
659ddcee44 | ||
7d4e9651f5 | |||
|
c6b5c9d03d | ||
|
656f744c52 | ||
b01ea54ae9 | |||
6c04899a49 | |||
|
edbced6e5b | ||
|
8f8506617a | ||
|
7cbec15ac2 | ||
5f80b2a7f3 | |||
8c4de70ec4 | |||
b5214bd5df | |||
|
697fdd8bbe | ||
872985ac58 | |||
930e1aac89 | |||
|
590a1c2373 | ||
|
9c841c24cd | ||
49348198db | |||
8fbc353b9b | |||
|
a6c765e1ae | ||
63a38bd033 | |||
f246b1d280 | |||
48bead3372 | |||
|
ff7cdd0857 | ||
6bf5fa8754 | |||
ae1fc2e698 | |||
8c8961bc8e | |||
c0724d12f2 | |||
2a55822632 | |||
90072d2d43 | |||
|
19af4c5c47 | ||
8457c57394 | |||
0af993f5b1 | |||
|
db299322bc | ||
3875ad7a2c | |||
|
3a220af100 | ||
|
c35952c307 | ||
|
183d422439 | ||
|
96db2914ca | ||
|
1c77303641 | ||
|
2f99efb570 | ||
65184f6fc9 | |||
|
ffd126bf10 | ||
|
cf8701ad2f | ||
|
f8585dd93b | ||
|
364ccf7c84 | ||
13171987d8 | |||
ddd51bf1c6 | |||
|
870aef309e | ||
|
067b1bf449 | ||
887fbb90e1 | |||
5c61c96e14 | |||
|
98277d747e | ||
|
8a8c51409c | ||
f32e067fbe | |||
|
fd7629faf3 | ||
|
5a6af40cd7 | ||
|
2738dd3870 | ||
|
ba386afbb5 | ||
|
8ec0eb29be | ||
ea23877b4a | |||
|
255fd776c6 | ||
|
181777004f | ||
b1f139a722 | |||
8d68b98c88 | |||
|
37baf6f8ae | ||
|
9e1a6398b9 | ||
|
c2ace14781 | ||
|
24124e44ae | ||
|
d29e6e23b9 | ||
7326a7c73d | |||
|
4668b2512a | ||
|
02e19acd42 | ||
2404e7aeab | |||
2bd123697f | |||
|
fc011b7533 |
@ -1,23 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
{{ range .Versions -}}
|
||||
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }})
|
||||
|
||||
{{ range .CommitGroups -}}
|
||||
### {{ .Title }}
|
||||
|
||||
{{ range .Commits -}}
|
||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ (regexReplaceAll "(.*)/issues/(.*)" (regexReplaceAll "(Co-\\w*-by.*)" .Subject "") "${1}/pull/${2}") | trim }}
|
||||
{{ end }}
|
||||
{{- end -}}
|
||||
|
||||
{{- if .NoteGroups -}}
|
||||
{{ range .NoteGroups -}}
|
||||
### {{ .Title }}
|
||||
|
||||
{{ range .Notes }}
|
||||
{{ .Body }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
@ -1,25 +0,0 @@
|
||||
style: github
|
||||
template: CHANGELOG.tpl.md
|
||||
info:
|
||||
title: CHANGELOG
|
||||
repository_url: https://github.com/thegeeklab/url-parser
|
||||
options:
|
||||
commit_groups:
|
||||
title_maps:
|
||||
feat: Features
|
||||
fix: Bug Fixes
|
||||
perf: Performance Improvements
|
||||
refactor: Code Refactoring
|
||||
chore: Others
|
||||
test: Testing
|
||||
ci: CI Pipeline
|
||||
docs: Documentation
|
||||
header:
|
||||
pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$"
|
||||
pattern_maps:
|
||||
- Type
|
||||
- Scope
|
||||
- Subject
|
||||
notes:
|
||||
keywords:
|
||||
- BREAKING CHANGE
|
4
.dictionary
Normal file
4
.dictionary
Normal file
@ -0,0 +1,4 @@
|
||||
url-parser
|
||||
herloct
|
||||
multiarch
|
||||
(P|p)rebuilt
|
210
.drone.jsonnet
210
.drone.jsonnet
@ -1,210 +0,0 @@
|
||||
local PipelineTest = {
|
||||
kind: 'pipeline',
|
||||
image_pull_secrets: ['docker_config'],
|
||||
name: 'test',
|
||||
platform: {
|
||||
os: 'linux',
|
||||
arch: 'amd64',
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
name: 'staticcheck',
|
||||
image: 'golang:1.16',
|
||||
commands: [
|
||||
'go run honnef.co/go/tools/cmd/staticcheck ./...',
|
||||
],
|
||||
volumes: [
|
||||
{
|
||||
name: 'gopath',
|
||||
path: '/go',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'lint',
|
||||
image: 'golang:1.16',
|
||||
commands: [
|
||||
'go run golang.org/x/lint/golint -set_exit_status ./...',
|
||||
],
|
||||
volumes: [
|
||||
{
|
||||
name: 'gopath',
|
||||
path: '/go',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'vet',
|
||||
image: 'golang:1.16',
|
||||
commands: [
|
||||
'go vet ./...',
|
||||
],
|
||||
volumes: [
|
||||
{
|
||||
name: 'gopath',
|
||||
path: '/go',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'test',
|
||||
image: 'golang:1.16',
|
||||
commands: [
|
||||
'go test -race -coverprofile=coverage.txt -covermode=atomic ./...',
|
||||
],
|
||||
volumes: [
|
||||
{
|
||||
name: 'gopath',
|
||||
path: '/go',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'coverage',
|
||||
image: 'plugins/codecov',
|
||||
settings: {
|
||||
token: {
|
||||
from_secret: 'codecov_token',
|
||||
},
|
||||
files: [
|
||||
'coverage.txt',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
volumes: [
|
||||
{
|
||||
name: 'gopath',
|
||||
temp: {},
|
||||
},
|
||||
],
|
||||
trigger: {
|
||||
ref: ['refs/heads/main', 'refs/tags/**', 'refs/pull/**'],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
local PipelineBuildBinaries = {
|
||||
kind: 'pipeline',
|
||||
image_pull_secrets: ['docker_config'],
|
||||
name: 'build-binaries',
|
||||
platform: {
|
||||
os: 'linux',
|
||||
arch: 'amd64',
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
name: 'build',
|
||||
image: 'techknowlogick/xgo:go-1.16.x',
|
||||
commands: [
|
||||
'[ -z "${DRONE_TAG}" ] && BUILD_VERSION=${DRONE_COMMIT_SHA:0:8} || BUILD_VERSION=${DRONE_TAG##v}',
|
||||
'mkdir -p release/',
|
||||
"cd cmd/url-parser && xgo -ldflags \"-s -w -X main.version=$BUILD_VERSION\" -tags netgo -targets 'linux/amd64,linux/arm-6,linux/arm-7,linux/arm64' -out url-parser .",
|
||||
'mv /build/* /drone/src/release/',
|
||||
'ls -l /drone/src/release/',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'executable',
|
||||
image: 'alpine',
|
||||
commands: [
|
||||
'$(find release/ -executable -type f | grep url-parser-linux-amd64) --help',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'compress',
|
||||
image: 'alpine',
|
||||
commands: [
|
||||
'apk add upx',
|
||||
'find release/ -maxdepth 1 -executable -type f -exec upx {} \\;',
|
||||
'ls -lh release/',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'checksum',
|
||||
image: 'alpine',
|
||||
commands: [
|
||||
'cd release/ && sha256sum * > sha256sum.txt',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'changelog-generate',
|
||||
image: 'thegeeklab/git-chglog',
|
||||
commands: [
|
||||
'git fetch -tq',
|
||||
'git-chglog --no-color --no-emoji -o CHANGELOG.md ${DRONE_TAG:---next-tag unreleased unreleased}',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'changelog-format',
|
||||
image: 'thegeeklab/alpine-tools',
|
||||
commands: [
|
||||
'prettier CHANGELOG.md',
|
||||
'prettier -w CHANGELOG.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'publish',
|
||||
image: 'plugins/github-release',
|
||||
settings: {
|
||||
overwrite: true,
|
||||
api_key: {
|
||||
from_secret: 'github_token',
|
||||
},
|
||||
files: ['release/*'],
|
||||
title: '${DRONE_TAG}',
|
||||
note: 'CHANGELOG.md',
|
||||
},
|
||||
when: {
|
||||
ref: [
|
||||
'refs/tags/**',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
depends_on: [
|
||||
'test',
|
||||
],
|
||||
trigger: {
|
||||
ref: ['refs/heads/main', 'refs/tags/**', 'refs/pull/**'],
|
||||
},
|
||||
};
|
||||
|
||||
local PipelineNotifications = {
|
||||
kind: 'pipeline',
|
||||
image_pull_secrets: ['docker_config'],
|
||||
name: 'notifications',
|
||||
platform: {
|
||||
os: 'linux',
|
||||
arch: 'amd64',
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
name: 'matrix',
|
||||
image: 'thegeeklab/drone-matrix',
|
||||
settings: {
|
||||
homeserver: { from_secret: 'matrix_homeserver' },
|
||||
roomid: { from_secret: 'matrix_roomid' },
|
||||
template: 'Status: **{{ build.Status }}**<br/> Build: [{{ repo.Owner }}/{{ repo.Name }}]({{ build.Link }}){{#if build.Branch}} ({{ build.Branch }}){{/if}} by {{ commit.Author }}<br/> Message: {{ commit.Message.Title }}',
|
||||
username: { from_secret: 'matrix_username' },
|
||||
password: { from_secret: 'matrix_password' },
|
||||
},
|
||||
when: {
|
||||
status: ['success', 'failure'],
|
||||
},
|
||||
},
|
||||
],
|
||||
depends_on: [
|
||||
'build-binaries',
|
||||
],
|
||||
trigger: {
|
||||
ref: ['refs/heads/main', 'refs/tags/**'],
|
||||
status: ['success', 'failure'],
|
||||
},
|
||||
};
|
||||
|
||||
[
|
||||
PipelineTest,
|
||||
PipelineBuildBinaries,
|
||||
PipelineNotifications,
|
||||
]
|
180
.drone.yml
180
.drone.yml
@ -1,180 +0,0 @@
|
||||
---
|
||||
kind: pipeline
|
||||
name: test
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: staticcheck
|
||||
image: golang:1.16
|
||||
commands:
|
||||
- go run honnef.co/go/tools/cmd/staticcheck ./...
|
||||
volumes:
|
||||
- name: gopath
|
||||
path: /go
|
||||
|
||||
- name: lint
|
||||
image: golang:1.16
|
||||
commands:
|
||||
- go run golang.org/x/lint/golint -set_exit_status ./...
|
||||
volumes:
|
||||
- name: gopath
|
||||
path: /go
|
||||
|
||||
- name: vet
|
||||
image: golang:1.16
|
||||
commands:
|
||||
- go vet ./...
|
||||
volumes:
|
||||
- name: gopath
|
||||
path: /go
|
||||
|
||||
- name: test
|
||||
image: golang:1.16
|
||||
commands:
|
||||
- go test -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
volumes:
|
||||
- name: gopath
|
||||
path: /go
|
||||
|
||||
- name: coverage
|
||||
image: plugins/codecov
|
||||
settings:
|
||||
files:
|
||||
- coverage.txt
|
||||
token:
|
||||
from_secret: codecov_token
|
||||
|
||||
volumes:
|
||||
- name: gopath
|
||||
temp: {}
|
||||
|
||||
image_pull_secrets:
|
||||
- docker_config
|
||||
|
||||
trigger:
|
||||
ref:
|
||||
- refs/heads/main
|
||||
- refs/tags/**
|
||||
- refs/pull/**
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: build-binaries
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: techknowlogick/xgo:go-1.16.x
|
||||
commands:
|
||||
- "[ -z \"${DRONE_TAG}\" ] && BUILD_VERSION=${DRONE_COMMIT_SHA:0:8} || BUILD_VERSION=${DRONE_TAG##v}"
|
||||
- mkdir -p release/
|
||||
- cd cmd/url-parser && xgo -ldflags "-s -w -X main.version=$BUILD_VERSION" -tags netgo -targets 'linux/amd64,linux/arm-6,linux/arm-7,linux/arm64' -out url-parser .
|
||||
- mv /build/* /drone/src/release/
|
||||
- ls -l /drone/src/release/
|
||||
|
||||
- name: executable
|
||||
image: alpine
|
||||
commands:
|
||||
- $(find release/ -executable -type f | grep url-parser-linux-amd64) --help
|
||||
|
||||
- name: compress
|
||||
image: alpine
|
||||
commands:
|
||||
- apk add upx
|
||||
- find release/ -maxdepth 1 -executable -type f -exec upx {} \;
|
||||
- ls -lh release/
|
||||
|
||||
- name: checksum
|
||||
image: alpine
|
||||
commands:
|
||||
- cd release/ && sha256sum * > sha256sum.txt
|
||||
|
||||
- name: changelog-generate
|
||||
image: thegeeklab/git-chglog
|
||||
commands:
|
||||
- git fetch -tq
|
||||
- git-chglog --no-color --no-emoji -o CHANGELOG.md ${DRONE_TAG:---next-tag unreleased unreleased}
|
||||
|
||||
- name: changelog-format
|
||||
image: thegeeklab/alpine-tools
|
||||
commands:
|
||||
- prettier CHANGELOG.md
|
||||
- prettier -w CHANGELOG.md
|
||||
|
||||
- name: publish
|
||||
image: plugins/github-release
|
||||
settings:
|
||||
api_key:
|
||||
from_secret: github_token
|
||||
files:
|
||||
- release/*
|
||||
note: CHANGELOG.md
|
||||
overwrite: true
|
||||
title: ${DRONE_TAG}
|
||||
when:
|
||||
ref:
|
||||
- refs/tags/**
|
||||
|
||||
image_pull_secrets:
|
||||
- docker_config
|
||||
|
||||
trigger:
|
||||
ref:
|
||||
- refs/heads/main
|
||||
- refs/tags/**
|
||||
- refs/pull/**
|
||||
|
||||
depends_on:
|
||||
- test
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: notifications
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: matrix
|
||||
image: thegeeklab/drone-matrix
|
||||
settings:
|
||||
homeserver:
|
||||
from_secret: matrix_homeserver
|
||||
password:
|
||||
from_secret: matrix_password
|
||||
roomid:
|
||||
from_secret: matrix_roomid
|
||||
template: "Status: **{{ build.Status }}**<br/> Build: [{{ repo.Owner }}/{{ repo.Name }}]({{ build.Link }}){{#if build.Branch}} ({{ build.Branch }}){{/if}} by {{ commit.Author }}<br/> Message: {{ commit.Message.Title }}"
|
||||
username:
|
||||
from_secret: matrix_username
|
||||
when:
|
||||
status:
|
||||
- success
|
||||
- failure
|
||||
|
||||
image_pull_secrets:
|
||||
- docker_config
|
||||
|
||||
trigger:
|
||||
ref:
|
||||
- refs/heads/main
|
||||
- refs/tags/**
|
||||
status:
|
||||
- success
|
||||
- failure
|
||||
|
||||
depends_on:
|
||||
- build-binaries
|
||||
|
||||
---
|
||||
kind: signature
|
||||
hmac: 93e1fe6fe0e097355d77fd21bc67f05998e1fccec3848624cc6508f9de8facd9
|
||||
|
||||
...
|
7
.github/settings.yml
vendored
7
.github/settings.yml
vendored
@ -50,6 +50,9 @@ branches:
|
||||
required_status_checks:
|
||||
strict: false
|
||||
contexts:
|
||||
- continuous-integration/drone/pr
|
||||
enforce_admins: null
|
||||
- ci/woodpecker/pr/test
|
||||
- ci/woodpecker/pr/build-package
|
||||
- ci/woodpecker/pr/docs
|
||||
enforce_admins: false
|
||||
required_linear_history: true
|
||||
restrictions: null
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
/release/
|
||||
/dist
|
||||
/release
|
||||
/url-parser*
|
||||
|
||||
coverage.out
|
||||
|
47
.gitsv/config.yml
Normal file
47
.gitsv/config.yml
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
version: "1.1"
|
||||
|
||||
versioning:
|
||||
update-major: []
|
||||
update-minor: [feat]
|
||||
update-patch: [fix, perf, refactor, chore, test, ci, docs]
|
||||
|
||||
tag:
|
||||
pattern: "v%d.%d.%d"
|
||||
|
||||
release-notes:
|
||||
sections:
|
||||
- name: Features
|
||||
commit-types: [feat]
|
||||
section-type: commits
|
||||
- name: Bug Fixes
|
||||
commit-types: [fix]
|
||||
section-type: commits
|
||||
- name: Performance Improvements
|
||||
commit-types: [perf]
|
||||
section-type: commits
|
||||
- name: Code Refactoring
|
||||
commit-types: [refactor]
|
||||
section-type: commits
|
||||
- name: Others
|
||||
commit-types: [chore]
|
||||
section-type: commits
|
||||
- name: Testing
|
||||
commit-types: [test]
|
||||
section-type: commits
|
||||
- name: CI Pipeline
|
||||
commit-types: [ci]
|
||||
section-type: commits
|
||||
- name: Documentation
|
||||
commit-types: [docs]
|
||||
section-type: commits
|
||||
- name: BREAKING CHANGES
|
||||
section-type: breaking-changes
|
||||
|
||||
commit-message:
|
||||
footer:
|
||||
issue:
|
||||
key: issue
|
||||
add-value-prefix: "#"
|
||||
issue:
|
||||
regex: "#?[0-9]+"
|
96
.golangci.yml
Normal file
96
.golangci.yml
Normal file
@ -0,0 +1,96 @@
|
||||
linters:
|
||||
enable-all: false
|
||||
disable-all: true
|
||||
enable:
|
||||
- errcheck
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- staticcheck
|
||||
- typecheck
|
||||
- unused
|
||||
- asasalint
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- bodyclose
|
||||
- containedctx
|
||||
- contextcheck
|
||||
- decorder
|
||||
- dogsled
|
||||
- dupl
|
||||
- dupword
|
||||
- durationcheck
|
||||
- errchkjson
|
||||
- errname
|
||||
- errorlint
|
||||
- exhaustive
|
||||
- copyloopvar
|
||||
- forcetypeassert
|
||||
- ginkgolinter
|
||||
- gocheckcompilerdirectives
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocognit
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- godot
|
||||
- godox
|
||||
- err113
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goheader
|
||||
- goimports
|
||||
- mnd
|
||||
- gomoddirectives
|
||||
- gomodguard
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- grouper
|
||||
- importas
|
||||
- interfacebloat
|
||||
- ireturn
|
||||
- lll
|
||||
- loggercheck
|
||||
- maintidx
|
||||
- makezero
|
||||
- misspell
|
||||
- musttag
|
||||
- nakedret
|
||||
- nestif
|
||||
- nilerr
|
||||
- nilnil
|
||||
- nlreturn
|
||||
- noctx
|
||||
- nolintlint
|
||||
- nonamedreturns
|
||||
- nosprintfhostport
|
||||
- prealloc
|
||||
- predeclared
|
||||
- promlinter
|
||||
- reassign
|
||||
- revive
|
||||
# - rowserrcheck
|
||||
# - sqlclosecheck
|
||||
# - structcheck
|
||||
- stylecheck
|
||||
- tagliatelle
|
||||
- tenv
|
||||
- testableexamples
|
||||
- thelper
|
||||
- tparallel
|
||||
- unconvert
|
||||
- unparam
|
||||
- usestdlibvars
|
||||
# - wastedassign
|
||||
- whitespace
|
||||
- wsl
|
||||
- zerologlint
|
||||
fast: false
|
||||
|
||||
run:
|
||||
timeout: 3m
|
||||
|
||||
linters-settings:
|
||||
gofumpt:
|
||||
extra-rules: true
|
6
.markdownlint.yml
Normal file
6
.markdownlint.yml
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
default: True
|
||||
MD013: False
|
||||
MD041: False
|
||||
MD004:
|
||||
style: dash
|
@ -1,3 +1,2 @@
|
||||
.drone.yml
|
||||
*.tpl.md
|
||||
LICENSE
|
||||
|
41
.woodpecker/build-package.yml
Normal file
41
.woodpecker/build-package.yml
Normal file
@ -0,0 +1,41 @@
|
||||
---
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: docker.io/techknowlogick/xgo:go-1.23.3
|
||||
commands:
|
||||
- ln -s $(pwd) /source
|
||||
- make release
|
||||
|
||||
- name: executable
|
||||
image: quay.io/thegeeklab/alpine-tools
|
||||
commands:
|
||||
- $(find dist/ -executable -type f -iname ${CI_REPO_NAME}-linux-amd64) --help
|
||||
|
||||
- name: changelog
|
||||
image: quay.io/thegeeklab/git-sv
|
||||
commands:
|
||||
- git sv current-version
|
||||
- git sv release-notes -t ${CI_COMMIT_TAG:-next} -o CHANGELOG.md
|
||||
- cat CHANGELOG.md
|
||||
|
||||
- name: publish-github
|
||||
image: docker.io/plugins/github-release
|
||||
settings:
|
||||
api_key:
|
||||
from_secret: github_token
|
||||
files:
|
||||
- dist/*
|
||||
note: CHANGELOG.md
|
||||
overwrite: true
|
||||
title: ${CI_COMMIT_TAG}
|
||||
when:
|
||||
- event: [tag]
|
||||
|
||||
depends_on:
|
||||
- test
|
22
.woodpecker/docs.yml
Normal file
22
.woodpecker/docs.yml
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
steps:
|
||||
- name: markdownlint
|
||||
image: quay.io/thegeeklab/markdownlint-cli
|
||||
commands:
|
||||
- markdownlint 'README.md' 'CONTRIBUTING.md'
|
||||
|
||||
- name: spellcheck
|
||||
image: quay.io/thegeeklab/alpine-tools
|
||||
commands:
|
||||
- spellchecker --files 'README.md' 'CONTRIBUTING.md' -d .dictionary -p spell indefinite-article syntax-urls
|
||||
environment:
|
||||
FORCE_COLOR: "true"
|
||||
|
||||
depends_on:
|
||||
- build-package
|
26
.woodpecker/notify.yml
Normal file
26
.woodpecker/notify.yml
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
when:
|
||||
- event: [tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
runs_on: [success, failure]
|
||||
|
||||
steps:
|
||||
- name: matrix
|
||||
image: quay.io/thegeeklab/wp-matrix
|
||||
settings:
|
||||
homeserver:
|
||||
from_secret: matrix_homeserver
|
||||
room_id:
|
||||
from_secret: matrix_room_id
|
||||
user_id:
|
||||
from_secret: matrix_user_id
|
||||
access_token:
|
||||
from_secret: matrix_access_token
|
||||
when:
|
||||
- status: [success, failure]
|
||||
|
||||
depends_on:
|
||||
- docs
|
17
.woodpecker/test.yml
Normal file
17
.woodpecker/test.yml
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
steps:
|
||||
- name: lint
|
||||
image: docker.io/library/golang:1.23.3
|
||||
commands:
|
||||
- make lint
|
||||
|
||||
- name: test
|
||||
image: docker.io/library/golang:1.23.3
|
||||
commands:
|
||||
- make test
|
@ -3,7 +3,7 @@
|
||||
## Security
|
||||
|
||||
If you think you have found a **security issue**, please do not mention it in this repository.
|
||||
Instead, send an email to security@thegeeklab.de with as many details as possible so it can be handled confidential.
|
||||
Instead, send an email to `security@thegeeklab.de` with as many details as possible so it can be handled confidential.
|
||||
|
||||
## Bug Reports and Feature Requests
|
||||
|
||||
|
104
Makefile
Normal file
104
Makefile
Normal file
@ -0,0 +1,104 @@
|
||||
# renovate: datasource=github-releases depName=mvdan/gofumpt
|
||||
GOFUMPT_PACKAGE_VERSION := v0.7.0
|
||||
# renovate: datasource=github-releases depName=golangci/golangci-lint
|
||||
GOLANGCI_LINT_PACKAGE_VERSION := v1.62.0
|
||||
# renovate: datasource=docker depName=docker.io/techknowlogick/xgo
|
||||
XGO_PACKAGE_VERSION := go-1.23.3
|
||||
|
||||
EXECUTABLE := url-parser
|
||||
|
||||
DIST := dist
|
||||
DIST_DIRS := $(DIST)
|
||||
IMPORT := github.com/thegeeklab/$(EXECUTABLE)
|
||||
|
||||
GO ?= go
|
||||
CWD ?= $(shell pwd)
|
||||
PACKAGES ?= $(shell go list ./...)
|
||||
SOURCES ?= $(shell find . -name "*.go" -type f)
|
||||
|
||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@$(GOFUMPT_PACKAGE_VERSION)
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_PACKAGE_VERSION)
|
||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||
GOTESTSUM_PACKAGE ?= gotest.tools/gotestsum@latest
|
||||
|
||||
GENERATE ?=
|
||||
XGO_TARGETS ?= linux/amd64,linux/arm-6,linux/arm-7,linux/arm64
|
||||
|
||||
TARGETOS ?= linux
|
||||
TARGETARCH ?= amd64
|
||||
ifneq ("$(TARGETVARIANT)","")
|
||||
GOARM ?= $(subst v,,$(TARGETVARIANT))
|
||||
endif
|
||||
TAGS ?= netgo
|
||||
|
||||
ifndef VERSION
|
||||
ifneq ($(CI_COMMIT_TAG),)
|
||||
VERSION ?= $(subst v,,$(CI_COMMIT_TAG))
|
||||
else
|
||||
VERSION ?= $(shell git rev-parse --short HEAD)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef DATE
|
||||
DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%S%z")
|
||||
endif
|
||||
|
||||
LDFLAGS += -s -w -X "main.BuildVersion=$(VERSION)" -X "main.BuildDate=$(DATE)"
|
||||
|
||||
.PHONY: all
|
||||
all: clean build
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(GO) clean -i ./...
|
||||
rm -rf $(DIST_DIRS)
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
$(GO) run $(GOFUMPT_PACKAGE) -extra -w $(SOURCES)
|
||||
|
||||
.PHONY: golangci-lint
|
||||
golangci-lint:
|
||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
|
||||
|
||||
.PHONY: lint
|
||||
lint: golangci-lint
|
||||
|
||||
.PHONY: generate
|
||||
generate:
|
||||
$(GO) generate $(GENERATE)
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(GO) run $(GOTESTSUM_PACKAGE) --no-color=false -- -coverprofile=coverage.out $(PACKAGES)
|
||||
|
||||
.PHONY: build
|
||||
build: $(DIST)/$(EXECUTABLE)
|
||||
|
||||
$(DIST)/$(EXECUTABLE): $(SOURCES)
|
||||
GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) GOARM=$(GOARM) $(GO) build -v -tags '$(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -o $@ ./cmd/$(EXECUTABLE)
|
||||
|
||||
$(DIST_DIRS):
|
||||
mkdir -p $(DIST_DIRS)
|
||||
|
||||
.PHONY: xgo
|
||||
xgo: | $(DIST_DIRS)
|
||||
$(GO) run $(XGO_PACKAGE) -go $(XGO_PACKAGE_VERSION) -v -ldflags '-extldflags "-static" $(LDFLAGS)' -tags '$(TAGS)' -targets '$(XGO_TARGETS)' -out $(EXECUTABLE) --pkg cmd/$(EXECUTABLE) .
|
||||
cp /build/* $(CWD)/$(DIST)
|
||||
ls -l $(CWD)/$(DIST)
|
||||
|
||||
.PHONY: checksum
|
||||
checksum:
|
||||
cd $(DIST); $(foreach file,$(wildcard $(DIST)/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
|
||||
ls -l $(CWD)/$(DIST)
|
||||
|
||||
.PHONY: release
|
||||
release: xgo checksum
|
||||
|
||||
.PHONY: deps
|
||||
deps:
|
||||
$(GO) mod download
|
||||
$(GO) install $(GOFUMPT_PACKAGE)
|
||||
$(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||
$(GO) install $(XGO_PACKAGE)
|
||||
$(GO) install $(GOTESTSUM_PACKAGE)
|
48
README.md
48
README.md
@ -1,8 +1,9 @@
|
||||
# url-parser
|
||||
|
||||
[![Build Status](https://img.shields.io/drone/build/thegeeklab/url-parser?logo=drone&server=https%3A%2F%2Fdrone.thegeeklab.de)](https://drone.thegeeklab.de/thegeeklab/url-parser)
|
||||
Simple command-line URL parser
|
||||
|
||||
[![Build Status](https://ci.thegeeklab.de/api/badges/thegeeklab/url-parser/status.svg)](https://ci.thegeeklab.de/repos/thegeeklab/url-parser)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/thegeeklab/url-parser)](https://goreportcard.com/report/github.com/thegeeklab/url-parser)
|
||||
[![Codecov](https://img.shields.io/codecov/c/github/thegeeklab/url-parser)](https://codecov.io/gh/thegeeklab/url-parser)
|
||||
[![GitHub contributors](https://img.shields.io/github/contributors/thegeeklab/url-parser)](https://github.com/thegeeklab/url-parser/graphs/contributors)
|
||||
[![License: MIT](https://img.shields.io/github/license/thegeeklab/url-parser)](https://github.com/thegeeklab/url-parser/blob/main/LICENSE)
|
||||
|
||||
@ -10,12 +11,11 @@ Inspired by [herloct/url-parser](https://github.com/herloct/url-parser), a simpl
|
||||
|
||||
## Installation
|
||||
|
||||
Prebuild multiarch binaries are availabe for Linux only:
|
||||
Prebuilt multiarch binaries are available for Linux only.
|
||||
|
||||
```Shell
|
||||
curl -L https://github.com/thegeeklab/url-parser/releases/download/v0.1.0/url-parser-0.1.0-linux-amd64 > /usr/local/bin/url-parser
|
||||
curl -SsfL https://github.com/thegeeklab/url-parser/releases/latest/download/url-parser-linux-amd64 -o /usr/local/bin/url-parser
|
||||
chmod +x /usr/local/bin/url-parser
|
||||
url-parser --help
|
||||
```
|
||||
|
||||
## Build
|
||||
@ -23,12 +23,7 @@ url-parser --help
|
||||
Build the binary from source with the following command:
|
||||
|
||||
```Shell
|
||||
export GOOS=linux
|
||||
export GOARCH=amd64
|
||||
export CGO_ENABLED=0
|
||||
export GO111MODULE=on
|
||||
|
||||
go build -v -a -tags netgo -o release/url-parser ./cmd/url-parser/
|
||||
make build
|
||||
```
|
||||
|
||||
## Usage
|
||||
@ -39,7 +34,7 @@ NAME:
|
||||
url-parser - Parse URL and shows the part of it.
|
||||
|
||||
USAGE:
|
||||
url-parser [global options] command [command options] [arguments...]
|
||||
url-parser [global options] command [command options]
|
||||
|
||||
VERSION:
|
||||
devel
|
||||
@ -50,7 +45,7 @@ COMMANDS:
|
||||
user, u Get username from url
|
||||
password, pw Get password from url
|
||||
path, pt Get path from url
|
||||
host, h Get hostname from url
|
||||
host, ht Get hostname from url
|
||||
port, p Get port from url
|
||||
query, q Get query from url
|
||||
fragment, f Get fragment from url
|
||||
@ -58,36 +53,43 @@ COMMANDS:
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--url value source url to parse [$URL_PARSER_URL]
|
||||
--help, -h show help (default: false)
|
||||
--version, -v print the version (default: false)
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```Shell
|
||||
$ url-parser host --url https://somedomain.com
|
||||
$ url-parser --url https://somedomain.com host
|
||||
somedomain.com
|
||||
|
||||
$ url-parser user --url https://herloct@somedomain.com
|
||||
$ url-parser --url https://herloct@somedomain.com user
|
||||
herloct
|
||||
|
||||
$ url-parser path --url https://somedomain.com/path/to
|
||||
$ url-parser --url https://somedomain.com/path/to path
|
||||
/path/to
|
||||
|
||||
$ url-parser path --path-index=1 --url https://somedomain.com/path/to
|
||||
$ url-parser --url https://somedomain.com/path/to path --path-index=1
|
||||
to
|
||||
|
||||
$ url-parser query --url https://somedomain.com/?some-key=somevalue
|
||||
$ url-parser --url https://somedomain.com/?some-key=somevalue query
|
||||
some-key=somevalue
|
||||
|
||||
$ url-parser query --query-field=some-key --url https://somedomain.com/?some-key=somevalue
|
||||
$ url-parser --url https://somedomain.com/?some-key=somevalue query --query-field=some-key
|
||||
somevalue
|
||||
|
||||
# It is also possible to read the URL from stdin
|
||||
$ echo "https://somedomain.com" | url-parser host
|
||||
somedomain.com
|
||||
|
||||
# Get json output or all parsed parts
|
||||
$ url-parser --url https://somedomain.com/?some-key=somevalue all --json
|
||||
{"scheme":"https","hostname":"somedomain.com","port":"","path":"/","fragment":"","rawQuery":"some-key=somevalue","queryParams":[{"key":"some-key","value":"somevalue"}],"username":"","password":""}
|
||||
```
|
||||
|
||||
## Contributors
|
||||
|
||||
Special thanks goes to all [contributors](https://github.com/thegeeklab/url-parser/graphs/contributors). If you would like to contribute,
|
||||
please see the [instructions](https://github.com/thegeeklab/url-parser/blob/main/CONTRIBUTING.md).
|
||||
Special thanks to all [contributors](https://github.com/thegeeklab/url-parser/graphs/contributors). If you would like to contribute, please see the [instructions](https://github.com/thegeeklab/url-parser/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
@ -1,84 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/thegeeklab/url-parser/internal/command"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func globalFlags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "url",
|
||||
Usage: "source url to parse",
|
||||
EnvVars: []string{"URL_PARSER_URL"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func configCommands() []*cli.Command {
|
||||
return []*cli.Command{
|
||||
{
|
||||
Name: "all",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Get all parts from url",
|
||||
Action: command.Run,
|
||||
Flags: globalFlags(),
|
||||
},
|
||||
{
|
||||
Name: "scheme",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Get scheme from url",
|
||||
Action: command.Scheme,
|
||||
Flags: globalFlags(),
|
||||
},
|
||||
{
|
||||
Name: "user",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Get username from url",
|
||||
Action: command.User,
|
||||
Flags: globalFlags(),
|
||||
},
|
||||
{
|
||||
Name: "password",
|
||||
Aliases: []string{"pw"},
|
||||
Usage: "Get password from url",
|
||||
Action: command.Password,
|
||||
Flags: globalFlags(),
|
||||
},
|
||||
{
|
||||
Name: "path",
|
||||
Aliases: []string{"pt"},
|
||||
Usage: "Get path from url",
|
||||
Action: command.Path,
|
||||
Flags: append(globalFlags(), command.PathFlags()...),
|
||||
},
|
||||
{
|
||||
Name: "host",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Get hostname from url",
|
||||
Action: command.Host,
|
||||
Flags: globalFlags(),
|
||||
},
|
||||
{
|
||||
Name: "port",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Get port from url",
|
||||
Action: command.Port,
|
||||
Flags: globalFlags(),
|
||||
},
|
||||
{
|
||||
Name: "query",
|
||||
Aliases: []string{"q"},
|
||||
Usage: "Get query from url",
|
||||
Action: command.Query,
|
||||
Flags: append(globalFlags(), command.QueryFlags()...),
|
||||
},
|
||||
{
|
||||
Name: "fragment",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "Get fragment from url",
|
||||
Action: command.Fragment,
|
||||
Flags: globalFlags(),
|
||||
},
|
||||
}
|
||||
}
|
@ -1,26 +1,126 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/thegeeklab/url-parser/internal/command"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/thegeeklab/url-parser/command"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Version of current build
|
||||
var Version = "devel"
|
||||
//nolint:gochecknoglobals
|
||||
var (
|
||||
BuildVersion = "devel"
|
||||
BuildDate = "00000000"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "url-parser"
|
||||
app.Usage = "Parse URL and shows the part of it."
|
||||
app.Version = Version
|
||||
app.Action = command.Run
|
||||
app.Flags = globalFlags()
|
||||
app.Commands = configCommands()
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
||||
cli.VersionPrinter = func(c *cli.Context) {
|
||||
fmt.Printf("%s version=%s date=%s\n", c.App.Name, c.App.Version, BuildDate)
|
||||
}
|
||||
|
||||
cfg := &config.Config{}
|
||||
|
||||
app := &cli.App{
|
||||
Name: "url-parser",
|
||||
Usage: "Parse URL and shows the part of it.",
|
||||
Version: BuildVersion,
|
||||
Action: command.Run(cfg),
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "url",
|
||||
Usage: "source url to parse",
|
||||
EnvVars: []string{"URL_PARSER_URL"},
|
||||
Destination: &cfg.URL,
|
||||
},
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Name: "all",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Get all parts from url",
|
||||
Action: command.Run(cfg),
|
||||
Flags: command.AllFlags(cfg),
|
||||
},
|
||||
{
|
||||
Name: "scheme",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Get scheme from url",
|
||||
Action: command.Scheme(cfg),
|
||||
},
|
||||
{
|
||||
Name: "user",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Get username from url",
|
||||
Action: command.User(cfg),
|
||||
},
|
||||
{
|
||||
Name: "password",
|
||||
Aliases: []string{"pw"},
|
||||
Usage: "Get password from url",
|
||||
Action: command.Password(cfg),
|
||||
},
|
||||
{
|
||||
Name: "path",
|
||||
Aliases: []string{"pt"},
|
||||
Usage: "Get path from url",
|
||||
Action: command.Path(cfg),
|
||||
Flags: command.PathFlags(cfg),
|
||||
},
|
||||
{
|
||||
Name: "host",
|
||||
Aliases: []string{"ht"},
|
||||
Usage: "Get hostname from url",
|
||||
Action: command.Host(cfg),
|
||||
},
|
||||
{
|
||||
Name: "port",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Get port from url",
|
||||
Action: command.Port(cfg),
|
||||
},
|
||||
{
|
||||
Name: "query",
|
||||
Aliases: []string{"q"},
|
||||
Usage: "Get query from url",
|
||||
Action: command.Query(cfg),
|
||||
Flags: command.QueryFlags(cfg),
|
||||
},
|
||||
{
|
||||
Name: "fragment",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "Get fragment from url",
|
||||
Action: command.Fragment(cfg),
|
||||
},
|
||||
},
|
||||
Before: func(_ *cli.Context) error {
|
||||
if cfg.URL == "" {
|
||||
stat, _ := os.Stdin.Stat()
|
||||
if (stat.Mode() & os.ModeCharDevice) == 0 {
|
||||
stdin, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error: %w: %w", config.ErrReadStdin, err)
|
||||
}
|
||||
cfg.URL = strings.TrimSuffix(string(stdin), "\n")
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.URL == "" {
|
||||
return fmt.Errorf("error: %w", config.ErrEmptyURL)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
logrus.Fatal(err)
|
||||
log.Fatal().Err(err).Msg("Execution error")
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
// +build tools
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
_ "golang.org/x/lint/golint"
|
||||
_ "honnef.co/go/tools/cmd/staticcheck"
|
||||
)
|
21
codecov.yml
21
codecov.yml
@ -1,21 +0,0 @@
|
||||
codecov:
|
||||
require_ci_to_pass: true
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 5%
|
||||
branches:
|
||||
- main
|
||||
if_ci_failed: error
|
||||
informational: false
|
||||
only_pulls: false
|
||||
patch:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 5%
|
||||
branches:
|
||||
- main
|
||||
if_ci_failed: error
|
||||
only_pulls: false
|
109
command/commands.go
Normal file
109
command/commands.go
Normal file
@ -0,0 +1,109 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
)
|
||||
|
||||
type QueryParam struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type URL struct {
|
||||
url *url.URL
|
||||
|
||||
Scheme string `json:"scheme"`
|
||||
Hostname string `json:"hostname"`
|
||||
Port string `json:"port"`
|
||||
Path string `json:"path"`
|
||||
Fragment string `json:"fragment"`
|
||||
RawQuery string `json:"rawQuery"`
|
||||
Query string `json:"-"`
|
||||
QueryParams []QueryParam `json:"queryParams"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func (u *URL) String() string {
|
||||
return u.url.String()
|
||||
}
|
||||
|
||||
type Parser struct {
|
||||
URL string
|
||||
QueryField string
|
||||
QuerySplit bool
|
||||
}
|
||||
|
||||
func NewURLParser(url, queryField string, querySplit bool) *Parser {
|
||||
return &Parser{
|
||||
URL: url,
|
||||
QueryField: queryField,
|
||||
QuerySplit: querySplit,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) parse() *URL {
|
||||
urlString := strings.TrimSpace(p.URL)
|
||||
|
||||
parts, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg(config.ErrParseURL.Error())
|
||||
}
|
||||
|
||||
extURL := &URL{
|
||||
url: parts,
|
||||
Scheme: parts.Scheme,
|
||||
Hostname: parts.Hostname(),
|
||||
Path: parts.Path,
|
||||
Fragment: parts.Fragment,
|
||||
QueryParams: []QueryParam{},
|
||||
}
|
||||
|
||||
if len(parts.Scheme) > 0 {
|
||||
extURL.Hostname = parts.Hostname()
|
||||
extURL.Port = parts.Port()
|
||||
}
|
||||
|
||||
if parts.User != nil {
|
||||
if len(parts.User.Username()) > 0 {
|
||||
extURL.Username = parts.User.Username()
|
||||
}
|
||||
}
|
||||
|
||||
if parts.User != nil {
|
||||
pw, _ := parts.User.Password()
|
||||
if len(pw) > 0 {
|
||||
extURL.Password = pw
|
||||
}
|
||||
}
|
||||
|
||||
// Handle query field extraction
|
||||
if parts.RawQuery != "" {
|
||||
extURL.RawQuery = parts.RawQuery
|
||||
}
|
||||
|
||||
if p.QueryField != "" {
|
||||
if result := parts.Query().Get(p.QueryField); result != "" {
|
||||
extURL.Query = result
|
||||
}
|
||||
} else {
|
||||
extURL.Query = parts.RawQuery
|
||||
}
|
||||
|
||||
// Handle query parameter splitting
|
||||
values := parts.Query()
|
||||
for k, v := range values {
|
||||
if len(v) > 0 {
|
||||
extURL.QueryParams = append(extURL.QueryParams, QueryParam{
|
||||
Key: k,
|
||||
Value: v[0],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return extURL
|
||||
}
|
64
command/commands_test.go
Normal file
64
command/commands_test.go
Normal file
@ -0,0 +1,64 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
//nolint:goconst
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config *config.Config
|
||||
expected *URL
|
||||
}{
|
||||
{
|
||||
name: "parse url",
|
||||
config: &config.Config{
|
||||
URL: urlString,
|
||||
QuerySplit: true,
|
||||
},
|
||||
expected: &URL{
|
||||
Scheme: "postgres",
|
||||
Username: "user",
|
||||
Password: "pass",
|
||||
Hostname: "host.com",
|
||||
Port: "5432",
|
||||
Path: "/path/to",
|
||||
Query: "key=value&other=other%20value",
|
||||
RawQuery: "key=value&other=other%20value",
|
||||
QueryParams: []QueryParam{
|
||||
{
|
||||
Key: "key",
|
||||
Value: "value",
|
||||
},
|
||||
{
|
||||
Key: "other",
|
||||
Value: "other value",
|
||||
},
|
||||
},
|
||||
Fragment: "some-fragment",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := NewURLParser(urlString, "", false).parse()
|
||||
assert.Equal(t, tt.expected.Scheme, result.Scheme)
|
||||
assert.Equal(t, tt.expected.Username, result.Username)
|
||||
assert.Equal(t, tt.expected.Password, result.Password)
|
||||
assert.Equal(t, tt.expected.Hostname, result.Hostname)
|
||||
assert.Equal(t, tt.expected.Port, result.Port)
|
||||
assert.Equal(t, tt.expected.Path, result.Path)
|
||||
assert.Equal(t, tt.expected.Fragment, result.Fragment)
|
||||
assert.Equal(t, tt.expected.RawQuery, result.RawQuery)
|
||||
assert.Equal(t, tt.expected.Query, result.Query)
|
||||
assert.ElementsMatch(t, tt.expected.QueryParams, result.QueryParams)
|
||||
})
|
||||
}
|
||||
}
|
21
command/fragment.go
Normal file
21
command/fragment.go
Normal file
@ -0,0 +1,21 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Fragment prints out the fragment part from the url.
|
||||
func Fragment(cfg *config.Config) cli.ActionFunc {
|
||||
return func(_ *cli.Context) error {
|
||||
parts := NewURLParser(cfg.URL, cfg.QueryField, cfg.QuerySplit).parse()
|
||||
|
||||
if len(parts.Scheme) > 0 {
|
||||
fmt.Println(parts.Fragment)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
37
command/fragment_test.go
Normal file
37
command/fragment_test.go
Normal file
@ -0,0 +1,37 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
func TestFragment(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config *config.Config
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "get fragment",
|
||||
config: &config.Config{URL: urlString},
|
||||
expected: "some-fragment",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { _ = Fragment(tt.config)(ctx) }))
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
21
command/host.go
Normal file
21
command/host.go
Normal file
@ -0,0 +1,21 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Host prints out the host part from the url.
|
||||
func Host(cfg *config.Config) cli.ActionFunc {
|
||||
return func(_ *cli.Context) error {
|
||||
parts := NewURLParser(cfg.URL, cfg.QueryField, cfg.QuerySplit).parse()
|
||||
|
||||
if len(parts.Scheme) > 0 {
|
||||
fmt.Println(parts.Hostname)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
37
command/host_test.go
Normal file
37
command/host_test.go
Normal file
@ -0,0 +1,37 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
func TestHost(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config *config.Config
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "get host",
|
||||
config: &config.Config{URL: urlString},
|
||||
expected: "host.com",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { _ = Host(tt.config)(ctx) }))
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
21
command/password.go
Normal file
21
command/password.go
Normal file
@ -0,0 +1,21 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Password prints out the password part from url.
|
||||
func Password(cfg *config.Config) cli.ActionFunc {
|
||||
return func(_ *cli.Context) error {
|
||||
parts := NewURLParser(cfg.URL, cfg.QueryField, cfg.QuerySplit).parse()
|
||||
|
||||
if parts.Password != "" {
|
||||
fmt.Println(parts.Password)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
37
command/password_test.go
Normal file
37
command/password_test.go
Normal file
@ -0,0 +1,37 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
func TestPassword(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config *config.Config
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "get password",
|
||||
config: &config.Config{URL: urlString},
|
||||
expected: "pass",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { _ = Password(tt.config)(ctx) }))
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
44
command/path.go
Normal file
44
command/path.go
Normal file
@ -0,0 +1,44 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// PathFlags defines flags for path subcommand.
|
||||
func PathFlags(cfg *config.Config) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.IntFlag{
|
||||
Name: "path-index",
|
||||
Usage: "filter parsed path by index",
|
||||
EnvVars: []string{"URL_PARSER_PATH_INDEX"},
|
||||
Value: -1,
|
||||
Destination: &cfg.PathIndex,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Path prints out the path part from url.
|
||||
func Path(cfg *config.Config) cli.ActionFunc {
|
||||
return func(_ *cli.Context) error {
|
||||
parts := NewURLParser(cfg.URL, cfg.QueryField, cfg.QuerySplit).parse()
|
||||
i := cfg.PathIndex
|
||||
|
||||
if len(parts.Path) > 0 {
|
||||
if i > -1 {
|
||||
path := strings.Split(parts.Path, "/")
|
||||
|
||||
if i++; i < len(path) {
|
||||
fmt.Println(path[i])
|
||||
}
|
||||
} else {
|
||||
fmt.Println(parts.Path)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
42
command/path_test.go
Normal file
42
command/path_test.go
Normal file
@ -0,0 +1,42 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
func TestPath(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config *config.Config
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "get path",
|
||||
config: &config.Config{URL: urlString, PathIndex: -1},
|
||||
expected: "/path/to",
|
||||
},
|
||||
{
|
||||
name: "get path at index",
|
||||
config: &config.Config{URL: urlString, PathIndex: 0},
|
||||
expected: "path",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { _ = Path(tt.config)(ctx) }))
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
21
command/port.go
Normal file
21
command/port.go
Normal file
@ -0,0 +1,21 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Port prints out the port from the url.
|
||||
func Port(cfg *config.Config) cli.ActionFunc {
|
||||
return func(_ *cli.Context) error {
|
||||
parts := NewURLParser(cfg.URL, cfg.QueryField, cfg.QuerySplit).parse()
|
||||
|
||||
if len(parts.Scheme) > 0 {
|
||||
fmt.Println(parts.Port)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
37
command/port_test.go
Normal file
37
command/port_test.go
Normal file
@ -0,0 +1,37 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
func TestPort(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config *config.Config
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "get port",
|
||||
config: &config.Config{URL: urlString},
|
||||
expected: "5432",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { _ = Port(tt.config)(ctx) }))
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
33
command/query.go
Normal file
33
command/query.go
Normal file
@ -0,0 +1,33 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// QueryFlags defines flags for query subcommand.
|
||||
func QueryFlags(cfg *config.Config) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "query-field",
|
||||
Usage: "filter parsed query string by field name",
|
||||
EnvVars: []string{"URL_PARSER_QUERY_FIELD"},
|
||||
Destination: &cfg.QueryField,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Query prints out the query part from url.
|
||||
func Query(cfg *config.Config) cli.ActionFunc {
|
||||
return func(_ *cli.Context) error {
|
||||
parts := NewURLParser(cfg.URL, cfg.QueryField, cfg.QuerySplit).parse()
|
||||
|
||||
if parts.Query != "" {
|
||||
fmt.Println(parts.Query)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
43
command/query_test.go
Normal file
43
command/query_test.go
Normal file
@ -0,0 +1,43 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
func TestQuery(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config *config.Config
|
||||
QueryField string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "get query",
|
||||
config: &config.Config{URL: urlString},
|
||||
expected: "key=value&other=other%20value",
|
||||
},
|
||||
{
|
||||
name: "get query field",
|
||||
config: &config.Config{URL: urlString, QueryField: "other"},
|
||||
expected: "other value",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { _ = Query(tt.config)(ctx) }))
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
39
command/run.go
Normal file
39
command/run.go
Normal file
@ -0,0 +1,39 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Run default command and print out full url.
|
||||
func Run(cfg *config.Config) cli.ActionFunc {
|
||||
return func(_ *cli.Context) error {
|
||||
parts := NewURLParser(cfg.URL, cfg.QueryField, cfg.QuerySplit).parse()
|
||||
|
||||
if len(parts.String()) > 0 {
|
||||
if cfg.JSONOutput {
|
||||
json, _ := json.Marshal(parts)
|
||||
fmt.Println(string(json))
|
||||
} else {
|
||||
fmt.Println(parts)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// AllFlags defines flags for all subcommand.
|
||||
func AllFlags(cfg *config.Config) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "json",
|
||||
Usage: "output json",
|
||||
EnvVars: []string{"URL_PARSER_JSON"},
|
||||
Destination: &cfg.JSONOutput,
|
||||
},
|
||||
}
|
||||
}
|
88
command/run_test.go
Normal file
88
command/run_test.go
Normal file
@ -0,0 +1,88 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config *config.Config
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "get url",
|
||||
config: &config.Config{URL: urlString},
|
||||
expected: urlString,
|
||||
},
|
||||
{
|
||||
name: "get url with query split",
|
||||
config: &config.Config{
|
||||
URL: urlString,
|
||||
QuerySplit: true,
|
||||
JSONOutput: true,
|
||||
},
|
||||
expected: `{
|
||||
"scheme": "postgres",
|
||||
"hostname": "host.com",
|
||||
"port": "5432",
|
||||
"path": "/path/to",
|
||||
"fragment": "some-fragment",
|
||||
"rawQuery": "key=value&other=other%20value",
|
||||
"queryParams": [
|
||||
{
|
||||
"key": "key",
|
||||
"value": "value"
|
||||
},
|
||||
{
|
||||
"key": "other",
|
||||
"value": "other value"
|
||||
}
|
||||
],
|
||||
"username": "user",
|
||||
"password": "pass"
|
||||
}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { _ = Run(tt.config)(ctx) }))
|
||||
|
||||
if tt.config.JSONOutput {
|
||||
got := &URL{}
|
||||
expected := &URL{}
|
||||
|
||||
_ = json.Unmarshal([]byte(result), &got)
|
||||
_ = json.Unmarshal([]byte(tt.expected), &expected)
|
||||
|
||||
assert.Equal(t, expected.Scheme, got.Scheme)
|
||||
assert.Equal(t, expected.Username, got.Username)
|
||||
assert.Equal(t, expected.Password, got.Password)
|
||||
assert.Equal(t, expected.Hostname, got.Hostname)
|
||||
assert.Equal(t, expected.Port, got.Port)
|
||||
assert.Equal(t, expected.Path, got.Path)
|
||||
assert.Equal(t, expected.Fragment, got.Fragment)
|
||||
assert.Equal(t, expected.RawQuery, got.RawQuery)
|
||||
assert.Equal(t, expected.Query, got.Query)
|
||||
assert.ElementsMatch(t, expected.QueryParams, got.QueryParams)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
21
command/scheme.go
Normal file
21
command/scheme.go
Normal file
@ -0,0 +1,21 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Scheme prints out the scheme part from the url.
|
||||
func Scheme(cfg *config.Config) cli.ActionFunc {
|
||||
return func(_ *cli.Context) error {
|
||||
parts := NewURLParser(cfg.URL, cfg.QueryField, cfg.QuerySplit).parse()
|
||||
|
||||
if len(parts.Scheme) > 0 {
|
||||
fmt.Println(parts.Scheme)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
37
command/scheme_test.go
Normal file
37
command/scheme_test.go
Normal file
@ -0,0 +1,37 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
func TestScheme(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config *config.Config
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "get scheme",
|
||||
config: &config.Config{URL: urlString},
|
||||
expected: "postgres",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { _ = Scheme(tt.config)(ctx) }))
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
21
command/user.go
Normal file
21
command/user.go
Normal file
@ -0,0 +1,21 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// User prints out the user part from url.
|
||||
func User(cfg *config.Config) cli.ActionFunc {
|
||||
return func(_ *cli.Context) error {
|
||||
parts := NewURLParser(cfg.URL, cfg.QueryField, cfg.QuerySplit).parse()
|
||||
|
||||
if parts.Username != "" {
|
||||
fmt.Println(parts.Username)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
37
command/user_test.go
Normal file
37
command/user_test.go
Normal file
@ -0,0 +1,37 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/thegeeklab/url-parser/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
func TestUser(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config *config.Config
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "get user",
|
||||
config: &config.Config{URL: urlString},
|
||||
expected: "user",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { _ = User(tt.config)(ctx) }))
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
17
config/config.go
Normal file
17
config/config.go
Normal file
@ -0,0 +1,17 @@
|
||||
package config
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrEmptyURL = errors.New("no url provided either by \"url\" or \"stdin\"")
|
||||
ErrReadStdin = errors.New("failed to read \"stdin\"")
|
||||
ErrParseURL = errors.New("failed to parse url")
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
URL string
|
||||
QueryField string
|
||||
QuerySplit bool
|
||||
PathIndex int
|
||||
JSONOutput bool
|
||||
}
|
25
go.mod
25
go.mod
@ -1,15 +1,22 @@
|
||||
module github.com/thegeeklab/url-parser
|
||||
|
||||
go 1.16
|
||||
go 1.23.3
|
||||
|
||||
require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/urfave/cli/v2 v2.27.5
|
||||
github.com/zenizh/go-capturer v0.0.0-20211219060012-52ea6c8fed04
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096 // indirect
|
||||
honnef.co/go/tools v0.2.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
75
go.sum
75
go.sum
@ -1,58 +1,35 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
|
||||
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||
github.com/zenizh/go-capturer v0.0.0-20211219060012-52ea6c8fed04 h1:qXafrlZL1WsJW5OokjraLLRURHiw0OzKHD/RNdspp4w=
|
||||
github.com/zenizh/go-capturer v0.0.0-20211219060012-52ea6c8fed04/go.mod h1:FiwNQxz6hGoNFBC4nIx+CxZhI3nne5RmIOlT/MXcSD4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096 h1:5PbJGn5Sp3GEUjJ61aYbUP6RIo3Z3r2E4Tv9y2z8UHo=
|
||||
golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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/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-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.2.2 h1:MNh1AVMyVX23VUHE2O27jm6lNj3vjO5DexS4A1xvnzk=
|
||||
honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -1,19 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func parseURL(raw string) *url.URL {
|
||||
urlString := strings.TrimSpace(raw)
|
||||
|
||||
url, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package command
|
||||
|
||||
import "testing"
|
||||
|
||||
type TestParseData struct {
|
||||
urlString string
|
||||
expected string
|
||||
}
|
||||
|
||||
func TestParseURL(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tables := []TestParseData{
|
||||
{
|
||||
urlString: urlString,
|
||||
expected: urlString,
|
||||
},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
result := parseURL(urlString)
|
||||
|
||||
if result.String() != table.expected {
|
||||
t.Fatalf("URL `%v`, should be `%v`", result, table.expected)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Fragment prints out the fragment part from the url
|
||||
func Fragment(ctx *cli.Context) error {
|
||||
parts := parseURL(ctx.String("url"))
|
||||
|
||||
if len(parts.Scheme) > 0 {
|
||||
fmt.Println(parts.Fragment)
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
type TestFragmentData struct {
|
||||
urlString string
|
||||
expected string
|
||||
}
|
||||
|
||||
func TestFragment(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tables := []TestFragmentData{
|
||||
{
|
||||
urlString: urlString,
|
||||
expected: "some-fragment",
|
||||
},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("url", table.urlString, "test url")
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { Fragment(c) }))
|
||||
|
||||
if result != table.expected {
|
||||
t.Fatalf("URL fragment `%v`, should be `%v`", result, table.expected)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Host prints out the host part from the url
|
||||
func Host(ctx *cli.Context) error {
|
||||
parts := parseURL(ctx.String("url"))
|
||||
|
||||
if len(parts.Scheme) > 0 {
|
||||
fmt.Println(parts.Hostname())
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
type TestHostnameData struct {
|
||||
urlString string
|
||||
expected string
|
||||
}
|
||||
|
||||
func TestHost(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tables := []TestHostnameData{
|
||||
{
|
||||
urlString: urlString,
|
||||
expected: "host.com",
|
||||
},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("url", table.urlString, "test url")
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { Host(c) }))
|
||||
|
||||
if result != table.expected {
|
||||
t.Fatalf("URL host `%v`, should be `%v`", result, table.expected)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Password prints out the password part from url
|
||||
func Password(ctx *cli.Context) error {
|
||||
parts := parseURL(ctx.String("url"))
|
||||
|
||||
if parts.User != nil {
|
||||
pw, _ := parts.User.Password()
|
||||
if len(pw) > 0 {
|
||||
fmt.Println(pw)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
type TestPasswordData struct {
|
||||
urlString string
|
||||
expected string
|
||||
}
|
||||
|
||||
func TestPassword(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tables := []TestPasswordData{
|
||||
{
|
||||
urlString: urlString,
|
||||
expected: "pass",
|
||||
},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("url", table.urlString, "test url")
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { Password(c) }))
|
||||
|
||||
if result != table.expected {
|
||||
t.Fatalf("URL password `%v`, should be `%v`", result, table.expected)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// PathFlags defines flags for path subcommand
|
||||
func PathFlags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.IntFlag{
|
||||
Name: "path-index",
|
||||
Usage: "filter parsed path by index",
|
||||
EnvVars: []string{"URL_PARSER_PATH_INDEX"},
|
||||
Value: -1,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Path prints out the path part from url
|
||||
func Path(ctx *cli.Context) error {
|
||||
parts := parseURL(ctx.String("url"))
|
||||
i := ctx.Int("path-index")
|
||||
|
||||
if len(parts.Path) > 0 {
|
||||
if i > -1 {
|
||||
path := strings.Split(parts.Path, "/")
|
||||
|
||||
if i = i + 1; i < len(path) {
|
||||
fmt.Println(path[i])
|
||||
}
|
||||
} else {
|
||||
fmt.Println(parts.Path)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
type TestPathData struct {
|
||||
urlString string
|
||||
pathIndex int
|
||||
expected string
|
||||
}
|
||||
|
||||
func TestPath(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tables := []TestPathData{
|
||||
{
|
||||
urlString: urlString,
|
||||
pathIndex: -1,
|
||||
expected: "/path/to",
|
||||
},
|
||||
{
|
||||
urlString: urlString,
|
||||
pathIndex: 0,
|
||||
expected: "path",
|
||||
},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("url", table.urlString, "test url")
|
||||
set.Int("path-index", table.pathIndex, "index")
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { Path(c) }))
|
||||
|
||||
if result != table.expected {
|
||||
t.Fatalf("URL path `%v`, should be `%v`", result, table.expected)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Port prints out the port from the url
|
||||
func Port(ctx *cli.Context) error {
|
||||
parts := parseURL(ctx.String("url"))
|
||||
|
||||
if len(parts.Scheme) > 0 {
|
||||
fmt.Println(parts.Port())
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
type TestPortData struct {
|
||||
urlString string
|
||||
expected string
|
||||
}
|
||||
|
||||
func TestPort(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tables := []TestPortData{
|
||||
{
|
||||
urlString: urlString,
|
||||
expected: "5432",
|
||||
},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("url", table.urlString, "test url")
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { Port(c) }))
|
||||
|
||||
if result != table.expected {
|
||||
t.Fatalf("URL port `%v`, should be `%v`", result, table.expected)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// QueryFlags defines flags for query subcommand
|
||||
func QueryFlags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "query-field",
|
||||
Usage: "filter parsed query string by field name",
|
||||
EnvVars: []string{"URL_PARSER_QUERY_FIELD"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Query prints out the query part from url
|
||||
func Query(ctx *cli.Context) error {
|
||||
parts := parseURL(ctx.String("url"))
|
||||
f := ctx.String("query-field")
|
||||
|
||||
if len(parts.RawQuery) > 0 {
|
||||
if f != "" {
|
||||
if result := parts.Query().Get(f); result != "" {
|
||||
fmt.Println(result)
|
||||
}
|
||||
} else {
|
||||
fmt.Println(parts.RawQuery)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
type TestQueryData struct {
|
||||
urlString string
|
||||
QueryField string
|
||||
expected string
|
||||
}
|
||||
|
||||
func TestQuery(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tables := []TestQueryData{
|
||||
{
|
||||
urlString: urlString,
|
||||
expected: "key=value&other=other%20value",
|
||||
},
|
||||
{
|
||||
urlString: urlString,
|
||||
QueryField: "other",
|
||||
expected: "other value",
|
||||
},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("url", table.urlString, "test url")
|
||||
set.String("query-field", table.QueryField, "index")
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { Query(c) }))
|
||||
|
||||
if result != table.expected {
|
||||
t.Fatalf("URL query `%v`, should be `%v`", result, table.expected)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Run default command and print out full url
|
||||
func Run(ctx *cli.Context) error {
|
||||
parts := parseURL(ctx.String("url"))
|
||||
|
||||
if len(parts.String()) > 0 {
|
||||
fmt.Println(parts)
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
type TestRunData struct {
|
||||
urlString string
|
||||
expected string
|
||||
}
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tables := []TestRunData{
|
||||
{
|
||||
urlString: urlString,
|
||||
expected: urlString,
|
||||
},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("url", table.urlString, "test url")
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { Run(c) }))
|
||||
|
||||
if result != table.expected {
|
||||
t.Fatalf("URL `%v`, should be `%v`", result, table.expected)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Scheme prints out the scheme part from the url
|
||||
func Scheme(ctx *cli.Context) error {
|
||||
parts := parseURL(ctx.String("url"))
|
||||
|
||||
if len(parts.Scheme) > 0 {
|
||||
fmt.Println(parts.Scheme)
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
type TestSchemeData struct {
|
||||
urlString string
|
||||
expected string
|
||||
}
|
||||
|
||||
func TestScheme(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tables := []TestSchemeData{
|
||||
{
|
||||
urlString: urlString,
|
||||
expected: "postgres",
|
||||
},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("url", table.urlString, "test url")
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { Scheme(c) }))
|
||||
|
||||
if result != table.expected {
|
||||
t.Fatalf("URL scheme `%v`, should be `%v`", result, table.expected)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// User prints out the user part from url
|
||||
func User(ctx *cli.Context) error {
|
||||
parts := parseURL(ctx.String("url"))
|
||||
|
||||
if parts.User != nil {
|
||||
if len(parts.User.Username()) > 0 {
|
||||
fmt.Println(parts.User.Username())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/zenizh/go-capturer"
|
||||
)
|
||||
|
||||
type TestUserData struct {
|
||||
urlString string
|
||||
expected string
|
||||
}
|
||||
|
||||
func TestUser(t *testing.T) {
|
||||
urlString := "postgres://user:pass@host.com:5432/path/to?key=value&other=other%20value#some-fragment"
|
||||
|
||||
tables := []TestUserData{
|
||||
{
|
||||
urlString: urlString,
|
||||
expected: "user",
|
||||
},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("url", table.urlString, "test url")
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
result := strings.TrimSpace(capturer.CaptureStdout(func() { User(c) }))
|
||||
|
||||
if result != table.expected {
|
||||
t.Fatalf("URL user `%v`, should be `%v`", result, table.expected)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user