diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 6fae5e95d..f82f71a78 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: go: ['1.18','1.19'] - + steps: - name: install make run: sudo apt-get install make diff --git a/.github/workflows/push_image.yml b/.github/workflows/push_image.yml index 10d83c9cc..1b0cd1daf 100644 --- a/.github/workflows/push_image.yml +++ b/.github/workflows/push_image.yml @@ -5,10 +5,9 @@ on: env: REGISTRY_USER: netobserv+github_ci - REGISTRY_PASSWORD: ${{ secrets.QUAY_SECRET }} REGISTRY: quay.io/netobserv - REG_IMAGE: network-observability-console-plugin - REG_TAG: main + IMAGE: network-observability-console-plugin + VERSION: main jobs: push-image: @@ -26,23 +25,14 @@ jobs: go-version: ${{ matrix.go }} - name: checkout uses: actions/checkout@v3 - - name: build images - run: BASE_IMAGE="${{ env.REGISTRY }}/${{ env.REG_IMAGE }}" TAG="${{ env.REG_TAG }}" make build-ci-images - - name: podman login to quay.io - uses: redhat-actions/podman-login@v1 + - name: docker login to quay.io + uses: docker/login-action@v2 with: username: ${{ env.REGISTRY_USER }} - password: ${{ env.REGISTRY_PASSWORD }} + password: ${{ secrets.QUAY_SECRET }} registry: quay.io - - name: get short sha - run: echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - - name: push to quay.io - id: push-to-quay - uses: redhat-actions/push-to-registry@v2 - with: - image: ${{ env.REG_IMAGE }} - tags: ${{ env.REG_TAG }} ${{ env.short_sha }} - registry: ${{ env.REGISTRY }} + - name: build and push manifest with images + run: VERSION=${{ env.VERSION }} make ci - name: print image url run: echo "Image pushed to ${{ steps.push-to-quay.outputs.registry-paths }}" diff --git a/.github/workflows/push_image_pr.yml b/.github/workflows/push_image_pr.yml index c1ae0e558..5374a5bd7 100644 --- a/.github/workflows/push_image_pr.yml +++ b/.github/workflows/push_image_pr.yml @@ -6,7 +6,8 @@ on: env: REGISTRY_USER: netobserv+github_ci REGISTRY: quay.io/netobserv - REG_IMAGE: network-observability-console-plugin + IMAGE: network-observability-console-plugin + VERSION: temp jobs: push-pr-image: @@ -27,23 +28,18 @@ jobs: uses: actions/checkout@v3 with: ref: "refs/pull/${{ github.event.number }}/merge" - - name: build images - run: BASE_IMAGE="${{ env.REGISTRY }}/${{ env.REG_IMAGE }}" TAG=temp make build-ci-images - - name: podman login to quay.io - uses: redhat-actions/podman-login@v1 + - name: docker login to quay.io + uses: docker/login-action@v2 with: username: ${{ env.REGISTRY_USER }} password: ${{ secrets.QUAY_SECRET }} registry: quay.io - name: get short sha run: echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - - name: push to quay.io - id: push-to-quay - uses: redhat-actions/push-to-registry@v2 - with: - image: ${{ env.REG_IMAGE }} - tags: ${{ env.short_sha }} - registry: ${{ env.REGISTRY }} + - name: build and push images + run: IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE }}:$(( env.short_sha )) make images + - name: build and push manifest + run: VERSION=${{ env.VERSION }} make ci-manifest - uses: actions/github-script@v6 with: github-token: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5ca73d22d..0131e6f42 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,20 +36,13 @@ jobs: uses: actions/setup-go@v3 with: go-version: ${{ matrix.go }} - - name: build images - run: IMAGE="quay.io/netobserv/${{ env.IMAGE }}:${{ env.tag }}" make image - - name: podman login to quay.io - uses: redhat-actions/podman-login@v1 + - name: docker login to quay.io + uses: docker/login-action@v2 with: username: ${{ env.REGISTRY_USER }} password: ${{ env.REGISTRY_PASSWORD }} registry: quay.io - - name: push to quay.io - id: push-to-quay - uses: redhat-actions/push-to-registry@v2 - with: - image: ${{ env.IMAGE }} - tags: ${{ env.tag }} - registry: ${{ env.REGISTRY }} + - name: build and push images + run: OCI_BIN=docker IMAGE="quay.io/netobserv/${{ env.IMAGE }}:${{ env.tag }}" make images - name: print image url run: echo "Image pushed to ${{ steps.push-to-quay.outputs.registry-paths }}" diff --git a/.mk/shortcuts.mk b/.mk/shortcuts.mk new file mode 100644 index 000000000..8f0425a76 --- /dev/null +++ b/.mk/shortcuts.mk @@ -0,0 +1,56 @@ +##@ shortcuts helpers +.PHONY: fmt +fmt: fmt-backend fmt-frontend ## Fmt all + +.PHONY: lint +lint: lint-backend lint-frontend ## Lint all + +.PHONY: test +test: test-backend test-frontend ## Test all + +.PHONY: i18n +i18n: ## Run frontend i18n + @echo "### generating frontend locales" + cd web && npm run i18n + +.PHONY: build-frontend +build-frontend: install-frontend fmt-frontend just-build-frontend ## Run npm install, format and build frontend + +.PHONY: build +build: build-backend build-frontend ## Build all + +.PHONY: build-standalone +build-standalone: build-backend build-frontend-standalone ## Build all as standalone + +.PHONY: frontend +frontend: build-frontend lint-frontend test-frontend ## Build lint and test frontend + +.PHONY: backend +backend: build-backend lint-backend test-backend ## Build lint and test backend + +.PHONY: build-image +build-image: image-build ## Build MULTIARCH_TARGETS images + +.PHONY: push-image +push-image: image-push ## Push MULTIARCH_TARGETS images + +.PHONY: build-manifest +build-manifest: manifest-build ## Build MULTIARCH_TARGETS manifest + +.PHONY: push-manifest +push-manifest: manifest-push ## Push MULTIARCH_TARGETS manifest + +.PHONY: images +images: image-build image-push manifest-build manifest-push ## Build and push MULTIARCH_TARGETS images and related manifest + +.PHONY: build-ci-manifest +build-ci-manifest: ci-manifest-build ## Build CI manifest + +.PHONY: push-ci-manifest +push-ci-manifest: ci-manifest-push ## Push CI manifest + +.PHONY: ci-manifest +ci-manifest: ci-manifest-build ci-manifest-push ## Build and push CI manifest + +.PHONY: ci +ci: images ci-manifest ## Build and push CI images and manifest \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index a3d90da28..246ad62c2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,27 @@ -FROM registry.access.redhat.com/ubi9/nodejs-16:1 as web-builder - +# We do not use --platform feature to auto fill this ARG because of incompatibility between podman and docker +ARG TARGETPLATFORM=linux/amd64 +ARG BUILDPLATFORM=linux/amd64 +FROM --platform=$BUILDPLATFORM docker.io/library/node:16-alpine as web-builder +USER node + +ARG TARGETPLATFORM +ARG TARGETARCH=amd64 WORKDIR /opt/app-root -COPY --chown=default Makefile Makefile -COPY --chown=default web/package.json web/package.json -COPY --chown=default web/package-lock.json web/package-lock.json -RUN NPM_INSTALL=ci make install-frontend +COPY --chown=node Makefile Makefile +COPY --chown=node web/package.json web/package.json +COPY --chown=node web/package-lock.json web/package-lock.json +RUN cd web && npm ci -COPY --chown=default web web +COPY --chown=node web web COPY mocks mocks -RUN make fmt-frontend just-build-frontend +RUN cd web && npm run format-all +RUN cd web && npm run build -FROM docker.io/library/golang:1.19 as go-builder +FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.19 as go-builder +ARG TARGETPLATFORM +ARG TARGETARCH=amd64 WORKDIR /opt/app-root COPY .git .git @@ -20,12 +29,13 @@ COPY go.mod go.mod COPY go.sum go.sum COPY vendor/ vendor/ COPY Makefile Makefile +COPY .mk/ .mk/ COPY cmd/ cmd/ COPY pkg/ pkg/ -RUN make build-backend +RUN CGO_ENABLED=0 GOARCH=$TARGETARCH make build-backend -FROM registry.access.redhat.com/ubi9/ubi-minimal:9.1 +FROM --platform=$TARGETPLATFORM registry.access.redhat.com/ubi9/ubi-minimal:9.1 COPY --from=web-builder /opt/app-root/web/dist ./web/dist COPY --from=go-builder /opt/app-root/plugin-backend ./ diff --git a/Makefile b/Makefile index 507ec9ae4..bb9ba6fa2 100644 --- a/Makefile +++ b/Makefile @@ -1,173 +1,230 @@ -IMG_USER ?= netobserv -TAG ?= dev -BUILD_VERSION := $(shell git describe --long HEAD) +# VERSION defines the project version for the bundle. +# Update this value when you upgrade the version of your project. +# To re-generate a bundle for another specific version without changing the standard setup, you can: +# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) +# - use environment variables to overwrite this value (e.g export VERSION=0.0.2) +VERSION ?= main BUILD_DATE := $(shell date +%Y-%m-%d\ %H:%M) -# You can add GO Build flags like -gcflags=all="-N -l" here to remove optimizations for debugging -BUILD_FLAGS ?= -ldflags "-X 'main.buildVersion=${BUILD_VERSION}' -X 'main.buildDate=${BUILD_DATE}'" +TAG_COMMIT := $(shell git rev-list --abbrev-commit --tags --max-count=1) +TAG := $(shell git describe --abbrev=0 --tags ${TAG_COMMIT} 2>/dev/null || true) BUILD_SHA := $(shell git rev-parse --short HEAD) -SHELL := /bin/bash +BUILD_VERSION := $(TAG:v%=%) +ifneq ($(COMMIT), $(TAG_COMMIT)) + BUILD_VERSION := $(BUILD_VERSION)-$(BUILD_SHA) +endif +ifneq ($(shell git status --porcelain),) + BUILD_VERSION := $(BUILD_VERSION)-dirty +endif + +# Go architecture and targets images to build +GOARCH ?= amd64 +MULTIARCH_TARGETS := amd64 arm64 ppc64le + +# Setting SHELL to bash allows bash commands to be executed by recipes. +SHELL := /usr/bin/env bash + +# In CI, to be replaced by `netobserv` +IMAGE_ORG ?= $(USER) -BASE_IMAGE ?= quay.io/${IMG_USER}/network-observability-console-plugin -IMAGE ?= ${BASE_IMAGE}:${TAG} +# IMAGE_TAG_BASE defines the namespace and part of the image name for remote images. +IMAGE_TAG_BASE ?= quay.io/${IMAGE_ORG}/network-observability-console-plugin + +# Image URL to use all building/pushing image targets +IMAGE ?= ${IMAGE_TAG_BASE}:${VERSION} +IMAGE_SHA = $(IMAGE_TAG_BASE):$(BUILD_SHA) + +# Image building tool (docker / podman) +OCI_BIN_PATH = $(shell which podman || which docker) +OCI_BIN ?= $(shell v='$(OCI_BIN_PATH)'; echo "$${v##*/}") GOLANGCI_LINT_VERSION = v1.50.1 NPM_INSTALL ?= install - CMDLINE_ARGS ?= --loglevel trace --loki-tenant-id netobserv --frontend-config config/sample-frontend-config.yaml --auth-check none +# You can add GO Build flags like -gcflags=all="-N -l" here to remove optimizations for debugging +BUILD_FLAGS ?= -ldflags "-X 'main.buildVersion=${BUILD_VERSION}' -X 'main.buildDate=${BUILD_DATE}'" -ifeq (,$(shell which podman 2>/dev/null)) -OCI_BIN ?= docker -else -OCI_BIN ?= podman -endif +.DEFAULT_GOAL := help + +# build a single arch target provided as argument +define build_target + echo 'building image for arch $(1)'; \ + DOCKER_BUILDKIT=1 $(OCI_BIN) buildx build --load --build-arg TARGETPLATFORM=linux/$(1) --build-arg TARGETARCH=$(1) --build-arg BUILDPLATFORM=linux/amd64 -t ${IMAGE}-$(1) -f Dockerfile .; +endef + +# push a single arch target image +define push_target + echo 'pushing image ${IMAGE}-$(1)'; \ + DOCKER_BUILDKIT=1 $(OCI_BIN) push ${IMAGE}-$(1); +endef + +##@ General + +# The help target prints out all targets with their descriptions organized +# beneath their categories. The categories are represented by '##@' and the +# target descriptions by '##'. The awk commands is responsible for reading the +# entire set of makefiles included in this invocation, looking for lines of the +# file as xyz: ## something, and then pretty-format the target and help. Then, +# if there's a line with ##@ something, that gets pretty-printed as a category. +# More info on the usage of ANSI control characters for terminal formatting: +# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info on the awk command: +# http://linuxcommand.org/lc3_adv_awk.php + +.PHONY: help +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) .PHONY: prereqs -prereqs: +prereqs: ## Test if prerequisites are met, and installing missing dependencies @echo "### Test if prerequisites are met, and installing missing dependencies" test -f $(go env GOPATH)/bin/golangci-lint || GOFLAGS="" go install github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLANGCI_LINT_VERSION} .PHONY: vendors -vendors: +vendors: ## Check go vendors @echo "### Checking vendors" go mod tidy && go mod vendor +##@ Develop + +.PHONY: start +start: build-backend install-frontend ## Run backend and frontend + @echo "### Starting backend on http://localhost:9002" + bash -c "trap 'fuser -k 9002/tcp' EXIT; \ + ./plugin-backend -port 9002 $(CMDLINE_ARGS) & cd web && npm run start" + +.PHONY: start-standalone +start-standalone: build-backend install-frontend ## Run backend and frontend as standalone + @echo "### Starting backend on http://localhost:9002" + bash -c "trap 'fuser -k 9002/tcp' EXIT; \ + ./plugin-backend -port 9002 $(CMDLINE_ARGS) & cd web && npm run start:standalone" + +.PHONY: start-standalone-mock +start-standalone-mock: build-backend install-frontend ## Run backend using mocks and frontend as standalone + @echo "### Starting backend on http://localhost:9002 using mock" + bash -c "trap 'fuser -k 9002/tcp' EXIT; \ + ./plugin-backend -port 9002 --loki-mock $(CMDLINE_ARGS) & cd web && npm run start:standalone" + +.PHONY: bridge +bridge: ## Bridge OCP console +ifeq (,${CONSOLE}) + @echo "CONSOLE must be set to your local path of the console repository clone. E.g. CONSOLE=/path/to/console make bridge" +else + @echo "### Setting bridge from ${CONSOLE} to http://localhost:9000/netflow-traffic" + cd ${CONSOLE} && source contrib/oc-environment.sh && ./bin/bridge -plugins netobserv-plugin=http://localhost:9001/ --plugin-proxy='{"services":[{"consoleAPIPath":"/api/proxy/plugin/netobserv-plugin/backend/","endpoint":"http://localhost:9001"}]}' + cd - +endif + +.PHONY: generate-doc +generate-doc: ## Generate documentation of the flows JSON format + cd web && npm run generate-doc + +##@ Develop frontend + .PHONY: install-frontend -install-frontend: +install-frontend: ## Run frontend npm install @echo "### Installing frontend dependencies" cd web && npm ${NPM_INSTALL} -.PHONY: fmt-backend -fmt-backend: - go fmt ./... - .PHONY: fmt-frontend -fmt-frontend: i18n +fmt-frontend: i18n ## Run frontend i18n and fmt cd web && npm run format-all -.PHONY: fmt -fmt: fmt-backend fmt-frontend - -.PHONY: lint-backend -lint-backend: prereqs - @echo "### Linting backend code" - golangci-lint run ./... - .PHONY: lint-frontend -lint-frontend: +lint-frontend: ## Lint frontend code @echo "### Linting frontend code" cd web && npm run lint + +.PHONY: test-frontend +test-frontend: ## Test frontend using jest + @echo "### Testing frontend" + cd web && npm run test + +.PHONY: build-backend +build-backend: fmt-backend ## Build backend + @echo "### Building backend" + GOARCH=${GOARCH} go build ${BUILD_FLAGS} -mod vendor -o plugin-backend cmd/plugin-backend.go -.PHONY: lint -lint: lint-backend lint-frontend +##@ Develop backend -.PHONY: i18n -i18n: - @echo "### generating frontend locales" - cd web && npm run i18n +.PHONY: fmt-backend +fmt-backend: ## Run backend go fmt + go fmt ./... + +.PHONY: lint-backend +lint-backend: prereqs ## Lint backend code + @echo "### Linting backend code" + golangci-lint run ./... .PHONY: test-backend -test-backend: +test-backend: ## Test backend using go test @echo "### Testing backend" go test ./... -coverpkg=./... -coverprofile cover.out -.PHONY: test-frontend -test-frontend: - @echo "### Testing frontend" - cd web && npm run test - .PHONY: cypress -cypress: +cypress: ## Test frontend using cypress @echo "### Opening cypress" cd web && npm run cypress:open -.PHONY: test -test: test-backend test-frontend - -.PHONY: build-backend -build-backend: fmt-backend - @echo "### Building backend" - go build ${BUILD_FLAGS} -mod vendor -o plugin-backend cmd/plugin-backend.go - .PHONY: just-build-frontend -just-build-frontend: +just-build-frontend: ## Build frontend @echo "### Building frontend" cd web && npm run build -.PHONY: build-frontend -build-frontend: install-frontend fmt-frontend just-build-frontend - .PHONY: build-frontend-standalone -build-frontend-standalone: install-frontend fmt-frontend +build-frontend-standalone: install-frontend fmt-frontend ## Run npm install, format and build frontend as standalone @echo "### Building frontend standalone" cd web && npm run build:standalone -.PHONY: build -build: build-backend build-frontend - -.PHONY: build-standalone -build-standalone: build-backend build-frontend-standalone - -.PHONY: frontend -frontend: build-frontend lint-frontend test-frontend - -.PHONY: backend -backend: build-backend lint-backend test-backend - -.PHONY: image -image: - @echo "### Building image with ${OCI_BIN}" - $(OCI_BIN) build -t $(IMAGE) . - -.PHONY: build-ci-images -build-ci-images: -ifeq ($(TAG), main) -# Also tag "latest" only for branch "main" - $(OCI_BIN) build -t $(IMAGE) -t $(BASE_IMAGE):latest . -else - $(OCI_BIN) build -t $(IMAGE) . -endif - $(OCI_BIN) build --build-arg BASE_IMAGE=$(IMAGE) -t $(BASE_IMAGE):$(BUILD_SHA) -f shortlived.Dockerfile . - -.PHONY: push -push: - $(OCI_BIN) push $(IMAGE) - .PHONY: serve -serve: +serve: ## Run backend ./plugin-backend $(CMDLINE_ARGS) .PHONY: serve-mock -serve-mock: +serve-mock: ## Run backend using mocks ./plugin-backend --loki-mock $(CMDLINE_ARGS) -.PHONY: start -start: build-backend install-frontend - @echo "### Starting backend on http://localhost:9002" - bash -c "trap 'fuser -k 9002/tcp' EXIT; \ - ./plugin-backend -port 9002 $(CMDLINE_ARGS) & cd web && npm run start" - -.PHONY: start-standalone -start-standalone: build-backend install-frontend - @echo "### Starting backend on http://localhost:9002" - bash -c "trap 'fuser -k 9002/tcp' EXIT; \ - ./plugin-backend -port 9002 $(CMDLINE_ARGS) & cd web && npm run start:standalone" - -.PHONY: start-standalone-mock -start-standalone-mock: build-backend install-frontend - @echo "### Starting backend on http://localhost:9002 using mock" - bash -c "trap 'fuser -k 9002/tcp' EXIT; \ - ./plugin-backend -port 9002 --loki-mock $(CMDLINE_ARGS) & cd web && npm run start:standalone" - -.PHONY: bridge -bridge: -ifeq (,${CONSOLE}) - @echo "CONSOLE must be set to your local path of the console repository clone. E.g. CONSOLE=/path/to/console make bridge" +##@ Images + +# note: to build and push custom image tag use: IMAGE_ORG=myuser VERSION=dev make images +.PHONY: image-build +image-build: ## Build MULTIARCH_TARGETS images + trap 'exit' INT; \ + $(foreach target,$(MULTIARCH_TARGETS),$(call build_target,$(target))) + +.PHONY: image-push +image-push: ## Push MULTIARCH_TARGETS images + trap 'exit' INT; \ + $(foreach target,$(MULTIARCH_TARGETS),$(call push_target,$(target))) + +.PHONY: manifest-build +manifest-build: ## Build MULTIARCH_TARGETS manifest + @echo 'building manifest $(IMAGE)' + DOCKER_BUILDKIT=1 $(OCI_BIN) manifest create ${IMAGE} $(foreach target,$(MULTIARCH_TARGETS),--amend ${IMAGE}-$(target)); + +.PHONY: manifest-push +manifest-push: ## Push MULTIARCH_TARGETS manifest + @echo 'publish manifest $(IMAGE)' +ifeq (${OCI_BIN}, docker) + DOCKER_BUILDKIT=1 $(OCI_BIN) manifest push ${IMAGE}; else - @echo "### Setting bridge from ${CONSOLE} to http://localhost:9000/netflow-traffic" - cd ${CONSOLE} && source contrib/oc-environment.sh && ./bin/bridge -plugins netobserv-plugin=http://localhost:9001/ --plugin-proxy='{"services":[{"consoleAPIPath":"/api/proxy/plugin/netobserv-plugin/backend/","endpoint":"http://localhost:9001"}]}' - cd - + DOCKER_BUILDKIT=1 $(OCI_BIN) manifest push ${IMAGE} docker://${IMAGE}; endif -.PHONY: generate-doc -generate-doc: ## Generate documentation of the flows JSON format - cd web && npm run generate-doc +.PHONY: ci-manifest-build +ci-manifest-build: manifest-build ## Build CI manifest + $(OCI_BIN) build --build-arg BASE_IMAGE=$(IMAGE) -t $(IMAGE_SHA) -f shortlived.Dockerfile . +ifeq ($(VERSION), main) +# Also tag "latest" only for branch "main" + $(OCI_BIN) build -t $(IMAGE) -t $(IMAGE_TAG_BASE):latest . +endif + +.PHONY: ci-manifest-push +ci-manifest-push: ## Push CI manifest + $(OCI_BIN) push $(IMAGE_SHA) + ifeq ($(VERSION), main) +# Also tag "latest" only for branch "main" + $(OCI_BIN) push $(IMAGE) + $(OCI_BIN) push $(IMAGE_TAG_BASE):latest + endif + +include .mk/shortcuts.mk diff --git a/README.md b/README.md index c62c16672..0b3dcb37b 100644 --- a/README.md +++ b/README.md @@ -78,13 +78,16 @@ Images are located on https://quay.io/repository/netobserv/network-observability ```bash # build the default image (quay.io/netobserv/network-observability-console-plugin:main): -make image +make image-build -# build and push on your own quay.io account (quay.io/myuser/network-observability-console-plugin:main): -IMG_USER=myuser make image push +# push the default image (quay.io/netobserv/network-observability-console-plugin:main): +make image-push + +# build and push on your own quay.io account (quay.io/myuser/network-observability-console-plugin:dev): +IMAGE_ORG=myuser VERSION=dev make images # build and push on a different registry -IMAGE=dockerhub.io/myuser/plugin:tag make image push +IMAGE=dockerhub.io/myuser/plugin:tag make images ``` ### Testing in OpenShift @@ -94,7 +97,7 @@ Probably the easiest way to test without dev mode (e.g. to test a pull request) E.g: ```bash -IMAGE=quay.io/${USER}/network-observability-console-plugin:pr-xx make image push +IMAGE=quay.io/${USER}/network-observability-console-plugin:pr-xx make images oc edit FlowCollector cluster # Here replace image with the newly created one under .spec.consolePlugin.image