Compare commits

..

11 commits

Author SHA1 Message Date
0a0fc645fc
Merge branch 'beta'
All checks were successful
Release / Semantic Release (push) Successful in 58s
Build / Checks (push) Successful in 38s
Build / Code Coverage (push) Successful in 47s
Build / Build (push) Successful in 31s
2025-03-01 13:50:43 +01:00
107c873b4b
ci: merge dependency updates into develop branch
All checks were successful
Build / Checks (push) Successful in 33s
Build / Code Coverage (push) Successful in 48s
Build / Build (push) Successful in 38s
Release / Semantic Release (push) Successful in 47s
2025-03-01 13:26:56 +01:00
851ecb345a
chore: Configure Renovate (#1)
Reviewed-on: #1
2025-03-01 13:26:56 +01:00
f4ceca90ab
ci: merge dependency updates into develop branch 2025-03-01 13:26:00 +01:00
b4cff38dca chore: Configure Renovate (#1)
Reviewed-on: #1
2025-03-01 12:22:47 +00:00
7b5e1d0254
feat: new release of version 4
All checks were successful
Build / Checks (push) Successful in 34s
Build / Code Coverage (push) Successful in 45s
Build / Build (push) Successful in 33s
2025-02-28 15:46:06 +01:00
18a84b9b92
style: removed unnecessary braces and else if statements
All checks were successful
Build / Checks (push) Successful in 34s
Build / Code Coverage (push) Successful in 44s
Build / Build (push) Successful in 34s
2025-02-27 20:43:46 +01:00
8d8f8b0c99
style: fixed typo 2025-02-27 20:42:57 +01:00
203438dc8c
ci: new build pipeline 2025-02-27 20:41:08 +01:00
ceb7d04edd
ci: new release workflow 2025-02-27 20:39:15 +01:00
2fb1b35713
feat: renamed goHTTPRouter to httprouter
BREAKING CHANGE: new package name git.martin-riedl.de/golang/httprouter
2025-02-27 20:34:47 +01:00
14 changed files with 193 additions and 181 deletions

View file

@ -0,0 +1,81 @@
name: Build
on:
push:
branches:
- main
- beta
- develop
pull_request:
jobs:
checks:
name: Checks
runs-on: docker
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23.x'
check-latest: true
- name: Run go fmt and go vet
run: |
go fmt $(go list ./...)
go vet $(go list ./...)
code-coverage:
name: Code Coverage
runs-on: docker
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23.x'
check-latest: true
- name: Run tests and generate coverage report
run: |
go test -covermode=count -coverprofile coverage.cov $(go list ./...)
go tool cover -func=coverage.cov
go tool cover -html=coverage.cov -o coverage.html
- name: Upload coverage artifacts
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
with:
name: coverage-reports
path: |
coverage.cov
coverage.html
build:
name: Build
runs-on: docker
strategy:
matrix:
go:
- GOOS: darwin
GOARCH: amd64
- GOOS: darwin
GOARCH: arm64
- GOOS: linux
GOARCH: amd64
- GOOS: linux
GOARCH: arm64
- GOOS: windows
GOARCH: amd64
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23.x'
check-latest: true
- name: Set environment variables
run: |
echo "GOOS=${{ matrix.go.GOOS }}" >> $GITHUB_ENV
echo "GOARCH=${{ matrix.go.GOARCH }}" >> $GITHUB_ENV
- name: Build
run: go build .

View file

@ -0,0 +1,20 @@
name: Release
on:
push:
branches:
- main
- beta
jobs:
release:
name: Semantic Release
runs-on: docker
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Semantic Release
shell: bash
run: |
npm install -g semantic-release@23 conventional-changelog-conventionalcommits@7
semantic-release

View file

@ -1,135 +0,0 @@
image: golang:1.19
stages:
- test
- build
- pre-release
checks:
stage: test
script:
- go fmt $(go list ./...)
- go vet $(go list ./...)
tags:
- docker
code coverage:
stage: test
script:
- go install honnef.co/go/tools/cmd/staticcheck@latest
- go fmt $(go list ./...)
- go vet $(go list ./...)
- staticcheck ./...
- go test -coverprofile coverage.cov -p 1 $(go list ./...)
- go tool cover -html=coverage.cov -o coverage.html
- go tool cover -func=coverage.cov
coverage: '/\(statements\)\W+\d+\.\d+%/'
artifacts:
paths:
- coverage.cov
- coverage.html
tags:
- docker
codecov.io:
stage: test
script:
- curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --import
- curl -Os https://uploader.codecov.io/latest/linux/codecov
- curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM
- curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM.sig
- gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM
- shasum -a 256 -c codecov.SHA256SUM
- chmod +x codecov
- go test -race -coverprofile=coverage.out -covermode=atomic
- ./codecov -t ${CODECOV_TOKEN}
rules:
- if: $CODECOV_TOKEN
when: on_success
tags:
- docker
# stage "sonarcloud" is only needed because of this issue:
# https://gitlab.com/gitlab-org/gitlab/-/issues/30632
sonarcloud-check:
stage: test
needs:
- checks
image:
name: sonarsource/sonar-scanner-cli:latest
entrypoint: [""]
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
cache:
key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
script:
- sonar-scanner
tags:
- docker
allow_failure: true
# build template
# execute the following command for all os/arch combinations: go tool dist list
.compile:
stage: build
# no dependencies -> no download of artifacts from previous jobs/stages
dependencies: []
script:
- go build .
tags:
- docker
darwin-amd64:
extends: .compile
variables:
GOOS: "darwin"
GOARCH: "amd64"
linux-amd64:
extends: .compile
variables:
GOOS: "linux"
GOARCH: "amd64"
linux-arm64:
extends: .compile
variables:
GOOS: "linux"
GOARCH: "arm64"
windows-amd64:
extends: .compile
variables:
GOOS: "windows"
GOARCH: "amd64"
.semantic-release:
stage: pre-release
image: node:20-buster-slim
dependencies: []
before_script:
- apt-get update && apt-get install -y --no-install-recommends git-core ca-certificates
- npm install -g semantic-release@23 @semantic-release/gitlab@13 conventional-changelog-conventionalcommits@7
script:
- semantic-release -d $DRY_RUN
variables:
GL_TOKEN: $SEMANTIC_RELEASE_TOKEN
DRY_RUN: "false"
tags:
- docker
semantic-release-dry-run:
extends: .semantic-release
variables:
DRY_RUN: "true"
rules:
- if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "beta"'
semantic-release:
extends: .semantic-release
rules:
- if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "beta"'
when: manual

View file

@ -61,6 +61,12 @@
}
}
],
"@semantic-release/gitlab"
[
"@semantic-release/github",
{
"successCommentCondition": false,
"failTitle": false
}
]
]
}

View file

@ -1,17 +1,19 @@
# goHTTPRouter
# httprouter
[![release](https://git.martin-riedl.de/golang/httprouter/badges/release.svg)](https://git.martin-riedl.de/golang/httprouter/tags)
[![pipeline status](https://git.martin-riedl.de/golang/httprouter/badges/workflows/build.yml/badge.svg)](https://git.martin-riedl.de/golang/httprouter/actions)
[![GoDoc](https://godoc.org/gitlab.com/martinr92/gohttprouter?status.svg)](https://godoc.org/gitlab.com/martinr92/gohttprouter)
[![pipeline status](https://gitlab.com/martinr92/gohttprouter/badges/master/pipeline.svg)](https://gitlab.com/martinr92/gohttprouter/commits/master)
[![coverage report](https://gitlab.com/martinr92/gohttprouter/badges/master/coverage.svg)](https://gitlab.com/martinr92/gohttprouter/commits/master)
[![codecov](https://codecov.io/gl/martinr92/gohttprouter/branch/master/graph/badge.svg)](https://codecov.io/gl/martinr92/gohttprouter)
[![Go Report Card](https://goreportcard.com/badge/gitlab.com/martinr92/gohttprouter)](https://goreportcard.com/report/gitlab.com/martinr92/gohttprouter)
goHTTPRouter is a framework used for HTTP request routing.
httprouter is a framework used for HTTP request routing.
# Examples
## Simple Routing
Just replace the standard router of golang with this one:
```golang
import httprouter "gitlab.com/martinr92/gohttprouter/v3"
import "git.martin-riedl.de/golang/httprouter/v4"
```
```golang
router := httprouter.New()
@ -22,9 +24,10 @@ err := http.ListenAndServe("localhost:8080", router)
```
## Routing with placeholder
A path can also contain placeholder (like :id). If then a request is sent to the url "/user/123" the method gets executed and the URL part (in this case "123") is passed as parameter into your handler function.
```golang
import httprouter "gitlab.com/martinr92/gohttprouter/v3"
import "git.martin-riedl.de/golang/httprouter/v4"
```
```golang
router := httprouter.New()
@ -38,11 +41,12 @@ err := http.ListenAndServe("localhost:8080", router)
```
## Serve Static Content
Static files (like JavaScript or CSS) can be served automatically (including caching header and MIME type). It uses the `embed.FS` (since go 1.16) to serve static content.
```golang
import httprouter "gitlab.com/martinr92/gohttprouter/v3"
import "git.martin-riedl.de/golang/httprouter/v4"
//go:embed files/statc/*
//go:embed files/static/*
var staticFiles embed.FS
```
```golang
@ -51,9 +55,12 @@ router := httprouter.New()
router.Handle(http.MethodGet, "/static/*", staticFS)
```
For development purpose you can enable the local file serving additionally. The framework checks first, if the file exists locally and serves it directly. If not, the file is served from the `embed.FS`. This helps you during local development so you can modify a CSS file without recompiling everything.
For development purpose you can enable the local file serving additionally.
The framework checks first, if the file exists locally and serves it directly.
If not, the file is served from the `embed.FS`.
This helps you during local development so you can modify a CSS file without recompiling everything.
```golang
import httprouter "gitlab.com/martinr92/gohttprouter/v3"
import "git.martin-riedl.de/golang/httprouter/v4"
```
```golang
staticFS := httprouter.NewFS(&staticFiles)
@ -62,8 +69,9 @@ staticFS.LocalFolderPrefix = "some/folder" // optional
```
# License
```
Copyright 2018-2021 Martin Riedl
Copyright 2018-2025 Martin Riedl
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

4
fs.go
View file

@ -1,4 +1,4 @@
// Copyright 2021 Martin Riedl
// Copyright 2021-2025 Martin Riedl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package gohttprouter
package httprouter
import (
"embed"

View file

@ -1,4 +1,18 @@
package gohttprouter
// Copyright 2025 Martin Riedl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httprouter
import (
"embed"

2
go.mod
View file

@ -1,3 +1,3 @@
module gitlab.com/martinr92/gohttprouter/v3
module git.martin-riedl.de/golang/httprouter/v4
go 1.19

9
renovate.json Normal file
View file

@ -0,0 +1,9 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"local>ci/renovate//configs/base"
],
"baseBranches": [
"develop"
]
}

View file

@ -1,4 +1,4 @@
// Copyright 2018-2021 Martin Riedl
// Copyright 2018-2025 Martin Riedl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package gohttprouter
package httprouter
import (
"strings"
@ -82,7 +82,7 @@ func (r *route) parsePath(path string, create bool) (*route, bool, map[string]st
if !ok && !create {
// no route found
return nil, false, nil
} else if !ok && create {
} else if !ok {
subRoute = newRoute()
subRoute.parseName(subName)
r.routes[subRoute.name] = subRoute
@ -91,7 +91,7 @@ func (r *route) parsePath(path string, create bool) (*route, bool, map[string]st
// parse sub-route
matchingRoute, created, subParameters := subRoute.parsePath(parts[1], create)
return matchingRoute, (subRouteCreated || created), mergeParameterMaps(parameters, subParameters)
return matchingRoute, subRouteCreated || created, mergeParameterMaps(parameters, subParameters)
}
// last element in path

View file

@ -1,4 +1,18 @@
package gohttprouter
// Copyright 2025 Martin Riedl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httprouter
import (
"testing"
@ -59,7 +73,7 @@ func TestRoutePlaceholder(t *testing.T) {
t.Error("error during placeholder name validation;", placeholderElement.placeholderName)
}
// check path finder
// check pathfinder
foundRoute, _, foundParameters := route.parsePath("/user/123/home/martin", false)
if foundRoute != homePathElement.routes[":"] {
t.Error("wrong path element returned form path finding")

View file

@ -1,4 +1,4 @@
// Copyright 2018-2021 Martin Riedl
// Copyright 2018-2025 Martin Riedl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package gohttprouter
package httprouter
import (
"fmt"
@ -85,7 +85,7 @@ func (router *Router) findRoute(method string, path string, create bool) (route
methodRoute, ok := router.registry[methodUpper]
if !ok && !create {
return nil, false, nil
} else if !ok && create {
} else if !ok {
methodRoute = newRoute()
router.registry[methodUpper] = methodRoute
created = true

View file

@ -1,4 +1,18 @@
package gohttprouter
// Copyright 2025 Martin Riedl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httprouter
import (
"net"

View file

@ -1,19 +0,0 @@
sonar.projectKey=martinr92_gohttprouter
sonar.organization=martinr92
# This is the name and version displayed in the SonarCloud UI.
#sonar.projectName=goHTTPRouter
#sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
sonar.sources=.
sonar.exclusions=**/*_test.go,coverage.cov,coverage.html
sonar.tests=.
sonar.test.inclusions=**/*_test.go
# Encoding of the source code. Default is default system encoding
#sonar.sourceEncoding=UTF-8
# Golang
sonar.go.coverage.reportPaths=coverage.cov