mirror of
https://codeberg.org/demostf/api.git
synced 2026-06-03 18:04:08 +02:00
flake reorg, nix integration testing
This commit is contained in:
parent
1a8380360b
commit
233dc5f01f
20 changed files with 3565 additions and 3723 deletions
219
.github/workflows/ci.yaml
vendored
219
.github/workflows/ci.yaml
vendored
|
|
@ -1,209 +1,32 @@
|
||||||
on: [push, pull_request]
|
name: "CI"
|
||||||
|
on:
|
||||||
name: CI
|
pull_request:
|
||||||
|
push:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
php-cs-fixer:
|
matrix:
|
||||||
name: PHP-CS-Fixer
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@master
|
|
||||||
- name: Setup PHP
|
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
|
||||||
php-version: '8.2'
|
|
||||||
extensions: apcu
|
|
||||||
- name: PHP-CS-Fixer
|
|
||||||
uses: OskarStark/php-cs-fixer-ga@3.25.0
|
|
||||||
with:
|
|
||||||
args: --diff --dry-run --allow-risky yes --stop-on-violation --using-cache=no --path-mode=intersection
|
|
||||||
|
|
||||||
phpstan:
|
|
||||||
name: PHPStan Static Analysis
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Setup PHP
|
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
|
||||||
php-version: '8.2'
|
|
||||||
extensions: apcu
|
|
||||||
- name: Composer
|
|
||||||
run: composer install
|
|
||||||
- name: phpstan
|
|
||||||
run: |
|
|
||||||
./vendor/bin/phpstan analyse --level 6 src
|
|
||||||
|
|
||||||
phpunit:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: Unit tests
|
|
||||||
|
|
||||||
services:
|
|
||||||
db:
|
|
||||||
image: demostf/db
|
|
||||||
env:
|
|
||||||
POSTGRES_PASSWORD: test
|
|
||||||
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Setup PHP
|
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
|
||||||
php-version: '8.2'
|
|
||||||
extensions: apcu
|
|
||||||
- name: Composer
|
|
||||||
run: composer install
|
|
||||||
- name: PHPUnit Tests
|
|
||||||
env:
|
|
||||||
DB_PORT: 5432
|
|
||||||
DB_TYPE: pgsql
|
|
||||||
DB_HOST: localhost
|
|
||||||
DB_USERNAME: postgres
|
|
||||||
DB_PASSWORD: test
|
|
||||||
DB_DATABASE: postgres
|
|
||||||
run: |
|
|
||||||
php ./vendor/bin/phpunit test
|
|
||||||
|
|
||||||
api:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: Integration tests
|
|
||||||
|
|
||||||
services:
|
|
||||||
db:
|
|
||||||
image: demostf/db
|
|
||||||
env:
|
|
||||||
POSTGRES_PASSWORD: test
|
|
||||||
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
api:
|
|
||||||
image: demostf/api
|
|
||||||
env:
|
|
||||||
BASE_HOST: localhost
|
|
||||||
DEMO_ROOT: /tmp
|
|
||||||
DEMO_HOST: localhost
|
|
||||||
DB_TYPE: pgsql
|
|
||||||
DB_HOST: db
|
|
||||||
DB_PORT: 5432
|
|
||||||
DB_DATABASE: postgres
|
|
||||||
DB_USERNAME: postgres
|
|
||||||
DB_PASSWORD: test
|
|
||||||
APP_ROOT: https://localhost
|
|
||||||
EDIT_SECRET: edit
|
|
||||||
volumes:
|
|
||||||
- src:/app
|
|
||||||
nginx:
|
|
||||||
image: demostf/api-nginx-test
|
|
||||||
ports:
|
|
||||||
- 80:80
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Setup PHP
|
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
|
||||||
php-version: '8.2'
|
|
||||||
extensions: apcu
|
|
||||||
- name: Composer
|
|
||||||
run: composer install
|
|
||||||
- name: copy code
|
|
||||||
run: |
|
|
||||||
docker run -v src:/data --name helper busybox true
|
|
||||||
docker cp src helper:/data/
|
|
||||||
docker cp vendor helper:/data/
|
|
||||||
docker rm helper
|
|
||||||
- env:
|
|
||||||
DB_URL: postgres://postgres:test@db:5432/postgres
|
|
||||||
BASE_URL: http://nginx
|
|
||||||
EDIT_KEY: edit
|
|
||||||
uses: docker://demostf/api-test
|
|
||||||
|
|
||||||
build-parser:
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: cachix/install-nix-action@v27
|
||||||
|
- id: set-matrix
|
||||||
|
run: echo "matrix={\"check\":$(nix eval --json '.#checks.x86_64-linux' --apply 'builtins.attrNames')}" | tee -a $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
checks:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [matrix]
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
fail-fast: false
|
||||||
machine:
|
matrix: ${{fromJson(needs.matrix.outputs.matrix)}}
|
||||||
- platform: x86_64-linux
|
name: ${{ matrix.check }}
|
||||||
- platform: aarch64-linux
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- if: matrix.machine.platform != 'x86_64-linux'
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- uses: cachix/install-nix-action@v26
|
|
||||||
with:
|
|
||||||
extra_nix_config: |
|
|
||||||
extra-platforms = aarch64-linux
|
|
||||||
- uses: icewind1991/attic-action@v1
|
|
||||||
with:
|
|
||||||
name: ci
|
|
||||||
instance: https://cache.icewind.me
|
|
||||||
authToken: '${{ secrets.ATTIC_TOKEN }}'
|
|
||||||
- run: nix build --option system ${{ matrix.machine.platform }} .#demostf-parser
|
|
||||||
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
machine:
|
|
||||||
- platform: x86_64-linux
|
|
||||||
- platform: aarch64-linux
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- if: matrix.machine.platform != 'x86_64-linux'
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- uses: cachix/install-nix-action@v26
|
|
||||||
with:
|
|
||||||
extra_nix_config: |
|
|
||||||
extra-platforms = aarch64-linux
|
|
||||||
- uses: icewind1991/attic-action@v1
|
|
||||||
with:
|
|
||||||
name: ci
|
|
||||||
instance: https://cache.icewind.me
|
|
||||||
authToken: '${{ secrets.ATTIC_TOKEN }}'
|
|
||||||
- run: nix build --option system ${{ matrix.machine.platform }}
|
|
||||||
|
|
||||||
|
|
||||||
build-docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [build, build-parser]
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
machine:
|
|
||||||
- platform: x86_64-linux
|
|
||||||
- platform: aarch64-linux
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- if: matrix.machine.platform != 'x86_64-linux'
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- uses: cachix/install-nix-action@v26
|
|
||||||
with:
|
|
||||||
extra_nix_config: |
|
|
||||||
extra-platforms = aarch64-linux
|
|
||||||
- uses: icewind1991/attic-action@v1
|
|
||||||
with:
|
|
||||||
name: ci
|
|
||||||
instance: https://cache.icewind.me
|
|
||||||
authToken: '${{ secrets.ATTIC_TOKEN }}'
|
|
||||||
- run: nix build --option system ${{ matrix.machine.platform }} .#demostf-api-docker
|
|
||||||
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [build-docker, api, phpunit]
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- uses: cachix/install-nix-action@v26
|
- uses: cachix/install-nix-action@v26
|
||||||
- uses: icewind1991/attic-action@v1
|
- uses: icewind1991/attic-action@v1
|
||||||
with:
|
with:
|
||||||
name: ci
|
name: ci
|
||||||
instance: https://cache.icewind.me
|
instance: https://cache.icewind.me
|
||||||
- run: nix run .#dockerManifest
|
authToken: "${{ secrets.ATTIC_TOKEN }}"
|
||||||
if: github.ref == 'refs/heads/master'
|
- run: nix build .#checks.x86_64-linux.${{ matrix.check }}
|
||||||
env:
|
|
||||||
VERSION: "1.0.0"
|
|
||||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -5,3 +5,4 @@ node_modules
|
||||||
*.cache
|
*.cache
|
||||||
.direnv
|
.direnv
|
||||||
result
|
result
|
||||||
|
demos
|
||||||
|
|
@ -3,32 +3,32 @@
|
||||||
"description": "api implementation for demos.tf",
|
"description": "api implementation for demos.tf",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"mikecao/flight": "^3.6",
|
"mikecao/flight": "^3.6",
|
||||||
"vlucas/phpdotenv": "^v5.4.1",
|
"vlucas/phpdotenv": "^v5.4.1",
|
||||||
"ircmaxell/random-lib": "^v1.2.0",
|
"ircmaxell/random-lib": "^v1.2.0",
|
||||||
"ehesp/steam-login": "^1.2",
|
"ehesp/steam-login": "^1.2",
|
||||||
"koraktor/steam-condenser": "dev-master#92dde9e3b462e93cc498fe795a712c61eec7051e",
|
"koraktor/steam-condenser": "dev-master#92dde9e3b462e93cc498fe795a712c61eec7051e",
|
||||||
"doctrine/dbal": "^3.3.6",
|
"doctrine/dbal": "^3.3.6",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-apcu": "*"
|
"ext-apcu": "*"
|
||||||
},
|
},
|
||||||
"repositories": [
|
"repositories": [
|
||||||
{
|
{
|
||||||
"type": "vcs",
|
"type": "vcs",
|
||||||
"url": "https://github.com/koraktor/steam-condenser-php"
|
"url": "https://github.com/koraktor/steam-condenser-php"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Demostf\\API\\": "src/",
|
"Demostf\\API\\": "src/",
|
||||||
"Demostf\\API\\Test\\": "test/"
|
"Demostf\\API\\Test\\": "test/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9.5.20",
|
"phpunit/phpunit": "^9.5.20",
|
||||||
"friendsofphp/php-cs-fixer": "^v3.3.0",
|
"friendsofphp/php-cs-fixer": "^v3.3.0",
|
||||||
"phpstan/phpstan": "^1.6.8"
|
"phpstan/phpstan": "^1.6.8"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"allow-plugins": {
|
"allow-plugins": {
|
||||||
|
|
|
||||||
53
docker.nix
53
docker.nix
|
|
@ -1,53 +0,0 @@
|
||||||
{
|
|
||||||
demostf-api,
|
|
||||||
demostf-parser,
|
|
||||||
php,
|
|
||||||
runtimeShell,
|
|
||||||
writeScriptBin,
|
|
||||||
fakeNss,
|
|
||||||
coreutils,
|
|
||||||
bash,
|
|
||||||
dockerTools
|
|
||||||
}: let
|
|
||||||
phpWithExtensions = php.buildEnv {
|
|
||||||
extensions = ({ enabled, all }: enabled ++ (with all; [pdo apcu]));
|
|
||||||
extraConfig = ''
|
|
||||||
post_max_size = 150M
|
|
||||||
upload_max_filesize = 150M
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in dockerTools.buildLayeredImage {
|
|
||||||
name = "demostf/api";
|
|
||||||
tag = "latest";
|
|
||||||
maxLayers = 10;
|
|
||||||
|
|
||||||
contents = [
|
|
||||||
demostf-api
|
|
||||||
demostf-parser
|
|
||||||
phpWithExtensions
|
|
||||||
dockerTools.caCertificates
|
|
||||||
coreutils
|
|
||||||
bash
|
|
||||||
fakeNss
|
|
||||||
(writeScriptBin "start-server" ''
|
|
||||||
#!${runtimeShell}
|
|
||||||
php-fpm -F -y ${./php-fpm.conf}
|
|
||||||
'')
|
|
||||||
];
|
|
||||||
|
|
||||||
extraCommands = ''
|
|
||||||
mkdir -p tmp
|
|
||||||
chmod 1777 tmp
|
|
||||||
ln -s ${demostf-api}/share/php/demostf-api app
|
|
||||||
'';
|
|
||||||
|
|
||||||
config = {
|
|
||||||
Cmd = [ "start-server" ];
|
|
||||||
Env = [
|
|
||||||
"PARSER_PATH=${demostf-parser}/bin/parse_demo"
|
|
||||||
];
|
|
||||||
ExposedPorts = {
|
|
||||||
"9000/tcp" = {};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
118
flake.lock
generated
118
flake.lock
generated
|
|
@ -1,132 +1,44 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"flake-parts": {
|
"flakelight": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": "nixpkgs-lib"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1701473968,
|
|
||||||
"narHash": "sha256-YcVE5emp1qQ8ieHUnxt1wCZCC3ZfAS+SRRWZ2TMda7E=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"rev": "34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flocken": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-parts": "flake-parts",
|
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
],
|
]
|
||||||
"systems": "systems"
|
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1704105102,
|
"lastModified": 1734957624,
|
||||||
"narHash": "sha256-c4VWO9plhINjQzYPHSKURWgQ2D2q24aI3OIN0MTPjz0=",
|
"narHash": "sha256-RbvX9lf9lWQwG9vTXkscOiWTrKf8lzjyeOvW/v8IuBY=",
|
||||||
"owner": "mirkolenz",
|
"owner": "nix-community",
|
||||||
"repo": "flocken",
|
"repo": "flakelight",
|
||||||
"rev": "3a846dfca17f989805d9f4177de85c96dc0f8542",
|
"rev": "8c226ea0166784b02d4a58fbb015f9c01250221e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "mirkolenz",
|
"owner": "nix-community",
|
||||||
"ref": "v2",
|
"repo": "flakelight",
|
||||||
"repo": "flocken",
|
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1710523508,
|
"lastModified": 1734875076,
|
||||||
"narHash": "sha256-cyaeYdWG+RQOFPn1DHgO/lerVI4dxHWwF4EJ0dYcu5g=",
|
"narHash": "sha256-Pzyb+YNG5u3zP79zoi8HXYMs15Q5dfjDgwCdUI5B0nY=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "a3b22bfd2906b8c028d115f2ab4a1cc4ac806a9d",
|
"rev": "1807c2b91223227ad5599d7067a61665c52d1295",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "nixpkgs",
|
"id": "nixpkgs",
|
||||||
"ref": "release-23.11",
|
"ref": "nixos-24.11",
|
||||||
"type": "indirect"
|
"type": "indirect"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-lib": {
|
|
||||||
"locked": {
|
|
||||||
"dir": "lib",
|
|
||||||
"lastModified": 1701253981,
|
|
||||||
"narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"dir": "lib",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flocken": "flocken",
|
"flakelight": "flakelight",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs"
|
||||||
"utils": "utils"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems_2"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1710146030,
|
|
||||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
87
flake.nix
87
flake.nix
|
|
@ -1,73 +1,30 @@
|
||||||
{
|
{
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "nixpkgs/release-23.11";
|
nixpkgs.url = "nixpkgs/nixos-24.11";
|
||||||
utils.url = "github:numtide/flake-utils";
|
flakelight = {
|
||||||
flocken = {
|
url = "github:nix-community/flakelight";
|
||||||
url = "github:mirkolenz/flocken/v2";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
outputs = {flakelight, ...}:
|
||||||
outputs = {
|
flakelight ./. {
|
||||||
self,
|
withOverlays = [(import ./nix/overlay.nix)];
|
||||||
nixpkgs,
|
packages = {
|
||||||
utils,
|
api = pkgs: pkgs.demostf-api;
|
||||||
flocken,
|
api-dev = pkgs: pkgs.demostf-api-dev;
|
||||||
}:
|
api-test = pkgs: pkgs.demostf-api-test;
|
||||||
utils.lib.eachDefaultSystem (system: let
|
};
|
||||||
inherit (builtins) getEnv;
|
checks = {
|
||||||
overlays = [
|
integration-tests = pkgs: pkgs.nixosTest (import ./nix/integration-tests.nix);
|
||||||
(import ./overlay.nix)
|
unit-tests = pkgs: pkgs.nixosTest (import ./nix/unit-tests.nix);
|
||||||
|
};
|
||||||
|
formatters = pkgs: {
|
||||||
|
"*.nix" = pkgs.lib.getExe pkgs.alejandra;
|
||||||
|
};
|
||||||
|
devShell.packages = pkgs: [
|
||||||
|
pkgs.demostf-api-php.packages.composer
|
||||||
|
pkgs.demostf-api-php
|
||||||
|
pkgs.nodejs
|
||||||
];
|
];
|
||||||
pkgs = import nixpkgs {
|
|
||||||
inherit system overlays;
|
|
||||||
};
|
|
||||||
npmLd = pkgs.writeShellScriptBin "npm" ''
|
|
||||||
PATH="$PATH ${pkgs.nodejs_20}/bin" LD=$CC ${pkgs.nodejs_20}/bin/npm $@
|
|
||||||
'';
|
|
||||||
nodeLd = pkgs.writeShellScriptBin "node" ''
|
|
||||||
LD=$CC ${pkgs.nodejs_20}/bin/node $@
|
|
||||||
'';
|
|
||||||
inherit (flocken.legacyPackages.${system}) mkDockerManifest;
|
|
||||||
|
|
||||||
phpVersion = "php82";
|
|
||||||
phpPackages = pkgs."${phpVersion}Packages";
|
|
||||||
phpPackage = pkgs.${phpVersion}.buildEnv {
|
|
||||||
extraConfig = "memory_limit = 2G";
|
|
||||||
extensions = ({ enabled, all }: enabled ++ (with all; [
|
|
||||||
xdebug smbclient
|
|
||||||
]));
|
|
||||||
};
|
|
||||||
in rec {
|
|
||||||
packages = rec {
|
|
||||||
inherit (pkgs) demostf-api demostf-api-docker demostf-parser;
|
|
||||||
docker = demostf-api-docker;
|
|
||||||
default = demostf-api;
|
|
||||||
|
|
||||||
dockerManifest = mkDockerManifest {
|
|
||||||
tags = ["latest"];
|
|
||||||
registries = {
|
|
||||||
"docker.io" = {
|
|
||||||
enable = true;
|
|
||||||
repo = "demostf/api";
|
|
||||||
username = "$DOCKERHUB_USERNAME";
|
|
||||||
password = "$DOCKERHUB_TOKEN";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
version = "1.0.0";
|
|
||||||
images = with self.packages; [x86_64-linux.demostf-api-docker aarch64-linux.demostf-api-docker];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
devShells.default = pkgs.mkShell {
|
|
||||||
nativeBuildInputs = with pkgs; [
|
|
||||||
gnumake
|
|
||||||
phpPackage
|
|
||||||
phpPackages.composer
|
|
||||||
npmLd
|
|
||||||
nodeLd
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}) // {
|
|
||||||
overlays.default = import ./overlay.nix;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
nix/api-test.nix
Normal file
26
nix/api-test.nix
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
rustPlatform,
|
||||||
|
fetchgit,
|
||||||
|
pkg-config,
|
||||||
|
openssl,
|
||||||
|
}:
|
||||||
|
rustPlatform.buildRustPackage {
|
||||||
|
pname = "demostf-api-test";
|
||||||
|
version = "0.1.4";
|
||||||
|
|
||||||
|
src = fetchgit {
|
||||||
|
url = "https://github.com/demostf/api-test";
|
||||||
|
rev = "b2a8446e9b12c84d2c9228e4babe5d34132d3298";
|
||||||
|
hash = "sha256-Zn6P4ukhoxqP+16ZkLBbqzM9DsTLmSNa4zrkhmyzy/I";
|
||||||
|
fetchLFS = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
buildInputs = [openssl];
|
||||||
|
|
||||||
|
nativeBuildInputs = [pkg-config];
|
||||||
|
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
cargoHash = "sha256-Irv6atngsh0hPJ256tMxer3nR0PjBcaOJLVldnPnwUs=";
|
||||||
|
meta.mainProgram = "api-test";
|
||||||
|
}
|
||||||
127
nix/integration-tests.nix
Normal file
127
nix/integration-tests.nix
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
name = "demostf-api-client-test";
|
||||||
|
nodes.machine = {config, ...}: let
|
||||||
|
fpmCfg = config.services.phpfpm.pools.demostf-api;
|
||||||
|
in {
|
||||||
|
config = {
|
||||||
|
environment.systemPackages = [pkgs.demostf-api-test];
|
||||||
|
|
||||||
|
users.groups.demostf = {};
|
||||||
|
users.users.demostf = {
|
||||||
|
group = "demostf";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = {
|
||||||
|
enable = true;
|
||||||
|
ensureDatabases = ["demostf"];
|
||||||
|
ensureUsers = [
|
||||||
|
{
|
||||||
|
name = "demostf";
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
initialScript = pkgs.writeText "init-sql-script" ''
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx = {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts."localhost" = {
|
||||||
|
root = "/var/empty";
|
||||||
|
extraConfig = ''
|
||||||
|
try_files $uri /index.php?$query_string /index.php;
|
||||||
|
'';
|
||||||
|
locations = {
|
||||||
|
"~ ^(.+?\\.php)(/.*)?$" = {
|
||||||
|
extraConfig = ''
|
||||||
|
fastcgi_param PATH_INFO $2;
|
||||||
|
fastcgi_pass unix:${fpmCfg.socket};
|
||||||
|
fastcgi_index index.php;
|
||||||
|
fastcgi_param SCRIPT_FILENAME ${pkgs.demostf-api}/share/php/demostf-api/src/public/index.php;
|
||||||
|
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||||
|
client_max_body_size 250m;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"= /upload" = {
|
||||||
|
extraConfig = ''
|
||||||
|
fastcgi_pass unix:${fpmCfg.socket};
|
||||||
|
fastcgi_index index.php;
|
||||||
|
fastcgi_param SCRIPT_FILENAME ${pkgs.demostf-api}/share/php/demostf-api/src/public/upload.php;
|
||||||
|
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||||
|
client_max_body_size 250m;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"/static/" = {
|
||||||
|
alias = "/demos/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.phpfpm.pools.demostf-api = {
|
||||||
|
phpPackage = pkgs.php.buildEnv {
|
||||||
|
extensions = {
|
||||||
|
enabled,
|
||||||
|
all,
|
||||||
|
}:
|
||||||
|
enabled ++ (with all; [pdo apcu]);
|
||||||
|
extraConfig = ''
|
||||||
|
post_max_size = 150M
|
||||||
|
upload_max_filesize = 150M
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
settings = {
|
||||||
|
"clear_env" = "no";
|
||||||
|
"pm" = "dynamic";
|
||||||
|
"pm.max_children" = "25";
|
||||||
|
"pm.start_servers" = "5";
|
||||||
|
"pm.min_spare_servers" = "5";
|
||||||
|
"pm.max_spare_servers" = "15";
|
||||||
|
"catch_workers_output" = "yes";
|
||||||
|
"listen.owner" = "nginx";
|
||||||
|
"listen.group" = "nginx";
|
||||||
|
};
|
||||||
|
phpEnv = {
|
||||||
|
BASE_HOST = "demos.tf";
|
||||||
|
DEMO_ROOT = "/demos";
|
||||||
|
DEMO_HOST = "localhost";
|
||||||
|
DB_TYPE = "pgsql";
|
||||||
|
DB_HOST = "/run/postgresql";
|
||||||
|
DB_PORT = "5432";
|
||||||
|
DB_DATABASE = "demostf";
|
||||||
|
DB_USERNAME = "demostf";
|
||||||
|
APP_ROOT = "http://localhost";
|
||||||
|
EDIT_SECRET = "edit";
|
||||||
|
PARSER_PATH = lib.getExe pkgs.demostf-parser;
|
||||||
|
};
|
||||||
|
user = "demostf";
|
||||||
|
group = "demostf";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = let
|
||||||
|
initSql = pkgs.fetchurl {
|
||||||
|
url = "https://github.com/demostf/db/raw/refs/heads/master/schema.sql";
|
||||||
|
hash = "sha256-AwXN9mh9CRk6HWdvyUR+YdBkpmExNIDOIeDMz6XqjEQ=";
|
||||||
|
};
|
||||||
|
in ''
|
||||||
|
machine.succeed("mkdir /demos && chmod 0777 /demos");
|
||||||
|
machine.wait_for_unit("postgresql")
|
||||||
|
machine.succeed("sudo -u demostf psql demostf demostf < ${initSql}");
|
||||||
|
machine.succeed("sudo -u postgres psql postgres postgres -c \"alter user demostf with password 'demostf';\"");
|
||||||
|
machine.wait_for_unit("phpfpm-demostf-api")
|
||||||
|
machine.wait_for_unit("nginx")
|
||||||
|
machine.wait_until_succeeds("curl http://127.0.0.1", timeout=45)
|
||||||
|
machine.succeed("DB_URL='postgres://demostf:demostf@localhost/demostf'\
|
||||||
|
BASE_URL='http://localhost/'\
|
||||||
|
EDIT_KEY='edit'\
|
||||||
|
api-test", timeout=180)
|
||||||
|
'';
|
||||||
|
}
|
||||||
18
nix/overlay.nix
Normal file
18
nix/overlay.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
final: prev: {
|
||||||
|
demostf-parser = final.callPackage ./parser.nix {};
|
||||||
|
demostf-api = final.callPackage ./package.nix {};
|
||||||
|
demostf-api-dev = final.callPackage ./package.nix {dev = true;};
|
||||||
|
demostf-api-test = final.callPackage ./api-test.nix {};
|
||||||
|
demostf-api-php = final.php82.buildEnv {
|
||||||
|
extraConfig = "memory_limit = 2G";
|
||||||
|
extensions = {
|
||||||
|
enabled,
|
||||||
|
all,
|
||||||
|
}:
|
||||||
|
enabled
|
||||||
|
++ (with all; [
|
||||||
|
pdo
|
||||||
|
apcu
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
}
|
||||||
24
nix/package.nix
Normal file
24
nix/package.nix
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
demostf-api-php,
|
||||||
|
dev ? false,
|
||||||
|
}: let
|
||||||
|
inherit (lib.sources) sourceByRegex;
|
||||||
|
in
|
||||||
|
demostf-api-php.buildComposerProject (finalAttrs: {
|
||||||
|
pname = "demostf-api";
|
||||||
|
version = "0.1.0";
|
||||||
|
|
||||||
|
composerNoDev = !dev;
|
||||||
|
|
||||||
|
src = sourceByRegex ../. ["composer.*" "(src|test)(/.*)?"];
|
||||||
|
|
||||||
|
vendorHash =
|
||||||
|
if dev
|
||||||
|
then "sha256-PBp2PHoKfM66BjWxbEt5suKlkUxDxXdxhhCVzfRbJdo="
|
||||||
|
else "sha256-EYWCR2aJAoyWvEX+SML4Fb3F3KGcUtwCgqhAGT6ZjZ4=";
|
||||||
|
|
||||||
|
composerStrictValidation = false;
|
||||||
|
|
||||||
|
doCheck = false;
|
||||||
|
})
|
||||||
24
nix/parser.nix
Normal file
24
nix/parser.nix
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
rustPlatform,
|
||||||
|
fetchFromGitHub,
|
||||||
|
}:
|
||||||
|
rustPlatform.buildRustPackage {
|
||||||
|
pname = "demostf-parser";
|
||||||
|
version = "0.5.1";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "demostf";
|
||||||
|
repo = "parser";
|
||||||
|
rev = "0cd87a8a40e2a6af637d831b272c2758cebd2f9c";
|
||||||
|
hash = "sha256-bKcc0hWTkdYUDMI/DjUh45abuBeQEvkn6TsuAz02H5Y=";
|
||||||
|
};
|
||||||
|
|
||||||
|
cargoBuildFlags = ''
|
||||||
|
--bin parse_demo
|
||||||
|
'';
|
||||||
|
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
cargoHash = "sha256-/Fnw6l2fznrBK780E4q1PKFOkT0eiL+dE+UuhFA+V9M=";
|
||||||
|
meta.mainProgram = "parse_demo";
|
||||||
|
}
|
||||||
53
nix/unit-tests.nix
Normal file
53
nix/unit-tests.nix
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
name = "demostf-api-unit-tests";
|
||||||
|
nodes.machine = {config, ...}: {
|
||||||
|
config = {
|
||||||
|
users.groups.demostf = {};
|
||||||
|
users.users.demostf = {
|
||||||
|
group = "demostf";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = {
|
||||||
|
enable = true;
|
||||||
|
ensureDatabases = ["demostf"];
|
||||||
|
ensureUsers = [
|
||||||
|
{
|
||||||
|
name = "demostf";
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
initialScript = pkgs.writeText "init-sql-script" ''
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = let
|
||||||
|
php = lib.getExe pkgs.demostf-api-php;
|
||||||
|
api = pkgs.demostf-api-dev;
|
||||||
|
initSql = pkgs.fetchurl {
|
||||||
|
url = "https://github.com/demostf/db/raw/refs/heads/master/schema.sql";
|
||||||
|
hash = "sha256-AwXN9mh9CRk6HWdvyUR+YdBkpmExNIDOIeDMz6XqjEQ=";
|
||||||
|
};
|
||||||
|
in ''
|
||||||
|
machine.succeed("mkdir /demos && chmod 0777 /demos");
|
||||||
|
machine.wait_for_unit("postgresql")
|
||||||
|
machine.succeed("sudo -u demostf psql demostf demostf < ${initSql}");
|
||||||
|
machine.succeed("sudo -u postgres psql postgres postgres -c \"alter user demostf with password 'demostf';\"");
|
||||||
|
machine.succeed("cd ${api}/share/php/demostf-api; DB_HOST='localhost'\
|
||||||
|
DB_TYPE='pgsql'\
|
||||||
|
DB_PORT='5432'\
|
||||||
|
DB_USERNAME='demostf'\
|
||||||
|
DB_PASSWORD='demostf'\
|
||||||
|
DB_DATABASE='demostf'\
|
||||||
|
BASE_URL='http://localhost/'\
|
||||||
|
EDIT_KEY='edit'\
|
||||||
|
${php} ./vendor/bin/phpunit test", timeout=180)
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
final: prev: {
|
|
||||||
demostf-parser = final.callPackage ./parser.nix {};
|
|
||||||
demostf-api = final.callPackage ./package.nix {};
|
|
||||||
demostf-api-docker = final.callPackage ./docker.nix {};
|
|
||||||
}
|
|
||||||
20
package.nix
20
package.nix
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
stdenv,
|
|
||||||
php,
|
|
||||||
lib,
|
|
||||||
}: let
|
|
||||||
inherit (lib.sources) sourceByRegex;
|
|
||||||
phpWithExtensions = php.withExtensions ({ enabled, all }: enabled ++ (with all; [pdo apcu]));
|
|
||||||
in
|
|
||||||
phpWithExtensions.buildComposerProject (finalAttrs: {
|
|
||||||
pname = "demostf-api";
|
|
||||||
version = "0.1.0";
|
|
||||||
|
|
||||||
src = sourceByRegex ./. ["composer.*" "(src|test)(/.*)?"];
|
|
||||||
|
|
||||||
vendorHash = "sha256-EYWCR2aJAoyWvEX+SML4Fb3F3KGcUtwCgqhAGT6ZjZ4=";
|
|
||||||
|
|
||||||
composerStrictValidation = false;
|
|
||||||
|
|
||||||
doCheck = false;
|
|
||||||
})
|
|
||||||
1624
parser-Cargo.lock
generated
1624
parser-Cargo.lock
generated
File diff suppressed because it is too large
Load diff
32
parser.nix
32
parser.nix
|
|
@ -1,32 +0,0 @@
|
||||||
{
|
|
||||||
stdenv,
|
|
||||||
rustPlatform,
|
|
||||||
fetchFromGitHub,
|
|
||||||
lib,
|
|
||||||
}: let
|
|
||||||
inherit (lib.sources) sourceByRegex;
|
|
||||||
in
|
|
||||||
rustPlatform.buildRustPackage rec {
|
|
||||||
pname = "demostf-parser";
|
|
||||||
version = "0.1.0";
|
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "demostf";
|
|
||||||
repo = "parser";
|
|
||||||
rev = "2449c9666019a99b791f84d3c0c38b6b7c71ad20";
|
|
||||||
hash = "sha256-V0rm9pVfZUGPrD3raOJ7O6EQkbxVG6cIquWvdFkGPgM=";
|
|
||||||
};
|
|
||||||
|
|
||||||
cargoBuildFlags = ''
|
|
||||||
--bin parse_demo
|
|
||||||
'';
|
|
||||||
|
|
||||||
doCheck = false;
|
|
||||||
|
|
||||||
cargoLock = {
|
|
||||||
lockFile = ./parser-Cargo.lock;
|
|
||||||
outputHashes = {
|
|
||||||
"schemars-0.8.16" = "sha256-mQR56Ym76gSRulZrThmZHHw2JfhEgYhWXabwaYmyMYs=";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -273,14 +273,8 @@ class UploadProviderTest extends TestCase {
|
||||||
$this->userProvider->store($steamId, $name);
|
$this->userProvider->store($steamId, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUpload() {
|
private function preloadNames() {
|
||||||
copy(__DIR__ . '/../data/product.dem', $this->tmpDir . '/foo.dem');
|
// pre-save the names so we don't have to get them from steam
|
||||||
copy(__DIR__ . '/../data/product-raw.json', $this->tmpDir . '/foo-raw.json');
|
|
||||||
|
|
||||||
$steamId = $this->getSteamId('123', 'a');
|
|
||||||
$token = $this->userProvider->store($steamId, 'a');
|
|
||||||
|
|
||||||
// pre-save the names so we dont have to get them from steam
|
|
||||||
$this->saveSteamId('[U:1:64229260]', 'Icewind');
|
$this->saveSteamId('[U:1:64229260]', 'Icewind');
|
||||||
$this->saveSteamId('[U:1:115748435]', 'Foz');
|
$this->saveSteamId('[U:1:115748435]', 'Foz');
|
||||||
$this->saveSteamId('[U:1:115754284]', 'Deity');
|
$this->saveSteamId('[U:1:115754284]', 'Deity');
|
||||||
|
|
@ -299,6 +293,26 @@ class UploadProviderTest extends TestCase {
|
||||||
$this->saveSteamId('[U:1:92096346]', 'Fish');
|
$this->saveSteamId('[U:1:92096346]', 'Fish');
|
||||||
$this->saveSteamId('[U:1:143626373]', 'Pendulum');
|
$this->saveSteamId('[U:1:143626373]', 'Pendulum');
|
||||||
$this->saveSteamId('[U:1:30220936]', 'Jedi');
|
$this->saveSteamId('[U:1:30220936]', 'Jedi');
|
||||||
|
$this->saveSteamId('[U:1:1104797071]', 'Katsu');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uploadProvider(): array {
|
||||||
|
return [
|
||||||
|
[__DIR__ . '/../data/product.dem', __DIR__ . '/../data/product-raw.json', 'koth_product_rc8', 0, 3],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider uploadProvider
|
||||||
|
*/
|
||||||
|
public function testUpload(string $demo, string $parsed, string $map, int $blue, int $red) {
|
||||||
|
copy($demo, $this->tmpDir . '/foo.dem');
|
||||||
|
copy($parsed, $this->tmpDir . '/foo-raw.json');
|
||||||
|
|
||||||
|
$steamId = $this->getSteamId('123', 'a');
|
||||||
|
$token = $this->userProvider->store($steamId, 'a');
|
||||||
|
|
||||||
|
$this->preloadNames();
|
||||||
|
|
||||||
$result = $this->uploadProvider->upload($token, 'RED', 'BLU', 'foodemo', $this->tmpDir . '/foo.dem');
|
$result = $this->uploadProvider->upload($token, 'RED', 'BLU', 'foodemo', $this->tmpDir . '/foo.dem');
|
||||||
$this->assertStringStartsWith('STV available at: http://example.com/', $result);
|
$this->assertStringStartsWith('STV available at: http://example.com/', $result);
|
||||||
|
|
@ -309,8 +323,8 @@ class UploadProviderTest extends TestCase {
|
||||||
|
|
||||||
$this->assertNotNull($demo);
|
$this->assertNotNull($demo);
|
||||||
|
|
||||||
$this->assertEquals('koth_product_rc8', $demo->getMap());
|
$this->assertEquals($map, $demo->getMap());
|
||||||
$this->assertEquals(0, $demo->getBlueScore());
|
$this->assertEquals($blue, $demo->getBlueScore());
|
||||||
$this->assertEquals(3, $demo->getRedScore());
|
$this->assertEquals($red, $demo->getRedScore());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue