mirror of
https://github.com/netbirdio/dashboard.git
synced 2026-09-23 00:30:43 -07:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0844507d8e | ||
|
|
7812f76bcf | ||
|
|
ba31f63400 | ||
|
|
5cf41dbc76 |
No files matched your search
@@ -1,12 +0,0 @@
|
|||||||
# The image only needs the pre-built static export (out/) and the docker/
|
|
||||||
# config files. Keep the build context small by dropping everything heavy and
|
|
||||||
# irrelevant — without this, `docker build .` ships node_modules and .next.
|
|
||||||
node_modules
|
|
||||||
.next
|
|
||||||
.git
|
|
||||||
.github
|
|
||||||
e2e
|
|
||||||
src
|
|
||||||
public
|
|
||||||
*.tar.gz
|
|
||||||
*.tar
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": ["next/core-web-vitals","prettier"],
|
||||||
|
"plugins": ["simple-import-sort"],
|
||||||
|
"rules": {
|
||||||
|
"simple-import-sort/imports": [
|
||||||
|
"warn",
|
||||||
|
{
|
||||||
|
"groups": [["^\\u0000", "^@?\\w", "^[^.]", "^\\."]]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"simple-import-sort/exports": "warn"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
## Issue ticket number and link
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
Select exactly one:
|
|
||||||
|
|
||||||
- [ ] I added/updated documentation for this change
|
|
||||||
- [ ] Documentation is **not needed** for this change (explain why)
|
|
||||||
|
|
||||||
### Docs PR URL (required if "docs added" is checked)
|
|
||||||
Paste the PR link from https://github.com/netbirdio/docs here:
|
|
||||||
|
|
||||||
https://github.com/netbirdio/docs/pull/__
|
|
||||||
|
|
||||||
## E2E tests
|
|
||||||
Optional: override the image tags used by the Playwright e2e workflow.
|
|
||||||
Defaults to `main` when omitted.
|
|
||||||
|
|
||||||
management-cloud-tag: main
|
|
||||||
reverse-proxy-tag: main
|
|
||||||
@@ -7,24 +7,17 @@ on:
|
|||||||
- "**"
|
- "**"
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
# Cancel in-progress runs on the same ref (PR or branch) when a new commit
|
|
||||||
# arrives, so we don't waste CI building superseded commits.
|
|
||||||
concurrency:
|
|
||||||
group: build-and-push-${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DOCKERHUB_IMAGE: netbirdio/dashboard
|
IMAGE_NAME: netbirdio/dashboard
|
||||||
GHCR_IMAGE: ghcr.io/netbirdio/dashboard-cloud
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_n_push:
|
build_n_push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: setup-node
|
- name: setup-node
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: '20'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
@@ -39,7 +32,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
repository: netbirdio/IronRDP
|
repository: netbirdio/IronRDP
|
||||||
tag: v0.0.2
|
latest: true
|
||||||
fileName: "*.ts"
|
fileName: "*.ts"
|
||||||
out-file-path: 'public/ironrdp-pkg'
|
out-file-path: 'public/ironrdp-pkg'
|
||||||
|
|
||||||
@@ -48,7 +41,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
repository: netbirdio/IronRDP
|
repository: netbirdio/IronRDP
|
||||||
tag: v0.0.2
|
latest: true
|
||||||
fileName: "*.js"
|
fileName: "*.js"
|
||||||
out-file-path: 'public/ironrdp-pkg'
|
out-file-path: 'public/ironrdp-pkg'
|
||||||
|
|
||||||
@@ -57,7 +50,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
repository: netbirdio/IronRDP
|
repository: netbirdio/IronRDP
|
||||||
tag: v0.0.2
|
latest: true
|
||||||
fileName: "ironrdp_web_bg.wasm"
|
fileName: "ironrdp_web_bg.wasm"
|
||||||
out-file-path: 'public/ironrdp-pkg'
|
out-file-path: 'public/ironrdp-pkg'
|
||||||
|
|
||||||
@@ -76,83 +69,29 @@ jobs:
|
|||||||
NEXT_PUBLIC_DASHBOARD_VERSION: ${{ steps.version.outputs.version }}
|
NEXT_PUBLIC_DASHBOARD_VERSION: ${{ steps.version.outputs.version }}
|
||||||
-
|
-
|
||||||
name: Set up QEMU
|
name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v2
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v2
|
||||||
-
|
-
|
||||||
name: Docker meta
|
name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v4
|
||||||
with:
|
with:
|
||||||
images: |
|
images: ${{ env.IMAGE_NAME }}
|
||||||
${{ env.DOCKERHUB_IMAGE }}
|
-
|
||||||
${{ env.GHCR_IMAGE }}
|
name: Login to DockerHub
|
||||||
flavor: |
|
uses: docker/login-action@v2
|
||||||
latest=false
|
|
||||||
tags: |
|
|
||||||
type=schedule
|
|
||||||
type=ref,event=branch
|
|
||||||
type=ref,event=tag
|
|
||||||
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}
|
|
||||||
type=ref,event=pr
|
|
||||||
type=sha
|
|
||||||
|
|
||||||
- name: Docker meta (rootless)
|
|
||||||
id: meta_rootless
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
${{ env.DOCKERHUB_IMAGE }}
|
|
||||||
${{ env.GHCR_IMAGE }}
|
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
suffix=-rootless,onlatest=true
|
|
||||||
tags: |
|
|
||||||
type=schedule
|
|
||||||
type=ref,event=branch
|
|
||||||
type=ref,event=tag
|
|
||||||
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}
|
|
||||||
type=ref,event=pr
|
|
||||||
type=sha
|
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.NB_DOCKER_USER }}
|
username: ${{ secrets.NB_DOCKER_USER }}
|
||||||
password: ${{ secrets.NB_DOCKER_TOKEN }}
|
password: ${{ secrets.NB_DOCKER_TOKEN }}
|
||||||
|
-
|
||||||
- name: Log in to the GitHub Container registry
|
name: Docker build and push
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
uses: docker/build-push-action@v3
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push Docker image
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/Dockerfile
|
file: docker/Dockerfile
|
||||||
push: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
|
push: true
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm
|
platforms: linux/amd64,linux/arm64,linux/arm
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
||||||
- name: Build and push rootless Docker image
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/Dockerfile.rootless
|
|
||||||
push: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
|
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm
|
|
||||||
tags: ${{ steps.meta_rootless.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta_rootless.outputs.labels }}
|
|
||||||
|
|
||||||
- if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
||||||
run: |
|
|
||||||
echo '### Pushed tags' >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo '${{ steps.meta.outputs.tags }}' >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo '${{ steps.meta_rootless.outputs.tags }}' >> $GITHUB_STEP_SUMMARY
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
name: Bump netbird wasm client
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
tag:
|
|
||||||
description: 'NetBird release tag (e.g. v0.78.0)'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ inputs.tag }}
|
|
||||||
cancel-in-progress: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
bump:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
token: ${{ secrets.NETBIRD_DEV_BOT_GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Configure git
|
|
||||||
run: |
|
|
||||||
git config --global user.email "dev@netbird.io"
|
|
||||||
git config --global user.name "netbirddev"
|
|
||||||
|
|
||||||
# The tag rides in env and is validated before use, so a crafted dispatch
|
|
||||||
# input cannot expand into shell source or reach the sed expression.
|
|
||||||
- name: Update the default wasm path
|
|
||||||
id: bump
|
|
||||||
env:
|
|
||||||
TAG: ${{ inputs.tag }}
|
|
||||||
run: |
|
|
||||||
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
||||||
echo "Refusing tag '$TAG': expected vMAJOR.MINOR.PATCH"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
sed -i "s|https://pkgs.netbird.io/wasm/client/v[0-9.]*|https://pkgs.netbird.io/wasm/client/${TAG}|" src/utils/config.ts
|
|
||||||
|
|
||||||
branch="bump-netbird-wasm-${TAG#v}"
|
|
||||||
echo "branch=${branch}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
# The branch name is derived from the tag, so a re-dispatch of the
|
|
||||||
# same release would collide with the branch and pull request an
|
|
||||||
# earlier run left behind.
|
|
||||||
if git ls-remote --exit-code --heads origin "${branch}" >/dev/null 2>&1; then
|
|
||||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "Branch ${branch} already exists, ${TAG} was handled by an earlier run"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
git checkout -b "${branch}"
|
|
||||||
git add src/utils/config.ts
|
|
||||||
if git diff --cached --quiet; then
|
|
||||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "Default wasm path already at ${TAG}, nothing to do"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
||||||
git commit -m "Bump the WASM client to ${TAG}"
|
|
||||||
git push --set-upstream origin "${branch}"
|
|
||||||
|
|
||||||
- name: Create pull request
|
|
||||||
if: steps.bump.outputs.skip != 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.NETBIRD_DEV_BOT_GITHUB_TOKEN }}
|
|
||||||
TAG: ${{ inputs.tag }}
|
|
||||||
BRANCH: ${{ steps.bump.outputs.branch }}
|
|
||||||
run: |
|
|
||||||
gh pr create \
|
|
||||||
--base main \
|
|
||||||
--head "$BRANCH" \
|
|
||||||
--title "Bump the WASM client to ${TAG}" \
|
|
||||||
--body "Automated wasm path bump triggered by netbird release ${TAG}."
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
name: Docs Acknowledgement
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, edited, synchronize]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docs-ack:
|
|
||||||
name: Require docs PR URL or explicit "not needed"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Read PR body
|
|
||||||
id: body
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
BODY_B64=$(jq -r '.pull_request.body // "" | @base64' "$GITHUB_EVENT_PATH")
|
|
||||||
{
|
|
||||||
echo "body_b64=$BODY_B64"
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Validate checkbox selection
|
|
||||||
id: validate
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
BODY_B64: ${{ steps.body.outputs.body_b64 }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
if ! body="$(printf '%s' "$BODY_B64" | base64 -d)"; then
|
|
||||||
echo "::error::Failed to decode PR body from base64. Data may be corrupted or missing."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
added_checked=$(printf '%s' "$body" | grep -Ei '^[[:space:]]*-\s*\[x\]\s*I added/updated documentation' | wc -l | tr -d '[:space:]' || true)
|
|
||||||
noneed_checked=$(printf '%s' "$body" | grep -Ei '^[[:space:]]*-\s*\[x\]\s*Documentation is \*\*not needed\*\*' | wc -l | tr -d '[:space:]' || true)
|
|
||||||
|
|
||||||
total=$((added_checked + noneed_checked))
|
|
||||||
if [ "$total" -ne 1 ]; then
|
|
||||||
echo "::error::You must check exactly one docs option in the PR template (either 'docs added' OR 'not needed')."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$added_checked" -eq 1 ]; then
|
|
||||||
echo "mode=added" >> "$GITHUB_OUTPUT"
|
|
||||||
else
|
|
||||||
echo "mode=noneed" >> "$GITHUB_OUTPUT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Extract docs PR URL (when 'docs added')
|
|
||||||
if: steps.validate.outputs.mode == 'added'
|
|
||||||
id: extract
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
BODY_B64: ${{ steps.body.outputs.body_b64 }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
body="$(printf '%s' "$BODY_B64" | base64 -d)"
|
|
||||||
|
|
||||||
# Strictly require HTTPS and that it's a PR in netbirdio/docs
|
|
||||||
# e.g., https://github.com/netbirdio/docs/pull/1234
|
|
||||||
url="$(printf '%s' "$body" | grep -Eo 'https://github\.com/netbirdio/docs/pull/[0-9]+' | head -n1 || true)"
|
|
||||||
|
|
||||||
if [ -z "${url:-}" ]; then
|
|
||||||
echo "::error::You checked 'docs added' but didn't include a valid HTTPS PR link to netbirdio/docs (e.g., https://github.com/netbirdio/docs/pull/1234)."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
pr_number="$(printf '%s' "$url" | sed -E 's#.*/pull/([0-9]+)$#\1#')"
|
|
||||||
{
|
|
||||||
echo "url=$url"
|
|
||||||
echo "pr_number=$pr_number"
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Verify docs PR exists (and is open or merged)
|
|
||||||
if: steps.validate.outputs.mode == 'added'
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
id: verify
|
|
||||||
env:
|
|
||||||
PR_NUMBER: ${{ steps.extract.outputs.pr_number }}
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const prNumber = parseInt(process.env.PR_NUMBER, 10);
|
|
||||||
const { data } = await github.rest.pulls.get({
|
|
||||||
owner: 'netbirdio',
|
|
||||||
repo: 'docs',
|
|
||||||
pull_number: prNumber
|
|
||||||
});
|
|
||||||
|
|
||||||
// Allow open or merged PRs
|
|
||||||
const ok = data.state === 'open' || data.merged === true;
|
|
||||||
core.setOutput('state', data.state);
|
|
||||||
core.setOutput('merged', String(!!data.merged));
|
|
||||||
if (!ok) {
|
|
||||||
core.setFailed(`Docs PR #${prNumber} exists but is neither open nor merged (state=${data.state}, merged=${data.merged}).`);
|
|
||||||
}
|
|
||||||
result-encoding: string
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: All good
|
|
||||||
run: echo "Documentation requirement satisfied âś…"
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
name: Playwright E2E Tests
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
pull_request:
|
|
||||||
# `edited` is included so that updating the PR description (e.g. to set
|
|
||||||
# `management-cloud-tag: <tag>` or `reverse-proxy-tag: <tag>`) re-triggers
|
|
||||||
# the e2e run with the new tag.
|
|
||||||
types: [opened, synchronize, reopened, edited]
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
management-cloud-tag:
|
|
||||||
description: 'Management Cloud image tag'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
default: 'main'
|
|
||||||
reverse-proxy-tag:
|
|
||||||
description: 'Reverse Proxy image tag'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
default: 'main'
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
playwright-run:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.ref }}
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: setup-node
|
|
||||||
uses: actions/setup-node@v5
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm install
|
|
||||||
|
|
||||||
- name: Install Playwright browsers
|
|
||||||
run: npx playwright install --with-deps chromium
|
|
||||||
|
|
||||||
- name: Log in to the Container registry
|
|
||||||
uses: docker/login-action@v4
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.CI_DOCKER_PULL_GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- run: echo '{}' > .local-config.json
|
|
||||||
|
|
||||||
- name: Install jq
|
|
||||||
run: sudo apt-get install jq
|
|
||||||
|
|
||||||
- name: Resolve management-cloud image tag
|
|
||||||
id: management_tag
|
|
||||||
env:
|
|
||||||
INPUT_TAG: ${{ inputs.management-cloud-tag }}
|
|
||||||
PR_BODY: ${{ github.event.pull_request.body }}
|
|
||||||
run: |
|
|
||||||
# Use workflow_dispatch input if provided, otherwise parse PR body.
|
|
||||||
# Falls back to `main` when not specified.
|
|
||||||
if [ -n "$INPUT_TAG" ]; then
|
|
||||||
TAG="$INPUT_TAG"
|
|
||||||
else
|
|
||||||
TAG=$(printf '%s' "$PR_BODY" \
|
|
||||||
| grep -iE '^[[:space:]]*management-cloud-tag:[[:space:]]*[A-Za-z0-9._-]+[[:space:]]*$' \
|
|
||||||
| head -n1 \
|
|
||||||
| sed -E 's/^[[:space:]]*[Mm]anagement-cloud-tag:[[:space:]]*([A-Za-z0-9._-]+)[[:space:]]*$/\1/' \
|
|
||||||
|| true)
|
|
||||||
if [ -z "$TAG" ]; then
|
|
||||||
TAG="main"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo "Using management-cloud tag: $TAG"
|
|
||||||
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Resolve reverse-proxy image tag
|
|
||||||
id: reverse_proxy_tag
|
|
||||||
env:
|
|
||||||
INPUT_TAG: ${{ inputs.reverse-proxy-tag }}
|
|
||||||
PR_BODY: ${{ github.event.pull_request.body }}
|
|
||||||
run: |
|
|
||||||
if [ -n "$INPUT_TAG" ]; then
|
|
||||||
TAG="$INPUT_TAG"
|
|
||||||
else
|
|
||||||
TAG=$(printf '%s' "$PR_BODY" \
|
|
||||||
| grep -iE '^[[:space:]]*reverse-proxy-tag:[[:space:]]*[A-Za-z0-9._-]+[[:space:]]*$' \
|
|
||||||
| head -n1 \
|
|
||||||
| sed -E 's/^[[:space:]]*[Rr]everse-proxy-tag:[[:space:]]*([A-Za-z0-9._-]+)[[:space:]]*$/\1/' \
|
|
||||||
|| true)
|
|
||||||
if [ -z "$TAG" ]; then
|
|
||||||
TAG="main"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo "Using reverse-proxy tag: $TAG"
|
|
||||||
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Restore geolocation database cache
|
|
||||||
id: geo-cache
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
path: e2e/environment/geo-cache
|
|
||||||
key: geolite-dbs-v1
|
|
||||||
|
|
||||||
- name: Build dashboard and set up test environment
|
|
||||||
env:
|
|
||||||
MANAGEMENT_IMAGE_TAG: ${{ steps.management_tag.outputs.tag }}
|
|
||||||
REVERSE_PROXY_IMAGE_TAG: ${{ steps.reverse_proxy_tag.outputs.tag }}
|
|
||||||
# The docker environment (image pulls, Zitadel bootstrap) is
|
|
||||||
# network-bound and the Next build is CPU-bound, so they overlap.
|
|
||||||
# The build reads .test-config.json via the @/config/test alias,
|
|
||||||
# and create-test-env.sh renders that file only after the Zitadel
|
|
||||||
# bootstrap — so the build waits for it before starting.
|
|
||||||
run: |
|
|
||||||
(cd ./e2e/environment && bash create-test-env.sh) > env-setup.log 2>&1 &
|
|
||||||
ENV_PID=$!
|
|
||||||
until [ -s .test-config.json ] && jq empty .test-config.json 2>/dev/null; do
|
|
||||||
if ! kill -0 "$ENV_PID" 2>/dev/null; then break; fi
|
|
||||||
sleep 2
|
|
||||||
done
|
|
||||||
if ! [ -s .test-config.json ]; then
|
|
||||||
echo "::error::create-test-env.sh exited before rendering .test-config.json"
|
|
||||||
cat env-setup.log
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# Lowest CPU priority: the containers must win the scheduler, or
|
|
||||||
# the build can starve management past the proxy-registration wait.
|
|
||||||
if ! nice -n 19 env APP_ENV=test npx next build; then
|
|
||||||
kill "$ENV_PID" 2>/dev/null || true
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if ! wait "$ENV_PID"; then
|
|
||||||
echo "::error::Test environment setup failed"
|
|
||||||
cat env-setup.log
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
cat env-setup.log
|
|
||||||
|
|
||||||
# Saved right after env setup rather than in a post step, so a later
|
|
||||||
# test failure doesn't lose the cache.
|
|
||||||
- name: Save geolocation database cache
|
|
||||||
if: always() && steps.geo-cache.outputs.cache-hit != 'true' && hashFiles('e2e/environment/geo-cache/**') != ''
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
with:
|
|
||||||
path: e2e/environment/geo-cache
|
|
||||||
key: geolite-dbs-v1
|
|
||||||
|
|
||||||
- name: Run Playwright tests
|
|
||||||
id: playwright
|
|
||||||
run: |
|
|
||||||
set -o pipefail
|
|
||||||
npx playwright test --config=e2e/playwright.config.ts 2>&1 | tee playwright-output.log
|
|
||||||
|
|
||||||
- name: Append Playwright summary to job summary
|
|
||||||
if: always() && hashFiles('e2e/test-results/results.json') != ''
|
|
||||||
run: |
|
|
||||||
if [ -f e2e/test-results/results.json ]; then
|
|
||||||
passed=$(jq '.stats.expected // 0' e2e/test-results/results.json)
|
|
||||||
failed=$(jq '.stats.unexpected // 0' e2e/test-results/results.json)
|
|
||||||
skipped=$(jq '.stats.skipped // 0' e2e/test-results/results.json)
|
|
||||||
duration=$(jq '.stats.duration // 0' e2e/test-results/results.json)
|
|
||||||
{
|
|
||||||
echo '### Playwright results'
|
|
||||||
echo ''
|
|
||||||
echo "| Passed | Failed | Skipped | Duration |"
|
|
||||||
echo "|--------|--------|---------|----------|"
|
|
||||||
echo "| $passed | $failed | $skipped | ${duration}ms |"
|
|
||||||
} >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Collect container logs
|
|
||||||
if: failure()
|
|
||||||
run: |
|
|
||||||
cd e2e/environment
|
|
||||||
docker compose logs management --tail=500 --no-color > management.log 2>&1 || true
|
|
||||||
docker compose logs reverse-proxy --tail=500 --no-color > reverse-proxy.log 2>&1 || true
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
if: ${{ !cancelled() }}
|
|
||||||
with:
|
|
||||||
name: playwright-report
|
|
||||||
path: e2e/playwright-report/
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
if: ${{ failure() }}
|
|
||||||
with:
|
|
||||||
name: playwright-traces
|
|
||||||
path: e2e/test-results/
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
if: ${{ failure() }}
|
|
||||||
with:
|
|
||||||
name: management-logs
|
|
||||||
path: e2e/environment/management.log
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
if: ${{ failure() }}
|
|
||||||
with:
|
|
||||||
name: reverse-proxy-logs
|
|
||||||
path: e2e/environment/reverse-proxy.log
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
name: Sync deploy templates to S3
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
paths:
|
|
||||||
- "templates/reverse-proxy/**"
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
id-token: write
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
sync:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- uses: aws-actions/configure-aws-credentials@v4
|
|
||||||
with:
|
|
||||||
role-to-assume: ${{ secrets.DEPLOY_TEMPLATES_ROLE_ARN }}
|
|
||||||
aws-region: eu-central-1
|
|
||||||
|
|
||||||
- name: Validate CloudFormation template
|
|
||||||
run: |
|
|
||||||
aws cloudformation validate-template \
|
|
||||||
--template-body file://templates/reverse-proxy/netbird-proxy-cfn.yaml
|
|
||||||
|
|
||||||
- name: Upload CloudFormation template
|
|
||||||
run: |
|
|
||||||
aws s3 cp templates/reverse-proxy/netbird-proxy-cfn.yaml \
|
|
||||||
s3://netbird-deploy-templates/templates/netbird-proxy-cfn.yaml
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
name: Test cloud deploy config
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- "docker/init_react_envs.sh"
|
|
||||||
- "templates/reverse-proxy/**"
|
|
||||||
- "src/modules/reverse-proxy/clusters/ClusterCloudDeploy.tsx"
|
|
||||||
- ".github/workflows/test-cloud-deploy.yml"
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
csp-connect-src:
|
|
||||||
name: CSP allows cloud provider APIs
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install nginx
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y nginx gettext-base
|
|
||||||
|
|
||||||
- name: Prepare nginx layout expected by the init script
|
|
||||||
run: |
|
|
||||||
sudo mkdir -p /etc/nginx/http.d /usr/share/nginx/html
|
|
||||||
echo 'add_header Content-Security-Policy "placeholder" always;' | sudo tee /etc/nginx/http.d/default.conf
|
|
||||||
sudo touch /usr/share/nginx/html/OidcTrustedDomains.js.tmpl
|
|
||||||
sudo systemctl start nginx
|
|
||||||
|
|
||||||
- name: Run init script with production-like env
|
|
||||||
env:
|
|
||||||
AUTH_AUTHORITY: https://auth.example.com
|
|
||||||
AUTH_CLIENT_ID: test-client
|
|
||||||
AUTH_AUDIENCE: test-audience
|
|
||||||
AUTH_SUPPORTED_SCOPES: openid profile email
|
|
||||||
USE_AUTH0: "false"
|
|
||||||
NETBIRD_MGMT_API_ENDPOINT: https://api.example.com
|
|
||||||
run: sudo -E bash docker/init_react_envs.sh
|
|
||||||
|
|
||||||
- name: Assert provider APIs are in connect-src
|
|
||||||
run: |
|
|
||||||
CSP=$(grep -o 'Content-Security-Policy "[^"]*"' /etc/nginx/http.d/default.conf)
|
|
||||||
echo "Generated CSP: $CSP"
|
|
||||||
CONNECT_SRC=$(echo "$CSP" | sed 's/.*connect-src \([^;]*\);.*/\1/')
|
|
||||||
echo "connect-src: $CONNECT_SRC"
|
|
||||||
status=0
|
|
||||||
for origin in https://api.hetzner.cloud https://api.digitalocean.com; do
|
|
||||||
if echo "$CONNECT_SRC" | grep -qF "$origin"; then
|
|
||||||
echo "OK: $origin"
|
|
||||||
else
|
|
||||||
echo "MISSING in connect-src: $origin"
|
|
||||||
status=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
exit $status
|
|
||||||
|
|
||||||
cfn-template-url:
|
|
||||||
name: CloudFormation template URL is live
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Extract template URL from component and check it
|
|
||||||
run: |
|
|
||||||
URL=$(grep -o 'https://[^"]*netbird-proxy-cfn\.yaml' src/modules/reverse-proxy/clusters/ClusterCloudDeploy.tsx)
|
|
||||||
echo "CFN_TEMPLATE_URL: $URL"
|
|
||||||
test -n "$URL"
|
|
||||||
# Non-blocking: the template is published by sync-deploy-templates on
|
|
||||||
# the default branch, so it may not exist yet for a PR that only edits
|
|
||||||
# the URL. Warn instead of failing the check.
|
|
||||||
if curl -sfI "$URL" >/dev/null; then
|
|
||||||
echo "OK: template URL is live"
|
|
||||||
else
|
|
||||||
echo "::warning::CloudFormation template URL is not reachable yet: $URL"
|
|
||||||
fi
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
name: Unit Tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
# Cancel superseded runs on the same ref so a new push doesn't queue behind an
|
|
||||||
# outdated one (mirrors build_and_push.yml).
|
|
||||||
concurrency:
|
|
||||||
group: unit-tests-${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
vitest:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: setup-node
|
|
||||||
uses: actions/setup-node@v5
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Run unit tests
|
|
||||||
run: npm run test:unit
|
|
||||||
+3
-14
@@ -35,19 +35,10 @@ yarn-error.log*
|
|||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
next-env.d.ts
|
next-env.d.ts
|
||||||
|
|
||||||
# local UI sandbox (throwaway preview harness — never commit)
|
|
||||||
/src/app/sandbox/
|
|
||||||
|
|
||||||
# config
|
# config
|
||||||
.local*config*.json
|
.local-config.json
|
||||||
.test-config.json
|
.test-config.json
|
||||||
e2e/playwright.env.json
|
cypress.env.json
|
||||||
e2e/fixtures/auth/*.json
|
|
||||||
e2e/test-results/
|
|
||||||
e2e/playwright-report/
|
|
||||||
/test-results/
|
|
||||||
/playwright-report/
|
|
||||||
playwright-report*.zip
|
|
||||||
.configs/.local-config.zitadel.json
|
.configs/.local-config.zitadel.json
|
||||||
.configs/.staging-config.json
|
.configs/.staging-config.json
|
||||||
.configs/.temp-config.json
|
.configs/.temp-config.json
|
||||||
@@ -56,6 +47,4 @@ playwright-report*.zip
|
|||||||
/public/ironrdp-pkg/
|
/public/ironrdp-pkg/
|
||||||
/public/netbird.wasm
|
/public/netbird.wasm
|
||||||
.idea
|
.idea
|
||||||
src/.local-config*
|
src/.local-config*
|
||||||
# local mock data (throwaway preview — never commit)
|
|
||||||
/src/utils/mockData.ts
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
Mikhail Bragin (https://github.com/braginini)
|
Mikhail Bragin (https://github.com/braginini)
|
||||||
Maycon Santos (https://github.com/mlsmaycon)
|
Maycon Santos (https://github.com/mlsmaycon)
|
||||||
NetBird GmbH
|
Wiretrustee UG (haftungsbeschränkt)
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"tag": "New",
|
"tag": "New",
|
||||||
"text": "The new NetBird desktop app is here - now available in the v0.75 release.",
|
"text": "NetBird Reverse Proxy - Expose internal services to the public with automatic TLS and optional authentication.",
|
||||||
"link": "https://netbird.io/knowledge-hub/netbird-v0-75-new-desktop-app",
|
"link": "https://docs.netbird.io/manage/reverse-proxy",
|
||||||
"linkText": "Learn more",
|
"linkText": "Learn more",
|
||||||
"variant": "important",
|
"variant": "important",
|
||||||
"isExternal": true,
|
"isExternal": true,
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# Build the netbird-dashboard Docker image for linux/amd64 and export it as a
|
|
||||||
# portable tarball that can be loaded and run on a remote server.
|
|
||||||
#
|
|
||||||
# The dashboard image is nginx serving a Next.js *static export*: the Dockerfile
|
|
||||||
# only COPYs the pre-built out/ directory, so we build out/ on the host first
|
|
||||||
# (the static files are arch-independent) and then assemble the amd64 image.
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# ./build.sh # build + export netbird-dashboard.tar.gz
|
|
||||||
# IMAGE_TAG=v1 ./build.sh # override the image tag
|
|
||||||
# SKIP_BUILD=1 ./build.sh # reuse an existing out/ (skip npm build)
|
|
||||||
# ROOTLESS=1 ./build.sh # build the amd64-rootless image variant
|
|
||||||
#
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Always run relative to this script's directory (the project root).
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
IMAGE_NAME="${IMAGE_NAME:-netbird-dashboard}"
|
|
||||||
IMAGE_TAG="${IMAGE_TAG:-amd64}"
|
|
||||||
DOCKERFILE="docker/Dockerfile"
|
|
||||||
CONTAINER_PORT=80
|
|
||||||
OUTPUT_SUFFIX=""
|
|
||||||
|
|
||||||
case "${ROOTLESS:-0}" in
|
|
||||||
0) ;;
|
|
||||||
1)
|
|
||||||
DOCKERFILE="docker/Dockerfile.rootless"
|
|
||||||
CONTAINER_PORT=8080
|
|
||||||
OUTPUT_SUFFIX="-rootless"
|
|
||||||
[[ "${IMAGE_TAG}" == *-rootless ]] || IMAGE_TAG="${IMAGE_TAG}-rootless"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "ERROR: ROOTLESS must be 0 or 1." >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
IMAGE="${IMAGE_NAME}:${IMAGE_TAG}"
|
|
||||||
OUTPUT="${OUTPUT:-${IMAGE_NAME}${OUTPUT_SUFFIX}.tar.gz}"
|
|
||||||
|
|
||||||
# Build the static export (out/) unless told to reuse an existing one. Next 16
|
|
||||||
# no longer runs ESLint during `next build`; types are checked by the build via
|
|
||||||
# tsc (verify separately with `npx tsc --noEmit`).
|
|
||||||
if [[ "${SKIP_BUILD:-0}" != "1" ]]; then
|
|
||||||
if [[ ! -d node_modules ]]; then
|
|
||||||
echo "==> Installing dependencies (npm ci)"
|
|
||||||
npm ci
|
|
||||||
fi
|
|
||||||
echo "==> Building static export (next build) into out/"
|
|
||||||
npx next build
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -d out ]]; then
|
|
||||||
echo "ERROR: out/ not found — the static export did not build." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "==> Building ${IMAGE} for linux/amd64"
|
|
||||||
docker build \
|
|
||||||
--platform linux/amd64 \
|
|
||||||
-f "${DOCKERFILE}" \
|
|
||||||
-t "${IMAGE}" \
|
|
||||||
.
|
|
||||||
|
|
||||||
echo "==> Exporting ${IMAGE} to ${OUTPUT}"
|
|
||||||
docker save "${IMAGE}" | gzip > "${OUTPUT}"
|
|
||||||
|
|
||||||
echo "==> Done: ${OUTPUT} ($(du -h "${OUTPUT}" | cut -f1))"
|
|
||||||
echo
|
|
||||||
echo "Copy and run on the server:"
|
|
||||||
echo " scp ${OUTPUT} user@your-server:/tmp/"
|
|
||||||
echo " docker load < /tmp/${OUTPUT##*/}"
|
|
||||||
echo
|
|
||||||
echo "Run (nginx serves on container port ${CONTAINER_PORT}). Set the runtime env vars the"
|
|
||||||
echo "dashboard templates at startup — for the Agent Network onboarding test,"
|
|
||||||
echo "flip NETBIRD_AGENT_NETWORK_ONLY=true:"
|
|
||||||
echo " docker run -d --name ${IMAGE_NAME} --restart unless-stopped \\"
|
|
||||||
echo " -p 8080:${CONTAINER_PORT} \\"
|
|
||||||
echo " -e NETBIRD_MGMT_API_ENDPOINT=https://your-mgmt:443 \\"
|
|
||||||
echo " -e AUTH_AUTHORITY=https://your-idp/realms/netbird \\"
|
|
||||||
echo " -e AUTH_CLIENT_ID=netbird-dashboard \\"
|
|
||||||
echo " -e AUTH_AUDIENCE=netbird-dashboard \\"
|
|
||||||
echo " -e AUTH_SUPPORTED_SCOPES='openid profile email' \\"
|
|
||||||
echo " -e USE_AUTH0=false \\"
|
|
||||||
echo " -e NETBIRD_AGENT_NETWORK_ONLY=true \\"
|
|
||||||
echo " ${IMAGE}"
|
|
||||||
+1
-11
@@ -14,15 +14,5 @@
|
|||||||
"hotjarTrackID": "$NETBIRD_HOTJAR_TRACK_ID",
|
"hotjarTrackID": "$NETBIRD_HOTJAR_TRACK_ID",
|
||||||
"googleAnalyticsID": "$NETBIRD_GOOGLE_ANALYTICS_ID",
|
"googleAnalyticsID": "$NETBIRD_GOOGLE_ANALYTICS_ID",
|
||||||
"googleTagManagerID": "$NETBIRD_GOOGLE_TAG_MANAGER_ID",
|
"googleTagManagerID": "$NETBIRD_GOOGLE_TAG_MANAGER_ID",
|
||||||
"authServiceUrl": "$NETBIRD_AUTH_SERVICE_URL",
|
"wasmPath": "$NETBIRD_WASM_PATH"
|
||||||
"wasmPath": "$NETBIRD_WASM_PATH",
|
|
||||||
"licensed": "$NETBIRD_LICENSED",
|
|
||||||
"cloud": "$NETBIRD_CLOUD",
|
|
||||||
"agentNetworkOnly": "$NETBIRD_AGENT_NETWORK_ONLY",
|
|
||||||
"agentNetworkEnabled": "$NETBIRD_AGENT_NETWORK_ENABLED",
|
|
||||||
"hubspotPortalId": "$NETBIRD_HUBSPOT_PORTAL_ID",
|
|
||||||
"hubspotSignupFormId": "$NETBIRD_HUBSPOT_SIGNUP_FORM_ID",
|
|
||||||
"hubspotOnboardingFormId": "$NETBIRD_HUBSPOT_ONBOARDING_FORM_ID",
|
|
||||||
"hubspotSurveyFormId": "$NETBIRD_HUBSPOT_SURVEY_FORM_ID",
|
|
||||||
"analyticsExcludedEmails": "$NETBIRD_ANALYTICS_EXCLUDED_EMAILS"
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { defineConfig } from "cypress";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
e2e: {
|
||||||
|
baseUrl: "http://localhost:3000",
|
||||||
|
},
|
||||||
|
component: {
|
||||||
|
devServer: {
|
||||||
|
framework: "next",
|
||||||
|
bundler: "webpack",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewportWidth: 1920,
|
||||||
|
viewportHeight: 1080,
|
||||||
|
});
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
describe("Click all tabs in peer modal", () => {
|
||||||
|
it("passes", () => {
|
||||||
|
cy.visit("/install");
|
||||||
|
cy.get("div").contains("Linux").click();
|
||||||
|
cy.get("[data-cy=copy-to-clipboard]").click();
|
||||||
|
cy.get("div").contains("Windows").click();
|
||||||
|
cy.get("[data-cy=copy-to-clipboard]").click();
|
||||||
|
cy.get("div").contains("Android").click();
|
||||||
|
cy.get("[data-cy=copy-to-clipboard]").click();
|
||||||
|
cy.get("div").contains("Docker").click();
|
||||||
|
cy.get("[data-cy=copy-to-clipboard]").click();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "Using fixtures to represent data",
|
||||||
|
"email": "hello@cypress.io",
|
||||||
|
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
// ***********************************************
|
||||||
|
// This example commands.ts shows you how to
|
||||||
|
// create various custom commands and overwrite
|
||||||
|
// existing commands.
|
||||||
|
//
|
||||||
|
// For more comprehensive examples of custom
|
||||||
|
// commands please read more here:
|
||||||
|
// https://on.cypress.io/custom-commands
|
||||||
|
// ***********************************************
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a parent command --
|
||||||
|
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a child command --
|
||||||
|
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a dual command --
|
||||||
|
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This will overwrite an existing command --
|
||||||
|
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||||
|
//
|
||||||
|
// declare global {
|
||||||
|
// namespace Cypress {
|
||||||
|
// interface Chainable {
|
||||||
|
// login(email: string, password: string): Chainable<void>
|
||||||
|
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||||
|
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||||
|
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// ***********************************************************
|
||||||
|
// This example support/e2e.ts is processed and
|
||||||
|
// loaded automatically before your test files.
|
||||||
|
//
|
||||||
|
// This is a great place to put global configuration and
|
||||||
|
// behavior that modifies Cypress.
|
||||||
|
//
|
||||||
|
// You can change the location of this file or turn off
|
||||||
|
// automatically serving support files with the
|
||||||
|
// 'supportFile' configuration option.
|
||||||
|
//
|
||||||
|
// You can read more here:
|
||||||
|
// https://on.cypress.io/configuration
|
||||||
|
// ***********************************************************
|
||||||
|
|
||||||
|
// Import commands.js using ES2015 syntax:
|
||||||
|
import './commands'
|
||||||
|
|
||||||
|
// Alternatively you can use CommonJS syntax:
|
||||||
|
// require('./commands')
|
||||||
Loaded 20 of 977 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user