ci: migrate from Woodpecker CI to Forgejo Actions #1
23 changed files with 342 additions and 332 deletions
7
.dockerignore
Normal file
7
.dockerignore
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
hako
|
||||||
|
hako.db
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
devdata/
|
||||||
|
.git/
|
||||||
|
webapp/node_modules/
|
||||||
110
.github/workflows/ci.yml
vendored
Normal file
110
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
pull_request:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
format:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install make
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends make
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
- uses: actions/setup-go@v7
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
- run: make format
|
||||||
|
- run: git diff --exit-code
|
||||||
|
|
||||||
|
goreleaser-lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
- uses: goreleaser/goreleaser-action@v6.4.0
|
||||||
|
with:
|
||||||
|
args: check
|
||||||
|
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install make
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends make
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
- uses: actions/setup-go@v7
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
- run: make ci-lint
|
||||||
|
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install make
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends make build-essential
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
- uses: actions/setup-go@v7
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
- run: make test
|
||||||
|
|
||||||
|
e2e:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
services:
|
||||||
|
dind:
|
||||||
|
image: docker:27-dind
|
||||||
|
env:
|
||||||
|
DOCKER_TLS_CERTDIR: ""
|
||||||
|
# GitHub honours this. The Forgejo runner ignores a workflow's options
|
||||||
|
# and takes `privileged` from its own config, which is set there.
|
||||||
|
options: --privileged
|
||||||
|
# containerd takes a shade over ten seconds to boot on this runner and
|
||||||
|
# dockerd waits exactly ten, so the first attempt always dies with
|
||||||
|
# "timeout waiting for containerd to start". The second one wins.
|
||||||
|
cmd:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- >-
|
||||||
|
for i in 1 2 3 4 5; do
|
||||||
|
dockerd-entrypoint.sh dockerd --host=tcp://0.0.0.0:2375 --host=unix:///var/run/docker.sock && break;
|
||||||
|
echo "dockerd attempt $i failed, retrying" >&2;
|
||||||
|
sleep 2;
|
||||||
|
done
|
||||||
|
env:
|
||||||
|
DOCKER_HOST: tcp://dind:2375
|
||||||
|
TESTCONTAINERS_RYUK_DISABLED: true
|
||||||
|
steps:
|
||||||
|
- name: Install make
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends make
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
- uses: actions/setup-go@v7
|
||||||
|
with:
|
||||||
|
go-version-file: e2e/go.mod
|
||||||
|
- uses: oven-sh/setup-bun@v2
|
||||||
|
- name: Wait for Docker
|
||||||
|
run: |
|
||||||
|
for i in $(seq 1 120); do
|
||||||
|
docker info >/dev/null 2>&1 && exit 0
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo "Docker daemon not ready" >&2
|
||||||
|
exit 1
|
||||||
|
- name: Install Playwright browsers
|
||||||
|
run: make e2e-install
|
||||||
|
- run: make e2e
|
||||||
|
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install make and UPX
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends make upx-ucl
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
- uses: actions/setup-go@v7
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
- uses: oven-sh/setup-bun@v2
|
||||||
|
- uses: goreleaser/goreleaser-action@v6.4.0
|
||||||
|
with:
|
||||||
|
install-only: true
|
||||||
|
- run: make build
|
||||||
41
.github/workflows/release.yml
vendored
Normal file
41
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ["v*"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install make and UPX
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends make upx-ucl
|
||||||
|
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v7
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
- name: Install Bun
|
||||||
|
uses: oven-sh/setup-bun@v2
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Login to container registry
|
||||||
|
run: echo "${{ secrets.FORGEJO_TOKEN }}" | docker login git.nakama.town -u ${{ github.actor }} --password-stdin
|
||||||
|
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v6.4.0
|
||||||
|
with:
|
||||||
|
args: release --clean
|
||||||
|
env:
|
||||||
|
GORELEASER_FORCE_TOKEN: gitea
|
||||||
|
GITEA_TOKEN: ${{ secrets.FORGEJO_TOKEN }}
|
||||||
|
|
@ -57,6 +57,7 @@ dockers_v2:
|
||||||
- "git.nakama.town/fmartingr/hako"
|
- "git.nakama.town/fmartingr/hako"
|
||||||
tags:
|
tags:
|
||||||
- "{{ .Version }}"
|
- "{{ .Version }}"
|
||||||
|
- latest
|
||||||
dockerfile: Containerfile
|
dockerfile: Containerfile
|
||||||
platforms:
|
platforms:
|
||||||
- linux/amd64
|
- linux/amd64
|
||||||
|
|
@ -65,7 +66,7 @@ dockers_v2:
|
||||||
|
|
||||||
nfpms:
|
nfpms:
|
||||||
- maintainer: Felipe Martin <me@fmartingr.com>
|
- maintainer: Felipe Martin <me@fmartingr.com>
|
||||||
description: SMTP server to forward messages to shoutrrr endpoints
|
description: Self-hosted link archival service
|
||||||
homepage: https://git.nakama.town/fmartingr/hako
|
homepage: https://git.nakama.town/fmartingr/hako
|
||||||
license: AGPL-3.0
|
license: AGPL-3.0
|
||||||
formats:
|
formats:
|
||||||
|
|
@ -119,4 +120,7 @@ changelog:
|
||||||
- "^chore\\(deps\\):"
|
- "^chore\\(deps\\):"
|
||||||
|
|
||||||
release:
|
release:
|
||||||
|
gitea:
|
||||||
|
owner: fmartingr
|
||||||
|
name: hako
|
||||||
prerelease: auto
|
prerelease: auto
|
||||||
|
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
when:
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
- pull_request
|
|
||||||
branch:
|
|
||||||
- main
|
|
||||||
|
|
||||||
steps:
|
|
||||||
format:
|
|
||||||
image: golang:1.24
|
|
||||||
commands:
|
|
||||||
- make format
|
|
||||||
- git diff --exit-code # Fail if files were changed
|
|
||||||
|
|
||||||
lint-goreleaser:
|
|
||||||
image: goreleaser/goreleaser:latest
|
|
||||||
commands:
|
|
||||||
- goreleaser check
|
|
||||||
|
|
||||||
lint:
|
|
||||||
image: golang:1.24
|
|
||||||
commands:
|
|
||||||
- make ci-lint
|
|
||||||
|
|
||||||
test:
|
|
||||||
image: golang:1.24
|
|
||||||
commands:
|
|
||||||
- make test
|
|
||||||
|
|
||||||
e2e:
|
|
||||||
image: golang:1.24
|
|
||||||
environment:
|
|
||||||
TESTCONTAINERS_RYUK_DISABLED: true
|
|
||||||
DOCKER_HOST: unix:///var/run/docker.sock
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
commands:
|
|
||||||
# Install system dependencies
|
|
||||||
- apt-get update && apt-get install -y docker.io curl unzip
|
|
||||||
|
|
||||||
# Install Bun for webapp build
|
|
||||||
- curl -fsSL https://bun.sh/install | bash
|
|
||||||
- export PATH="$HOME/.bun/bin:$PATH"
|
|
||||||
|
|
||||||
# Install Playwright browsers
|
|
||||||
- go run github.com/playwright-community/playwright-go/cmd/playwright@latest install --with-deps chromium
|
|
||||||
|
|
||||||
# Run e2e tests
|
|
||||||
- make e2e
|
|
||||||
when:
|
|
||||||
status: [success, failure]
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
when:
|
|
||||||
- event: tag
|
|
||||||
branch: main
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Release
|
|
||||||
image: ubuntu:24.04
|
|
||||||
environment:
|
|
||||||
GITEA_TOKEN:
|
|
||||||
from_secret: GITEA_TOKEN
|
|
||||||
DOCKER_HOST: unix:///var/run/docker.sock
|
|
||||||
volumes:
|
|
||||||
- "/var/run/docker.sock:/var/run/docker.sock"
|
|
||||||
commands:
|
|
||||||
# Install system dependencies
|
|
||||||
- apt-get update
|
|
||||||
- apt-get install -y ca-certificates curl git make wget unzip upx-ucl
|
|
||||||
|
|
||||||
# Install Docker from official repository (for buildx support)
|
|
||||||
- curl -fsSL https://get.docker.com | sh
|
|
||||||
|
|
||||||
# Install Go 1.23
|
|
||||||
- wget -q https://go.dev/dl/go1.23.5.linux-amd64.tar.gz
|
|
||||||
- tar -C /usr/local -xzf go1.23.5.linux-amd64.tar.gz
|
|
||||||
- rm go1.23.5.linux-amd64.tar.gz
|
|
||||||
- export PATH="/usr/local/go/bin:$HOME/go/bin:$PATH"
|
|
||||||
|
|
||||||
# Install GoReleaser via go install
|
|
||||||
- go install github.com/goreleaser/goreleaser/v2@latest
|
|
||||||
|
|
||||||
# Install Bun (using official installer)
|
|
||||||
- curl -fsSL https://bun.sh/install | bash
|
|
||||||
- export PATH="$HOME/.bun/bin:$PATH"
|
|
||||||
|
|
||||||
# Setup Docker buildx for multi-platform builds
|
|
||||||
- docker buildx create --use --name multiplatform --driver docker-container
|
|
||||||
|
|
||||||
# Verify installations
|
|
||||||
- docker --version
|
|
||||||
- docker buildx version
|
|
||||||
- goreleaser --version
|
|
||||||
- bun --version
|
|
||||||
- upx --version
|
|
||||||
|
|
||||||
# Authenticate and release
|
|
||||||
- docker login -u fmartingr -p $GITEA_TOKEN git.nakama.town
|
|
||||||
- goreleaser release --clean
|
|
||||||
|
|
@ -1,36 +1,20 @@
|
||||||
# This file is used directly by the goreleaser build
|
FROM alpine:3.23
|
||||||
# It is used to build the final container image
|
|
||||||
# To build the image locally use make build-docker
|
|
||||||
|
|
||||||
# Runtime image
|
|
||||||
FROM alpine:3.20
|
|
||||||
LABEL maintainer="Felipe Martin <me@fmartingr.com>"
|
LABEL maintainer="Felipe Martin <me@fmartingr.com>"
|
||||||
LABEL org.opencontainers.image.source="https://git.nakama.town/fmartingr/hako"
|
LABEL org.opencontainers.image.source="https://git.nakama.town/fmartingr/hako"
|
||||||
|
|
||||||
# Install runtime dependencies (yt-dlp and ffmpeg for video archival from Alpine community)
|
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
poppler-utils \
|
poppler-utils \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
tzdata \
|
tzdata \
|
||||||
&& apk add --no-cache --repository https://dl-cdn.alpinelinux.org/alpine/v3.20/community yt-dlp ffmpeg
|
&& apk add --no-cache --repository https://dl-cdn.alpinelinux.org/alpine/v3.23/community yt-dlp ffmpeg
|
||||||
|
|
||||||
# Create non-root user
|
RUN addgroup -g 1000 hako && adduser -u 1000 -G hako -s /bin/sh -D hako
|
||||||
RUN addgroup -g 1000 hako && \
|
|
||||||
adduser -D -u 1000 -G hako hako
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
COPY hako /usr/local/bin/hako
|
||||||
|
RUN chown -R hako:hako /app
|
||||||
|
|
||||||
# Copy binary from goreleaser build context
|
|
||||||
# With dockers_v2, goreleaser provides the pre-built binary at $TARGETPLATFORM/hako
|
|
||||||
# The binary already has the webapp embedded via //go:embed
|
|
||||||
ARG TARGETPLATFORM
|
|
||||||
COPY ${TARGETPLATFORM}/hako /usr/local/bin/hako
|
|
||||||
RUN chmod +x /usr/local/bin/hako && \
|
|
||||||
chown -R hako:hako /app
|
|
||||||
|
|
||||||
# Switch to non-root user
|
|
||||||
USER hako
|
USER hako
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/local/bin/hako"]
|
ENTRYPOINT ["/usr/local/bin/hako"]
|
||||||
|
|
|
||||||
166
Makefile
166
Makefile
|
|
@ -1,156 +1,108 @@
|
||||||
PROJECT_NAME := hako
|
PROJECT_NAME := hako
|
||||||
|
|
||||||
SOURCE_FILES ?=./...
|
|
||||||
|
|
||||||
TEST_OPTIONS ?= -v -failfast -race -bench=. -benchtime=100000x -cover -coverprofile=coverage.out
|
|
||||||
TEST_TIMEOUT ?=1m
|
|
||||||
|
|
||||||
GOLANGCI_LINT_VERSION ?= v1.64.5
|
|
||||||
|
|
||||||
CLEAN_OPTIONS ?=-modcache -testcache
|
|
||||||
|
|
||||||
CGO_ENABLED := 0
|
CGO_ENABLED := 0
|
||||||
|
|
||||||
BUILDS_PATH := ./dist
|
DIST_PATH := ./dist
|
||||||
FROM_MAKEFILE := y
|
TEST_OPTIONS := -v -failfast -race -bench=. -benchtime=100000x -cover -coverprofile=coverage.out
|
||||||
|
TEST_TIMEOUT := 5m
|
||||||
|
|
||||||
CONTAINERFILE_NAME := Containerfile
|
GOLANGCI_LINT_VERSION := v1.64.5
|
||||||
CONTAINER_ALPINE_VERSION := 3.20
|
|
||||||
CONTAINER_SOURCE_URL := "https://git.nakama.town/fmartingr/${PROJECT_NAME}"
|
|
||||||
CONTAINER_MAINTAINER := "Felipe Martin <me@fmartingr.com>"
|
|
||||||
CONTAINER_BIN_NAME := ${PROJECT_NAME}
|
|
||||||
|
|
||||||
BUILDX_PLATFORMS := linux/amd64,linux/arm64,linux/arm/v7
|
# The Playwright CLI must match the module the e2e tests link against.
|
||||||
|
PLAYWRIGHT_MODULE := github.com/mxschmitt/playwright-go
|
||||||
|
PLAYWRIGHT_CMD := $(PLAYWRIGHT_MODULE)/cmd/playwright
|
||||||
|
|
||||||
export PROJECT_NAME
|
.DEFAULT_GOAL := help
|
||||||
export FROM_MAKEFILE
|
|
||||||
|
|
||||||
export CGO_ENABLED
|
## help: Display this help message
|
||||||
|
|
||||||
export SOURCE_FILES
|
|
||||||
export TEST_OPTIONS
|
|
||||||
export TEST_TIMEOUT
|
|
||||||
export BUILDS_PATH
|
|
||||||
|
|
||||||
export CONTAINERFILE_NAME
|
|
||||||
export CONTAINER_ALPINE_VERSION
|
|
||||||
export CONTAINER_SOURCE_URL
|
|
||||||
export CONTAINER_MAINTAINER
|
|
||||||
export CONTAINER_BIN_NAME
|
|
||||||
|
|
||||||
export BUILDX_PLATFORMS
|
|
||||||
|
|
||||||
.PHONY: all
|
|
||||||
all: help
|
|
||||||
|
|
||||||
# this is godly
|
|
||||||
# https://news.ycombinator.com/item?id=11939200
|
|
||||||
.PHONY: help
|
.PHONY: help
|
||||||
help: ### this screen. Keep it first target to be default
|
help:
|
||||||
ifeq ($(UNAME), Linux)
|
@echo "Available targets:"
|
||||||
@grep -P '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
|
@grep -E '^## ' $(MAKEFILE_LIST) | sed 's/## / /' | sort
|
||||||
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
|
||||||
else
|
|
||||||
@# this is not tested, but prepared in advance for you, Mac drivers
|
|
||||||
@awk -F ':.*###' '$$0 ~ FS {printf "%15s%s\n", $$1 ":", $$2}' \
|
|
||||||
$(MAKEFILE_LIST) | grep -v '@awk' | sort
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
## clean: Clean test cache, build files
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean: ### clean test cache, build files
|
clean:
|
||||||
$(info: Make: Clean)
|
@rm -rf $(DIST_PATH)
|
||||||
@rm -rf ${BUILDS_PATH}
|
|
||||||
@rm -rf webapp/dist
|
@rm -rf webapp/dist
|
||||||
@rm -rf webapp/node_modules
|
@rm -rf webapp/node_modules
|
||||||
@rm -f webapp/bun.lockb
|
@rm -f webapp/bun.lockb
|
||||||
@go clean ${CLEAN_OPTIONS}
|
@go clean -modcache -testcache
|
||||||
@find devdata -mindepth 1 ! -name config.yaml -delete 2>/dev/null || true
|
|
||||||
@-docker buildx rm ${PROJECT_NAME}_builder
|
|
||||||
|
|
||||||
|
## clean-devdata: Clear devdata database and files (keeps config.yaml)
|
||||||
.PHONY: clean-devdata
|
.PHONY: clean-devdata
|
||||||
clean-devdata: ### Clear devdata database and files (keeps config.yaml)
|
clean-devdata:
|
||||||
$(info: Make: Cleaning devdata)
|
|
||||||
@rm -rf devdata/data
|
@rm -rf devdata/data
|
||||||
@rm -f devdata/hako.db devdata/hako.db-shm devdata/hako.db-wal
|
@rm -f devdata/hako.db devdata/hako.db-shm devdata/hako.db-wal
|
||||||
|
|
||||||
|
## build: Build project using goreleaser (snapshot)
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: build-webapp ### builds the project for the setup os/arch combinations
|
build: build-webapp
|
||||||
$(info: Make: Build)
|
goreleaser build --snapshot --clean
|
||||||
@goreleaser --clean --snapshot
|
|
||||||
|
|
||||||
|
## build-webapp: Build the webapp
|
||||||
.PHONY: build-webapp
|
.PHONY: build-webapp
|
||||||
build-webapp: ### Build the webapp
|
build-webapp:
|
||||||
$(info: Make: Building webapp)
|
|
||||||
@which bun > /dev/null || (echo "Error: Bun is not installed. Install it from https://bun.sh" && exit 1)
|
@which bun > /dev/null || (echo "Error: Bun is not installed. Install it from https://bun.sh" && exit 1)
|
||||||
@cd webapp && bun install && bun --bun node_modules/.bin/vite build
|
@cd webapp && bun install && bun --bun node_modules/.bin/vite build
|
||||||
|
|
||||||
|
## build-docker: Build Docker image locally via goreleaser
|
||||||
|
.PHONY: build-docker
|
||||||
|
build-docker: build-webapp
|
||||||
|
goreleaser release --snapshot --clean
|
||||||
|
|
||||||
|
## run: Build frontend and run the server
|
||||||
|
.PHONY: run
|
||||||
|
run: build-webapp run-server
|
||||||
|
|
||||||
|
## run-server: Run the API server only (without building webapp)
|
||||||
.PHONY: run-server
|
.PHONY: run-server
|
||||||
run-server: ### Runs the API server only (without building webapp)
|
run-server:
|
||||||
$(info: Make: Running server)
|
CGO_ENABLED=$(CGO_ENABLED) go run ./cmd/$(PROJECT_NAME)/*.go server --config devdata/config.yaml
|
||||||
CGO_ENABLED=${CGO_ENABLED} go run ./cmd/${PROJECT_NAME}/*.go server --config devdata/config.yaml
|
|
||||||
|
|
||||||
.PHONY: run-quick
|
|
||||||
run-quick: build-webapp run-server ### Builds the webapp and runs the server
|
|
||||||
|
|
||||||
|
## run-webapp: Run the webapp in dev mode with hot-reload
|
||||||
.PHONY: run-webapp
|
.PHONY: run-webapp
|
||||||
run-webapp: ### Runs the webapp in dev mode with hot-reload
|
run-webapp:
|
||||||
$(info: Make: Running webapp dev server)
|
|
||||||
@which bun > /dev/null || (echo "Error: Bun is not installed. Install it from https://bun.sh" && exit 1)
|
@which bun > /dev/null || (echo "Error: Bun is not installed. Install it from https://bun.sh" && exit 1)
|
||||||
@cd webapp && bun --bun node_modules/.bin/vite --mode development
|
@cd webapp && bun --bun node_modules/.bin/vite --mode development
|
||||||
|
|
||||||
.PHONY: run
|
## format: Format code and tidy modules
|
||||||
run: ### Executes the project build locally
|
|
||||||
@make build
|
|
||||||
${BUILDS_PATH}/${PROJECT_NAME}
|
|
||||||
|
|
||||||
.PHONY: build-docker
|
|
||||||
build-docker: build-webapp ### Build Docker image locally using goreleaser snapshot
|
|
||||||
$(info: Make: Building Docker image)
|
|
||||||
@which goreleaser > /dev/null || (echo "Error: goreleaser is not installed. Install it from https://goreleaser.com" && exit 1)
|
|
||||||
@which docker > /dev/null || (echo "Error: docker is not installed" && exit 1)
|
|
||||||
@goreleaser --clean --snapshot --skip=publish
|
|
||||||
|
|
||||||
.PHONY: format
|
.PHONY: format
|
||||||
format: ### Executes the formatting pipeline on the project
|
format:
|
||||||
$(info: Make: Format)
|
go fmt ./...
|
||||||
@go fmt ./...
|
go mod tidy
|
||||||
@go mod tidy
|
|
||||||
|
|
||||||
|
## ci-lint: Run golangci-lint (installs if missing)
|
||||||
.PHONY: ci-lint
|
.PHONY: ci-lint
|
||||||
ci-lint: ### Check the project for errors
|
ci-lint:
|
||||||
$(info: Make: Lint)
|
@which golangci-lint > /dev/null 2>&1 || go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)
|
||||||
@go install github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLANGCI_LINT_VERSION}
|
golangci-lint run ./...
|
||||||
@golangci-lint run ./...
|
|
||||||
|
|
||||||
|
## lint: Run all linters
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint: lint-server lint-webapp ### Check the project for errors
|
lint: lint-server lint-webapp
|
||||||
$(info: Make: Lint)
|
|
||||||
|
|
||||||
|
## lint-server: Check the server for linting errors
|
||||||
.PHONY: lint-server
|
.PHONY: lint-server
|
||||||
lint-server: ### Check the server for linting errors
|
lint-server:
|
||||||
$(info: Make: Lint server)
|
|
||||||
@golangci-lint run ./...
|
@golangci-lint run ./...
|
||||||
|
|
||||||
|
## lint-webapp: Check the webapp for linting errors
|
||||||
.PHONY: lint-webapp
|
.PHONY: lint-webapp
|
||||||
lint-webapp: ### Check the webapp for linting errors
|
lint-webapp:
|
||||||
$(info: Make: Lint webapp)
|
|
||||||
@which bun > /dev/null || (echo "Error: Bun is not installed. Install it from https://bun.sh" && exit 1)
|
@which bun > /dev/null || (echo "Error: Bun is not installed. Install it from https://bun.sh" && exit 1)
|
||||||
@cd webapp && bun --bun node_modules/.bin/eslint .
|
@cd webapp && bun --bun node_modules/.bin/eslint .
|
||||||
|
|
||||||
|
## test: Run tests with coverage
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: ### Runs the test suite
|
test:
|
||||||
$(info: Make: Test)
|
CGO_ENABLED=1 go test $(TEST_OPTIONS) -timeout=$(TEST_TIMEOUT) ./...
|
||||||
CGO_ENABLED=1 go test ${TEST_OPTIONS} -timeout=${TEST_TIMEOUT} ${SOURCE_FILES}
|
|
||||||
@echo "Generating HTML coverage report..."
|
|
||||||
@go tool cover -html=coverage.out -o coverage.html
|
|
||||||
@echo "✅ Coverage report generated: coverage.html"
|
|
||||||
|
|
||||||
|
## e2e: Run end-to-end integration tests
|
||||||
.PHONY: e2e
|
.PHONY: e2e
|
||||||
e2e: ### Run end-to-end integration tests
|
e2e:
|
||||||
$(info: Make: E2E Tests)
|
|
||||||
@./scripts/e2e.sh
|
@./scripts/e2e.sh
|
||||||
|
|
||||||
|
## e2e-install: Install Playwright browsers
|
||||||
.PHONY: e2e-install
|
.PHONY: e2e-install
|
||||||
e2e-install: ### Install Playwright browsers
|
e2e-install:
|
||||||
$(info: Make: Installing E2E dependencies)
|
@cd e2e && go run $(PLAYWRIGHT_CMD)@$$(go list -m -f '{{.Version}}' $(PLAYWRIGHT_MODULE)) install --with-deps chromium
|
||||||
@go run github.com/playwright-community/playwright-go/cmd/playwright@latest install --with-deps chromium
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,10 @@
|
||||||
services:
|
services:
|
||||||
hako:
|
hako:
|
||||||
# Note: Before running docker-compose, ensure the Linux binary is prepared:
|
# Note: Build the Docker image via goreleaser:
|
||||||
# Run: make prepare-docker-compose
|
# Run: make build-docker
|
||||||
# Or: make build-docker (which builds via goreleaser)
|
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Containerfile
|
dockerfile: Containerfile
|
||||||
platforms:
|
|
||||||
- linux/amd64
|
|
||||||
args:
|
|
||||||
TARGETPLATFORM: dist/hako_linux_amd64_v1
|
|
||||||
platform: linux/amd64
|
|
||||||
container_name: hako
|
container_name: hako
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
FROM alpine:3.20
|
FROM alpine:3.23
|
||||||
|
|
||||||
RUN apk add --no-cache poppler-utils ca-certificates tzdata && \
|
RUN apk add --no-cache poppler-utils ca-certificates tzdata && \
|
||||||
addgroup -g 1000 hako && \
|
addgroup -g 1000 hako && \
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,13 @@ func StartHakoContainer(ctx context.Context, t *testing.T) (testcontainers.Conta
|
||||||
os.Remove(binaryPath)
|
os.Remove(binaryPath)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create container request
|
// Ensure shared network exists so Hako can reach the test web server by alias.
|
||||||
|
nw, err := getSharedNetwork(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create container request attached to the shared network.
|
||||||
req := testcontainers.ContainerRequest{
|
req := testcontainers.ContainerRequest{
|
||||||
FromDockerfile: testcontainers.FromDockerfile{
|
FromDockerfile: testcontainers.FromDockerfile{
|
||||||
Context: filepath.Join(projectRoot, "e2e"),
|
Context: filepath.Join(projectRoot, "e2e"),
|
||||||
|
|
@ -63,6 +69,7 @@ func StartHakoContainer(ctx context.Context, t *testing.T) (testcontainers.Conta
|
||||||
ExposedPorts: []string{"8080/tcp"},
|
ExposedPorts: []string{"8080/tcp"},
|
||||||
WaitingFor: wait.ForLog("Starting HTTP server").
|
WaitingFor: wait.ForLog("Starting HTTP server").
|
||||||
WithStartupTimeout(30 * time.Second),
|
WithStartupTimeout(30 * time.Second),
|
||||||
|
Networks: []string{nw.Name},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start container
|
// Start container
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/playwright-community/playwright-go"
|
"github.com/mxschmitt/playwright-go"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -178,10 +178,12 @@ func (h *TestHelper) GetURL() string {
|
||||||
return h.page.URL()
|
return h.page.URL()
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsVisible checks if an element matching the selector is visible.
|
// IsVisible checks if any element matching the selector is visible.
|
||||||
|
// Uses .First() to avoid Playwright strict-mode errors when the selector
|
||||||
|
// resolves to multiple elements.
|
||||||
func (h *TestHelper) IsVisible(selector string) bool {
|
func (h *TestHelper) IsVisible(selector string) bool {
|
||||||
h.t.Helper()
|
h.t.Helper()
|
||||||
visible, err := h.page.Locator(selector).IsVisible()
|
visible, err := h.page.Locator(selector).First().IsVisible()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.t.Logf("Error checking visibility of %s: %v", selector, err)
|
h.t.Logf("Error checking visibility of %s: %v", selector, err)
|
||||||
return false
|
return false
|
||||||
|
|
@ -305,9 +307,18 @@ func (h *TestHelper) Logout() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateLink creates a new link via the Quick Add form.
|
// CreateLink creates a new link via the Quick Add form.
|
||||||
|
// Navigates to /home first to ensure the form is available even when called
|
||||||
|
// repeatedly (after the first call the user is redirected to /links).
|
||||||
func (h *TestHelper) CreateLink(url string) error {
|
func (h *TestHelper) CreateLink(url string) error {
|
||||||
h.t.Helper()
|
h.t.Helper()
|
||||||
|
|
||||||
|
// Ensure we're on the home page where the Quick Add form lives.
|
||||||
|
if !strings.HasSuffix(h.GetURL(), "/home") {
|
||||||
|
if err := h.Navigate("/home"); err != nil {
|
||||||
|
return fmt.Errorf("failed to navigate to home: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for URL input on home page
|
// Wait for URL input on home page
|
||||||
if err := h.WaitForSelector("input[name=\"url\"]", 5*time.Second); err != nil {
|
if err := h.WaitForSelector("input[name=\"url\"]", 5*time.Second); err != nil {
|
||||||
return fmt.Errorf("URL input not found: %w", err)
|
return fmt.Errorf("URL input not found: %w", err)
|
||||||
|
|
|
||||||
34
e2e/e2eutil/network.go
Normal file
34
e2e/e2eutil/network.go
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
package e2eutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/testcontainers/testcontainers-go"
|
||||||
|
"github.com/testcontainers/testcontainers-go/network"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Shared network used by the test web server and Hako container so that
|
||||||
|
// Hako can fetch URLs from the test web server via Docker DNS.
|
||||||
|
var (
|
||||||
|
sharedNetwork *testcontainers.DockerNetwork
|
||||||
|
sharedNetworkErr error
|
||||||
|
sharedNetworkOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
// Network alias used by the test web server inside the shared network.
|
||||||
|
const testServerAlias = "hako-testserver"
|
||||||
|
|
||||||
|
// getSharedNetwork lazily creates a shared Docker network for the test process.
|
||||||
|
// Both StartTestWebServer and StartHakoContainer attach to it so containers
|
||||||
|
// can communicate by alias.
|
||||||
|
func getSharedNetwork(ctx context.Context) (*testcontainers.DockerNetwork, error) {
|
||||||
|
sharedNetworkOnce.Do(func() {
|
||||||
|
sharedNetwork, sharedNetworkErr = network.New(ctx)
|
||||||
|
})
|
||||||
|
if sharedNetworkErr != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create shared network: %w", sharedNetworkErr)
|
||||||
|
}
|
||||||
|
return sharedNetwork, nil
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@ package e2eutil
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/playwright-community/playwright-go"
|
"github.com/mxschmitt/playwright-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewPlaywright initializes Playwright and returns a browser instance.
|
// NewPlaywright initializes Playwright and returns a browser instance.
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/go-connections/nat"
|
|
||||||
"github.com/testcontainers/testcontainers-go"
|
"github.com/testcontainers/testcontainers-go"
|
||||||
"github.com/testcontainers/testcontainers-go/wait"
|
"github.com/testcontainers/testcontainers-go/wait"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StartTestWebServer starts an nginx container with test content for E2E testing.
|
// StartTestWebServer starts an nginx container with test content for E2E testing.
|
||||||
// It builds the test web server image and returns the container instance and base URL.
|
// The container is attached to the shared network with the testServerAlias hostname,
|
||||||
|
// and the returned URL uses that alias so the Hako container can fetch from it.
|
||||||
func StartTestWebServer(ctx context.Context, t *testing.T) (testcontainers.Container, string, error) {
|
func StartTestWebServer(ctx context.Context, t *testing.T) (testcontainers.Container, string, error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
|
@ -23,7 +23,13 @@ func StartTestWebServer(ctx context.Context, t *testing.T) (testcontainers.Conta
|
||||||
return nil, "", fmt.Errorf("failed to get project root: %w", err)
|
return nil, "", fmt.Errorf("failed to get project root: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create container request
|
// Ensure shared network exists so Hako can reach this server by alias.
|
||||||
|
nw, err := getSharedNetwork(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create container request attached to the shared network.
|
||||||
req := testcontainers.ContainerRequest{
|
req := testcontainers.ContainerRequest{
|
||||||
FromDockerfile: testcontainers.FromDockerfile{
|
FromDockerfile: testcontainers.FromDockerfile{
|
||||||
Context: filepath.Join(projectRoot, "e2e", "testserver"),
|
Context: filepath.Join(projectRoot, "e2e", "testserver"),
|
||||||
|
|
@ -32,6 +38,10 @@ func StartTestWebServer(ctx context.Context, t *testing.T) (testcontainers.Conta
|
||||||
},
|
},
|
||||||
ExposedPorts: []string{"80/tcp"},
|
ExposedPorts: []string{"80/tcp"},
|
||||||
WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second),
|
WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second),
|
||||||
|
Networks: []string{nw.Name},
|
||||||
|
NetworkAliases: map[string][]string{
|
||||||
|
nw.Name: {testServerAlias},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start container
|
// Start container
|
||||||
|
|
@ -51,21 +61,10 @@ func StartTestWebServer(ctx context.Context, t *testing.T) (testcontainers.Conta
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Get the mapped port
|
// Use the network alias as the base URL so Hako can reach this server
|
||||||
mappedPort, err := container.MappedPort(ctx, nat.Port("80/tcp"))
|
// from inside its container via Docker DNS.
|
||||||
if err != nil {
|
baseURL := fmt.Sprintf("http://%s", testServerAlias)
|
||||||
return nil, "", fmt.Errorf("failed to get mapped port: %w", err)
|
t.Logf("Test web server started at %s (network alias)", baseURL)
|
||||||
}
|
|
||||||
|
|
||||||
// Get the host
|
|
||||||
host, err := container.Host(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("failed to get container host: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct base URL
|
|
||||||
baseURL := fmt.Sprintf("http://%s:%s", host, mappedPort.Port())
|
|
||||||
t.Logf("Test web server started at %s", baseURL)
|
|
||||||
|
|
||||||
return container, baseURL, nil
|
return container, baseURL, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@ replace github.com/fmartingr/hako => ../
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/docker/go-connections v0.6.0
|
github.com/docker/go-connections v0.6.0
|
||||||
github.com/playwright-community/playwright-go v0.5200.1
|
github.com/google/uuid v1.6.0
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.41
|
||||||
|
github.com/mxschmitt/playwright-go v0.6201.1
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/testcontainers/testcontainers-go v0.40.0
|
github.com/testcontainers/testcontainers-go v0.40.0
|
||||||
)
|
)
|
||||||
|
|
@ -23,18 +25,16 @@ require (
|
||||||
github.com/containerd/platforms v0.2.1 // indirect
|
github.com/containerd/platforms v0.2.1 // indirect
|
||||||
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/deckarep/golang-set/v2 v2.7.0 // indirect
|
github.com/deckarep/golang-set/v2 v2.8.0 // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
github.com/docker/docker v28.5.1+incompatible // indirect
|
github.com/docker/docker v28.5.1+incompatible // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/ebitengine/purego v0.8.4 // indirect
|
github.com/ebitengine/purego v0.8.4 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
|
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/go-stack/stack v1.8.1 // indirect
|
github.com/go-stack/stack v1.8.1 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||||
github.com/magiconair/properties v1.8.10 // indirect
|
github.com/magiconair/properties v1.8.10 // indirect
|
||||||
|
|
|
||||||
52
e2e/go.sum
52
e2e/go.sum
|
|
@ -25,8 +25,8 @@ github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/deckarep/golang-set/v2 v2.7.0 h1:gIloKvD7yH2oip4VLhsv3JyLLFnC0Y2mlusgcvJYW5k=
|
github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ=
|
||||||
github.com/deckarep/golang-set/v2 v2.7.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM=
|
github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM=
|
||||||
|
|
@ -39,8 +39,6 @@ github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0o
|
||||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY=
|
|
||||||
github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
|
@ -51,7 +49,6 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU
|
||||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
|
@ -68,8 +65,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||||
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||||
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
github.com/mattn/go-sqlite3 v1.14.41 h1:8p7Pwz5NHkEbWSqc/ygU4CBGubhFFkpgP9KwcdkAHNA=
|
||||||
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
github.com/mattn/go-sqlite3 v1.14.41/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ=
|
||||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
|
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
|
||||||
|
|
@ -88,14 +85,14 @@ github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
|
github.com/mxschmitt/playwright-go v0.6201.1 h1:KBBDopE+IIdjAp2FIk6zhLcKCCSSx/T6rGjKZmfo/Bs=
|
||||||
|
github.com/mxschmitt/playwright-go v0.6201.1/go.mod h1:vLBP2yVO1gokUlb9ENA+YE3VQaVqf2A9BGxcb7aPjMI=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/playwright-community/playwright-go v0.5200.1 h1:Sm2oOuhqt0M5Y4kUi/Qh9w4cyyi3ZIWTBeGKImc2UVo=
|
|
||||||
github.com/playwright-community/playwright-go v0.5200.1/go.mod h1:UnnyQZaqUOO5ywAZu60+N4EiWReUqX1MQBBA3Oofvf8=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||||
|
|
@ -118,7 +115,6 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA
|
||||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
|
|
@ -139,60 +135,24 @@ go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6
|
||||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||||
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
||||||
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
|
||||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
|
||||||
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
||||||
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.1.0/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-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
|
||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
|
||||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
||||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
||||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
|
||||||
|
|
|
||||||
|
|
@ -265,7 +265,7 @@ func TestRules_RuleApplication(t *testing.T) {
|
||||||
helper.Screenshot("link-created-rule-test")
|
helper.Screenshot("link-created-rule-test")
|
||||||
|
|
||||||
// Navigate to link details to see which archiver was used
|
// Navigate to link details to see which archiver was used
|
||||||
err = helper.Click("a[href*='/links/']")
|
err = helper.Click(".link-item")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
helper.Screenshot("link-details-archiver-used")
|
helper.Screenshot("link-details-archiver-used")
|
||||||
|
|
|
||||||
|
|
@ -53,13 +53,14 @@ func TestArchive_AutomaticCreation(t *testing.T) {
|
||||||
helper.Screenshot("link-created")
|
helper.Screenshot("link-created")
|
||||||
|
|
||||||
// Navigate to link details to see archive status
|
// Navigate to link details to see archive status
|
||||||
err = helper.Click("a[href*='/links/']")
|
err = helper.Click(".link-item")
|
||||||
require.NoError(t, err, "Failed to navigate to link details")
|
require.NoError(t, err, "Failed to navigate to link details")
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
helper.Screenshot("link-details-archive")
|
helper.Screenshot("link-details-archive")
|
||||||
|
|
||||||
// Verify archive section exists
|
// Wait for archive processing to surface in the UI
|
||||||
helper.AssertVisible(".archive-status, .archive-history, [class*='archive']", "Archive information should be visible")
|
err = helper.WaitForSelector(".archive-status, [class*='archive']", 30*time.Second)
|
||||||
|
require.NoError(t, err, "Archive information should appear")
|
||||||
|
helper.AssertVisible(".archive-status, [class*='archive']", "Archive information should be visible")
|
||||||
|
|
||||||
t.Log("Archive automatic creation test completed successfully")
|
t.Log("Archive automatic creation test completed successfully")
|
||||||
}
|
}
|
||||||
|
|
@ -105,15 +106,15 @@ func TestArchive_ViewHistory(t *testing.T) {
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
// Navigate to link details
|
// Navigate to link details
|
||||||
err = helper.Click("a[href*='/links/']")
|
err = helper.Click(".link-item")
|
||||||
require.NoError(t, err, "Failed to navigate to link details")
|
require.NoError(t, err, "Failed to navigate to link details")
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
helper.Screenshot("archive-history")
|
helper.Screenshot("archive-history")
|
||||||
|
|
||||||
// Verify archive history is visible
|
// Wait for archive to appear in the UI
|
||||||
helper.AssertVisible(".archive-history, .archive-list, [class*='archive']", "Archive history should be visible")
|
err = helper.WaitForSelector(".archive-status, [class*='archive']", 30*time.Second)
|
||||||
|
require.NoError(t, err, "Archive history should appear")
|
||||||
|
helper.AssertVisible(".archive-status, [class*='archive']", "Archive history should be visible")
|
||||||
|
|
||||||
// Wait for archive to process (with timeout)
|
|
||||||
t.Log("Waiting for archive to complete...")
|
t.Log("Waiting for archive to complete...")
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
helper.Screenshot("archive-after-wait")
|
helper.Screenshot("archive-after-wait")
|
||||||
|
|
@ -162,7 +163,7 @@ func TestArchive_StatusDisplay(t *testing.T) {
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
// Navigate to link details
|
// Navigate to link details
|
||||||
err = helper.Click("a[href*='/links/']")
|
err = helper.Click(".link-item")
|
||||||
require.NoError(t, err, "Failed to navigate to link details")
|
require.NoError(t, err, "Failed to navigate to link details")
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
helper.Screenshot("archive-status")
|
helper.Screenshot("archive-status")
|
||||||
|
|
@ -222,7 +223,7 @@ func TestArchive_Rearchive(t *testing.T) {
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
// Navigate to link details
|
// Navigate to link details
|
||||||
err = helper.Click("a[href*='/links/']")
|
err = helper.Click(".link-item")
|
||||||
require.NoError(t, err, "Failed to navigate to link details")
|
require.NoError(t, err, "Failed to navigate to link details")
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
helper.Screenshot("before-rearchive")
|
helper.Screenshot("before-rearchive")
|
||||||
|
|
@ -295,7 +296,7 @@ func TestArchive_ViewFiles(t *testing.T) {
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
// Navigate to link details
|
// Navigate to link details
|
||||||
err = helper.Click("a[href*='/links/']")
|
err = helper.Click(".link-item")
|
||||||
require.NoError(t, err, "Failed to navigate to link details")
|
require.NoError(t, err, "Failed to navigate to link details")
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
|
@ -356,7 +357,7 @@ func TestArchive_PreviewHTML(t *testing.T) {
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
// Navigate to link details
|
// Navigate to link details
|
||||||
err = helper.Click("a[href*='/links/']")
|
err = helper.Click(".link-item")
|
||||||
require.NoError(t, err, "Failed to navigate to link details")
|
require.NoError(t, err, "Failed to navigate to link details")
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ func TestError_ArchivalFailure(t *testing.T) {
|
||||||
helper.Screenshot("archival-failure-link-created")
|
helper.Screenshot("archival-failure-link-created")
|
||||||
|
|
||||||
// Navigate to link details
|
// Navigate to link details
|
||||||
err = helper.Click("a[href*='/links/']")
|
err = helper.Click(".link-item")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
helper.Screenshot("archival-failure-details")
|
helper.Screenshot("archival-failure-details")
|
||||||
|
|
|
||||||
|
|
@ -4,19 +4,23 @@ set -e
|
||||||
echo "🧪 Running Hako E2E Tests"
|
echo "🧪 Running Hako E2E Tests"
|
||||||
|
|
||||||
# Environment setup
|
# Environment setup
|
||||||
export TESTCONTAINERS_RYUK_DISABLED=false
|
export TESTCONTAINERS_RYUK_DISABLED="${TESTCONTAINERS_RYUK_DISABLED:-true}"
|
||||||
export DOCKER_HOST="${DOCKER_HOST:-unix:///var/run/docker.sock}"
|
export DOCKER_HOST="${DOCKER_HOST:-unix:///var/run/docker.sock}"
|
||||||
|
|
||||||
# Check Docker
|
# Check Docker
|
||||||
if ! docker info > /dev/null 2>&1; then
|
if ! docker info > /dev/null 2>&1; then
|
||||||
echo "❌ Error: Docker is not running"
|
echo "❌ Error: Docker is not available (check DOCKER_HOST and socket mount)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install Playwright if needed
|
# Install Playwright if needed, pinned to the module the tests link against
|
||||||
if ! go run github.com/playwright-community/playwright-go/cmd/playwright@latest --help > /dev/null 2>&1; then
|
PLAYWRIGHT_MODULE="github.com/mxschmitt/playwright-go"
|
||||||
|
PLAYWRIGHT_VERSION="$(cd e2e && go list -m -f '{{.Version}}' "$PLAYWRIGHT_MODULE")"
|
||||||
|
PLAYWRIGHT_CMD="$PLAYWRIGHT_MODULE/cmd/playwright@$PLAYWRIGHT_VERSION"
|
||||||
|
|
||||||
|
if ! go run "$PLAYWRIGHT_CMD" --help > /dev/null 2>&1; then
|
||||||
echo "📦 Installing Playwright browsers..."
|
echo "📦 Installing Playwright browsers..."
|
||||||
go run github.com/playwright-community/playwright-go/cmd/playwright@latest install --with-deps chromium
|
(cd e2e && go run "$PLAYWRIGHT_CMD" install chromium)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Build webapp (required for embed)
|
# Build webapp (required for embed)
|
||||||
|
|
|
||||||
0
webapp/dist/.gitkeep
vendored
Normal file
0
webapp/dist/.gitkeep
vendored
Normal file
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed dist
|
//go:embed all:dist
|
||||||
var embeddedWebappFS embed.FS
|
var embeddedWebappFS embed.FS
|
||||||
|
|
||||||
// GetFilesystem returns a HTTP filesystem with the embedded webapp files
|
// GetFilesystem returns a HTTP filesystem with the embedded webapp files
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue