Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f061e16bc | ||
|
|
b43bd5e37a | ||
|
|
522805c826 | ||
|
|
4ea17cbac2 | ||
|
|
3645c6cbc8 | ||
|
|
450537ea7e | ||
|
|
f1ab23ab14 | ||
|
|
ab7f532456 | ||
|
|
47586bcc7b | ||
|
|
393ce8bee1 | ||
|
|
1ef1429466 | ||
|
|
ba8265f820 | ||
|
|
6630aedc75 | ||
|
|
578c746771 |
No files matched your search
+10
-2
@@ -1,5 +1,13 @@
|
||||
node_modules
|
||||
dist/
|
||||
dist
|
||||
dist.tar.gz
|
||||
.git
|
||||
.gitignore
|
||||
.gitea
|
||||
.gitattributes
|
||||
.claude
|
||||
.wolf
|
||||
.superset
|
||||
docs
|
||||
*.md
|
||||
.DS_Store
|
||||
*.log
|
||||
@@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
||||
@@ -0,0 +1,119 @@
|
||||
name: CI
|
||||
|
||||
# Documentação e configuração de ferramenta não mudam nada que a suíte teste.
|
||||
# Na main não roda por push: o release.yml é quem a chama, e só quando a imagem
|
||||
# precisa ser reconstruída; rodar nos dois repetiria a mesma suíte no mesmo commit.
|
||||
# Sem gatilho de pull_request: o push da branch já valida o mesmo commit, e os
|
||||
# dois juntos rodariam tudo duas vezes (o repositório não recebe PR de fork).
|
||||
#
|
||||
# A imagem é construída aqui uma única vez, em arm64 (a arquitetura do servidor),
|
||||
# testada e publicada como inputs-<hash>. Ao fazer o merge, o release encontra
|
||||
# essa tag e só aplica os nomes novos, sem rodar nem construir nada de novo.
|
||||
on:
|
||||
push:
|
||||
branches-ignore: [main]
|
||||
paths-ignore: ['**.md', 'LICENSE', 'CITATION.cff', 'paper.md', 'references.bib', 'docs/**', '.claude/**', '.wolf/**', '.superset/**', 'scripts/release-notes.sh']
|
||||
schedule:
|
||||
- cron: '0 9 * * 1' # toda segunda: reavalia com a base de vulnerabilidades nova
|
||||
workflow_call:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ gitea.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
verificar:
|
||||
name: Tipos e testes
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: npm
|
||||
|
||||
- run: npm ci
|
||||
|
||||
# tsc -b é o mesmo que o build faz antes do Vite; aqui falha antes de gastar a imagem.
|
||||
- run: npx tsc -b
|
||||
- run: npm test
|
||||
|
||||
# Trivy roda pela imagem oficial: o trivy-action clona o repositório do Trivy
|
||||
# do mesmo servidor do workflow, que aqui é o Gitea, e não o GitHub.
|
||||
# O workspace do job é um volume que o daemon não enxerga, então os arquivos
|
||||
# entram no container com `docker cp` em vez de `-v`.
|
||||
seguranca:
|
||||
name: Trivy (dependências e segredos)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Repositório
|
||||
run: |
|
||||
cid=$(docker create --network host -v trivy-cache:/root/.cache/ -w /src aquasec/trivy:0.70.0 \
|
||||
fs --scanners vuln,secret,misconfig --severity HIGH,CRITICAL --exit-code 1 .)
|
||||
docker cp . "$cid:/src"
|
||||
docker start -a "$cid"
|
||||
status=$(docker inspect -f '{{.State.ExitCode}}' "$cid")
|
||||
docker rm "$cid" >/dev/null
|
||||
exit "$status"
|
||||
|
||||
# Só começa depois das verificações baratas: um teste quebrado não gasta um
|
||||
# build de imagem. Roda no runner arm64, o mesmo tipo do servidor, então o
|
||||
# que é escaneado e testado é a imagem que vai ao ar.
|
||||
imagem:
|
||||
name: Imagem Docker (linux/arm64)
|
||||
needs: [verificar, seguranca]
|
||||
runs-on: ubuntu-24.04-arm
|
||||
env:
|
||||
REGISTRY: git.lucasrguerra.dev.br
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Conteúdo já publicado (re-push, tag num commit já validado): nada a fazer.
|
||||
- id: plano
|
||||
run: scripts/plano-imagem.sh "$REGISTRY" "${{ gitea.repository }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# `docker build` simples, no daemon persistente do runner: as camadas e o
|
||||
# cache mount do npm sobrevivem entre execuções. Um buildx criaria um
|
||||
# BuildKit novo, e vazio, a cada job.
|
||||
- name: Build
|
||||
if: ${{ steps.plano.outputs.reuse != 'true' }}
|
||||
run: docker build -t pss:ci .
|
||||
|
||||
- name: Trivy na imagem
|
||||
if: ${{ steps.plano.outputs.reuse != 'true' }}
|
||||
run: |
|
||||
docker run --rm --network host -v trivy-cache:/root/.cache/ -e DOCKER_HOST=tcp://127.0.0.1:2375 aquasec/trivy:0.70.0 \
|
||||
image --severity HIGH,CRITICAL --exit-code 1 pss:ci
|
||||
|
||||
# A SPA sobe, cai no index nas rotas internas e entrega os assets com
|
||||
# cache imutável (scripts/smoke-imagem.sh).
|
||||
- name: A imagem sobe e responde
|
||||
if: ${{ steps.plano.outputs.reuse != 'true' }}
|
||||
run: |
|
||||
docker run -d --name pss-ci -p 127.0.0.1:3998:8080 pss:ci
|
||||
status=0
|
||||
scripts/smoke-imagem.sh http://127.0.0.1:3998 || status=1
|
||||
docker rm -f pss-ci >/dev/null
|
||||
exit "$status"
|
||||
|
||||
# O login fica por último: build, Trivy e smoke não precisam de credencial.
|
||||
- if: ${{ steps.plano.outputs.reuse != 'true' }}
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ gitea.actor }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
# Passou em tudo: publica a mesma imagem que foi testada, sem reconstruir.
|
||||
- name: Publica inputs-<hash>
|
||||
if: ${{ steps.plano.outputs.reuse != 'true' }}
|
||||
run: |
|
||||
tag="${{ steps.plano.outputs.image }}:inputs-${{ steps.plano.outputs.inputs }}"
|
||||
docker tag pss:ci "$tag"
|
||||
docker push "$tag"
|
||||
@@ -0,0 +1,129 @@
|
||||
name: Release
|
||||
|
||||
# Publica a imagem no registro de containers do Gitea depois de um merge em main,
|
||||
# e de novo com tag semver quando uma tag v* é enviada. O servidor só faz pull.
|
||||
# Precisa do secret REGISTRY_TOKEN no repositório (token do Gitea com write:package):
|
||||
# o registro recusa o token do job.
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags: ['v*']
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: release
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
REGISTRY: git.lucasrguerra.dev.br
|
||||
|
||||
jobs:
|
||||
# A imagem só depende dos arquivos que entram no build, não da documentação nem
|
||||
# da configuração de ferramentas. O push da branch já a construiu, testou e
|
||||
# publicou como inputs-<hash>; quando essa tag existe (o caso normal de um
|
||||
# merge, uma tag num commit validado, um merge só de docs), não há o que
|
||||
# construir: as tags novas apontam para o manifesto existente.
|
||||
plano:
|
||||
name: Plano (reaproveitar a imagem?)
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
inputs: ${{ steps.plano.outputs.inputs }}
|
||||
reuse: ${{ steps.plano.outputs.reuse }}
|
||||
image: ${{ steps.plano.outputs.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- id: plano
|
||||
run: scripts/plano-imagem.sh "$REGISTRY" "${{ gitea.repository }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Nada é publicado sem a suíte completa passar antes. Pulada quando a imagem é
|
||||
# reaproveitada: o mesmo conteúdo já passou por ela.
|
||||
ci:
|
||||
needs: plano
|
||||
if: ${{ needs.plano.outputs.reuse != 'true' }}
|
||||
uses: ./.gitea/workflows/ci.yml
|
||||
# Workflows reutilizáveis não herdam os secrets sozinhos: o login no registro precisa deles.
|
||||
secrets: inherit
|
||||
|
||||
publicar:
|
||||
name: Publica a imagem (linux/arm64)
|
||||
needs: [plano, ci]
|
||||
# ci é pulado, e não bem-sucedido, quando a imagem é reaproveitada.
|
||||
if: ${{ !cancelled() && needs.plano.result == 'success' && (needs.ci.result == 'success' || needs.plano.outputs.reuse == 'true') }}
|
||||
# O único runner é arm64 e o servidor de destino (Oracle) também, então a
|
||||
# imagem é construída nativamente, sem emulação.
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Se o ci chamado acima acabou de publicar a imagem (push direto na main),
|
||||
# o plano lá de cima está desatualizado: confere de novo antes de construir.
|
||||
- id: replano
|
||||
run: scripts/plano-imagem.sh "$REGISTRY" "${{ gitea.repository }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Autentica no registro
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ gitea.actor }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- name: Metadados
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ${{ needs.plano.outputs.image }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=raw,value=latest
|
||||
type=sha,format=long
|
||||
|
||||
- name: Build e push
|
||||
if: ${{ steps.replano.outputs.reuse != 'true' }}
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ steps.meta.outputs.tags }}
|
||||
${{ needs.plano.outputs.image }}:inputs-${{ needs.plano.outputs.inputs }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=registry,ref=${{ needs.plano.outputs.image }}:buildcache
|
||||
cache-to: type=registry,ref=${{ needs.plano.outputs.image }}:buildcache,mode=max
|
||||
|
||||
# Mesmo manifesto, nomes novos: nenhuma camada é lida nem escrita.
|
||||
- name: Aplica as tags à imagem existente
|
||||
if: ${{ steps.replano.outputs.reuse == 'true' }}
|
||||
run: |
|
||||
tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}')
|
||||
docker buildx imagetools create $tags "${{ needs.plano.outputs.image }}:inputs-${{ needs.plano.outputs.inputs }}"
|
||||
|
||||
# Cria a entrada em "Releases" quando a execução é de uma tag v*. Roda depois
|
||||
# de publicar a imagem, com as notas da seção do CHANGELOG.md.
|
||||
release:
|
||||
name: Cria a release no Gitea
|
||||
needs: [plano, publicar]
|
||||
# Explícito, como o publicar: o ci acima é pulado quando a imagem é
|
||||
# reaproveitada, e o success() implícito pularia este job também.
|
||||
if: ${{ !cancelled() && needs.publicar.result == 'success' && startsWith(gitea.ref, 'refs/tags/v') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Release
|
||||
env:
|
||||
TAG: ${{ gitea.ref_name }}
|
||||
TOKEN: ${{ gitea.token }}
|
||||
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
|
||||
IMAGE: ${{ needs.plano.outputs.image }}
|
||||
run: |
|
||||
scripts/release-notes.sh "$TAG" "$IMAGE" > notes.md
|
||||
pre=false; case "$TAG" in *-*) pre=true ;; esac
|
||||
jq -n --arg tag "$TAG" --arg name "PSS ${TAG#v}" --rawfile body notes.md --argjson pre "$pre" \
|
||||
'{tag_name:$tag, name:$name, body:$body, prerelease:$pre}' > release.json
|
||||
curl -fsS -X POST "$API/releases" -H "Authorization: token $TOKEN" \
|
||||
-H 'Content-Type: application/json' -d @release.json
|
||||
+8
-17
@@ -1,19 +1,10 @@
|
||||
!**/glob-import/dir/node_modules
|
||||
.DS_Store
|
||||
.idea
|
||||
.pnpm-store
|
||||
*.cpuprofile
|
||||
*.local
|
||||
*.log
|
||||
/.vscode/
|
||||
/docs/.vitepress/cache
|
||||
/docs/.vitepress/.temp
|
||||
/packages/vite/LICENSE
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
explorations
|
||||
node_modules
|
||||
playground-temp
|
||||
temp
|
||||
TODOs.md
|
||||
.eslintcache
|
||||
dist.tar.gz
|
||||
*.local
|
||||
*.log
|
||||
.DS_Store
|
||||
.idea
|
||||
/.vscode/
|
||||
.eslintcache
|
||||
@@ -0,0 +1,79 @@
|
||||
# Changelog
|
||||
|
||||
Everything notable in PSS is recorded here. The format follows
|
||||
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project follows
|
||||
[Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.3.3] - 2026-11-01
|
||||
|
||||
### Changed
|
||||
|
||||
- The code, the container image and the releases now live on Gitea
|
||||
(`git.lucasrguerra.dev.br`). The deployment pulls the image from its registry.
|
||||
- The `Dockerfile` is multi-stage: it builds Vite from source inside the image instead
|
||||
of unpacking a `dist.tar.gz` committed to the repository (removed, along with the
|
||||
`build:release` script). The final stage is `nginx-unprivileged`: the container runs
|
||||
as the `nginx` user and listens on port 8080 instead of 80 (Trivy DS-0002).
|
||||
- New CI on Gitea runners (`.gitea/workflows`): types, 282 tests, Trivy on the repository
|
||||
and on the image, and an image smoke test. The image is built once per content hash and
|
||||
reused by the release, so a merge or a tag on an already validated commit rebuilds nothing.
|
||||
- Repository links in `package.json`, `CITATION.cff`, the READMEs and `CONTRIBUTING.md`
|
||||
point to Gitea. `.gitattributes` forces LF line endings.
|
||||
|
||||
### Fixed
|
||||
|
||||
- `docker-compose.yml` healthcheck uses `CMD-SHELL` and the correct local URL, and the
|
||||
port mapping honours `PORT`.
|
||||
|
||||
## [1.3.2] - 2026-03-25
|
||||
|
||||
### Added
|
||||
|
||||
- Regression tests for Round Robin scheduling with threads.
|
||||
|
||||
## [1.3.1] - 2026-03-25
|
||||
|
||||
### Added
|
||||
|
||||
- `ThreadMetricsChart` and per-thread metrics.
|
||||
|
||||
### Changed
|
||||
|
||||
- Improvements to the Gantt chart and the metrics panel.
|
||||
|
||||
## [1.3.0] - 2026-03-24
|
||||
|
||||
### Added
|
||||
|
||||
- Multilevel Feedback Queue (MLFQ) scheduling algorithm.
|
||||
- Thread scheduler.
|
||||
|
||||
## [1.2.0] - 2026-03-23
|
||||
|
||||
### Added
|
||||
|
||||
- English documentation, a `CONTRIBUTING.md`, the JOSS paper and a Zenodo DOI in
|
||||
`CITATION.cff`.
|
||||
- Multilevel Queue (MLQ) scheduling algorithm and its documentation.
|
||||
|
||||
### Changed
|
||||
|
||||
- License switched to MIT.
|
||||
- Scheduling algorithms refactored into a class-based `BaseAlgorithm` structure, with
|
||||
the engine and tests updated and new algorithm and metrics documentation.
|
||||
|
||||
## [1.0.0] - 2026-03-23
|
||||
|
||||
### Added
|
||||
|
||||
- First release of the browser-based CPU scheduling simulator: core scheduling engine,
|
||||
algorithms (including Priority Round Robin), Gantt chart with context-switch handling,
|
||||
UI components and Docker setup.
|
||||
|
||||
[Unreleased]: https://git.lucasrguerra.dev.br/lucasrguerra/pss/compare/v1.3.3...HEAD
|
||||
[1.3.3]: https://git.lucasrguerra.dev.br/lucasrguerra/pss/compare/v1.3.2...v1.3.3
|
||||
[1.3.2]: https://git.lucasrguerra.dev.br/lucasrguerra/pss/compare/v1.2.0...v1.3.2
|
||||
[1.2.0]: https://git.lucasrguerra.dev.br/lucasrguerra/pss/compare/v1.0.0...v1.2.0
|
||||
[1.0.0]: https://git.lucasrguerra.dev.br/lucasrguerra/pss/releases/tag/v1.0.0
|
||||
+1
-1
@@ -6,7 +6,7 @@ version: 1.2.0
|
||||
date-released: "2026-03-23"
|
||||
license: MIT
|
||||
url: "https://pss.lucasrguerra.dev.br"
|
||||
repository-code: "https://github.com/lucasrguerra/pss"
|
||||
repository-code: "https://git.lucasrguerra.dev.br/lucasrguerra/pss"
|
||||
doi: "10.5281/zenodo.19197235"
|
||||
identifiers:
|
||||
- type: doi
|
||||
|
||||
+4
-4
@@ -10,7 +10,7 @@ This document provides guidelines and instructions for contributing to this proj
|
||||
|
||||
This section guides you through submitting a bug report for PSS. Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports.
|
||||
|
||||
If you find a bug, please create an issue on GitHub and include:
|
||||
If you find a bug, please create an issue on Gitea and include:
|
||||
- A clear and descriptive title.
|
||||
- Exact steps to reproduce the problem.
|
||||
- What you expected to happen, and what actually happened.
|
||||
@@ -37,10 +37,10 @@ To contribute code, you'll need to set up the project locally.
|
||||
|
||||
#### Installation Steps
|
||||
|
||||
1. **Fork the repository** on GitHub.
|
||||
1. **Fork the repository** on Gitea.
|
||||
2. **Clone your fork** locally:
|
||||
```bash
|
||||
git clone https://github.com/YOUR_USERNAME/pss.git
|
||||
git clone https://git.lucasrguerra.dev.br/YOUR_USERNAME/pss.git
|
||||
cd pss
|
||||
```
|
||||
3. **Install dependencies**:
|
||||
@@ -78,7 +78,7 @@ If you add a new feature, please include appropriate tests covering the new func
|
||||
```bash
|
||||
git commit -m "feat: add awesome new feature"
|
||||
```
|
||||
4. Push your branch to your fork on GitHub:
|
||||
4. Push your branch to your fork on Gitea:
|
||||
```bash
|
||||
git push origin feature/my-awesome-feature
|
||||
```
|
||||
|
||||
+19
-8
@@ -1,13 +1,24 @@
|
||||
# ── Production image ──
|
||||
FROM nginx:alpine
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# ── Build: compila o Vite a partir do código, sem artefato pré-construído ──
|
||||
FROM node:22-alpine AS build
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json ./
|
||||
RUN --mount=type=cache,target=/root/.npm npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# ── Imagem final: nginx sem privilégios (usuário nginx, porta 8080) e os estáticos ──
|
||||
FROM nginxinc/nginx-unprivileged:alpine
|
||||
# Aplica as correções de segurança do Alpine publicadas depois da imagem base.
|
||||
USER root
|
||||
RUN apk upgrade --no-cache
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
|
||||
# Unpack pre-built Vite output
|
||||
COPY dist.tar.gz /usr/share/nginx/html/
|
||||
RUN tar -xzf /usr/share/nginx/html/dist.tar.gz --strip-components=1 -C /usr/share/nginx/html \
|
||||
&& rm /usr/share/nginx/html/dist.tar.gz
|
||||
|
||||
EXPOSE 80
|
||||
USER nginx
|
||||
EXPOSE 8080
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
|
||||
CMD wget -q --spider http://127.0.0.1:8080/ || exit 1
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
+30
-3
@@ -35,7 +35,7 @@ A live demo is available at: **https://pss.lucasrguerra.dev.br/**
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/lucasrguerra/pss.git
|
||||
git clone https://git.lucasrguerra.dev.br/lucasrguerra/pss.git
|
||||
cd pss
|
||||
|
||||
# Install dependencies
|
||||
@@ -57,9 +57,36 @@ npm run preview
|
||||
### With Docker
|
||||
|
||||
```bash
|
||||
docker compose up
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
The `Dockerfile` builds Vite inside the image (Node 22) and serves the static files
|
||||
with an unprivileged nginx (`nginx` user, port 8080). There is no pre-built artifact in the repository.
|
||||
|
||||
### Published image
|
||||
|
||||
Every version is published to the Gitea container registry (linux/arm64):
|
||||
|
||||
```bash
|
||||
docker run -p 8080:8080 git.lucasrguerra.dev.br/lucasrguerra/pss:latest
|
||||
```
|
||||
|
||||
Tags: `latest`, `X.Y.Z`, `X.Y` and `sha-<commit>`. The public instance runs at
|
||||
[pss.lucasrguerra.dev.br](https://pss.lucasrguerra.dev.br).
|
||||
|
||||
### Continuous integration and releases
|
||||
|
||||
- `.gitea/workflows/ci.yml`: types (`tsc -b`), tests, Trivy (dependencies and secrets),
|
||||
image build, Trivy on the image and a smoke test (the SPA responds, falls back to the
|
||||
index on internal routes and serves assets with immutable caching). Runs on branches
|
||||
and every Monday.
|
||||
- `.gitea/workflows/release.yml`: on `main` and `vX.Y.Z` tags. If the registry already
|
||||
has the image for the same content (`inputs-<hash>`), nothing is rebuilt: only the new
|
||||
tags are applied. On a tag, it creates the Gitea release with the [CHANGELOG](CHANGELOG.md) notes.
|
||||
- To release: update the CHANGELOG, the version in `package.json` and the label in
|
||||
`src/components/Layout/Sidebar.tsx`, commit, and push the tag
|
||||
(`git tag vX.Y.Z && git push gitea vX.Y.Z`).
|
||||
|
||||
---
|
||||
|
||||
## 🎮 How to use
|
||||
@@ -229,4 +256,4 @@ Contributions are welcome! Please read our [CONTRIBUTING.md](./CONTRIBUTING.md)
|
||||
|
||||
## 📜 License
|
||||
|
||||
Distributed under the [MIT License](./LICENSE). Developed by [Lucas Rayan Guerra](https://github.com/lucasrguerra).
|
||||
Distributed under the [MIT License](./LICENSE). Developed by [Lucas Rayan Guerra](https://git.lucasrguerra.dev.br/lucasrguerra).
|
||||
@@ -33,7 +33,7 @@ Ideal para:
|
||||
|
||||
```bash
|
||||
# Clone o repositório
|
||||
git clone https://github.com/lucasrguerra/pss.git
|
||||
git clone https://git.lucasrguerra.dev.br/lucasrguerra/pss.git
|
||||
cd pss
|
||||
|
||||
# Instale as dependências
|
||||
@@ -55,9 +55,36 @@ npm run preview
|
||||
### Com Docker
|
||||
|
||||
```bash
|
||||
docker compose up
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
O `Dockerfile` compila o Vite dentro da própria imagem (Node 22) e entrega os
|
||||
arquivos estáticos por um nginx sem privilégios (usuário `nginx`, porta 8080). Não há artefato pré-construído no repositório.
|
||||
|
||||
### Imagem publicada
|
||||
|
||||
Cada versão é publicada no registro de contêineres do Gitea (linux/arm64):
|
||||
|
||||
```bash
|
||||
docker run -p 8080:8080 git.lucasrguerra.dev.br/lucasrguerra/pss:latest
|
||||
```
|
||||
|
||||
Tags: `latest`, `X.Y.Z`, `X.Y` e `sha-<commit>`. A instância pública roda em
|
||||
[pss.lucasrguerra.dev.br](https://pss.lucasrguerra.dev.br).
|
||||
|
||||
### Integração contínua e releases
|
||||
|
||||
- `.gitea/workflows/ci.yml`: tipos (`tsc -b`), testes, Trivy (dependências e segredos),
|
||||
build da imagem, Trivy na imagem e um teste de fumaça (a SPA responde, cai no index
|
||||
nas rotas internas e entrega os assets com cache imutável). Roda nas branches e toda
|
||||
segunda-feira.
|
||||
- `.gitea/workflows/release.yml`: na `main` e nas tags `vX.Y.Z`. Se o registro já tem a
|
||||
imagem do mesmo conteúdo (`inputs-<hash>`), nada é refeito: só as tags novas são
|
||||
aplicadas. Numa tag, cria a release no Gitea com as notas do [CHANGELOG](CHANGELOG.md).
|
||||
- Para lançar: atualize o CHANGELOG, a versão em `package.json` e o rótulo em
|
||||
`src/components/Layout/Sidebar.tsx`, faça o commit e envie a tag
|
||||
(`git tag vX.Y.Z && git push gitea vX.Y.Z`).
|
||||
|
||||
---
|
||||
|
||||
## 🎮 Como usar
|
||||
@@ -227,4 +254,4 @@ Contribuições são bem-vindas! Por favor, consulte nosso guia em [CONTRIBUTING
|
||||
|
||||
## 📜 Licença
|
||||
|
||||
Distribuído sob a [Licença MIT](./LICENSE). Desenvolvido por [Lucas Rayan Guerra](https://github.com/lucasrguerra).
|
||||
Distribuído sob a [Licença MIT](./LICENSE). Desenvolvido por [Lucas Rayan Guerra](https://git.lucasrguerra.dev.br/lucasrguerra).
|
||||
BIN
Binary file not shown.
+7
-1
@@ -2,5 +2,11 @@ services:
|
||||
pss:
|
||||
build: .
|
||||
ports:
|
||||
- "${PORT:-3000}:80"
|
||||
- "${PORT:-3000}:8080"
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:8080/ || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen 8080;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pss",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pss",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"clsx": "^2.1.1",
|
||||
|
||||
+4
-5
@@ -1,12 +1,11 @@
|
||||
{
|
||||
"name": "pss",
|
||||
"version": "1.3.2",
|
||||
"version": "1.3.3",
|
||||
"description": "Process Scheduler Simulator — an interactive educational tool that runs entirely in the browser",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"build:release": "tsc -b && vite build && tar --dereference -czf dist.tar.gz dist",
|
||||
"preview": "vite preview",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
@@ -39,14 +38,14 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/lucasrguerra/pss.git"
|
||||
"url": "git+https://git.lucasrguerra.dev.br/lucasrguerra/pss.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Lucas Rayan Guerra",
|
||||
"license": "MIT",
|
||||
"type": "commonjs",
|
||||
"bugs": {
|
||||
"url": "https://github.com/lucasrguerra/pss/issues"
|
||||
"url": "https://git.lucasrguerra.dev.br/lucasrguerra/pss/issues"
|
||||
},
|
||||
"homepage": "https://github.com/lucasrguerra/pss#readme"
|
||||
"homepage": "https://git.lucasrguerra.dev.br/lucasrguerra/pss#readme"
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
# Uso: scripts/plano-imagem.sh <registro> <repositório>
|
||||
# Imprime inputs=, image= e reuse= (para $GITHUB_OUTPUT). O hash cobre só os
|
||||
# arquivos que entram no build da imagem, não a documentação nem a configuração
|
||||
# de ferramentas. reuse=true quando o registro já tem inputs-<hash>.
|
||||
set -euo pipefail
|
||||
registry=$1; ns=${2,,}
|
||||
|
||||
inputs=$(git ls-tree -r HEAD \
|
||||
| awk -F'\t' '$2 !~ /^(\.gitea|\.github|\.claude|\.wolf|\.superset|docs)\// && $2 !~ /^(README.*|CONTRIBUTING\.md|CHANGELOG\.md|CITATION\.cff|LICENSE|paper\.md|references\.bib|\.gitignore|\.gitattributes|scripts\/release-notes\.sh)$/' \
|
||||
| sha256sum | cut -c1-16)
|
||||
token=$(curl -fsS "https://$registry/v2/token?service=container_registry&scope=repository:$ns:pull" | jq -r .token)
|
||||
code=$(curl -s -o /dev/null -w '%{http_code}' -I \
|
||||
-H "Authorization: Bearer $token" \
|
||||
-H 'Accept: application/vnd.oci.image.index.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.oci.image.manifest.v1+json' \
|
||||
"https://$registry/v2/$ns/manifests/inputs-$inputs")
|
||||
echo "inputs-$inputs -> HTTP $code" >&2
|
||||
reuse=false; [ "$code" = 200 ] && reuse=true
|
||||
echo "inputs=$inputs"
|
||||
echo "image=$registry/$ns"
|
||||
echo "reuse=$reuse"
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
# Imprime as notas de uma release: a imagem publicada (quando houver) e a seção
|
||||
# do CHANGELOG.md daquela versão (ou o log de commits desde a tag anterior, se
|
||||
# não houver seção).
|
||||
#
|
||||
# scripts/release-notes.sh v1.2.3 [git.exemplo.com/dono/projeto]
|
||||
set -euo pipefail
|
||||
|
||||
tag=${1:?uso: release-notes.sh <tag> [imagem]}
|
||||
image=${2:-}
|
||||
version=${tag#v}
|
||||
|
||||
if [ -n "$image" ]; then
|
||||
echo "## Imagem"
|
||||
echo
|
||||
echo '```'
|
||||
echo "$image:$version"
|
||||
echo '```'
|
||||
echo
|
||||
fi
|
||||
|
||||
section=""
|
||||
if [ -f CHANGELOG.md ]; then
|
||||
section=$(awk -v head="## [$version]" '
|
||||
index($0, head) == 1 { found = 1; next }
|
||||
found && /^## \[/ { exit }
|
||||
found && /^\[[^]]+\]: / { next }
|
||||
found { print }
|
||||
' CHANGELOG.md)
|
||||
fi
|
||||
|
||||
if [ -n "$(printf '%s' "$section" | tr -d '[:space:]')" ]; then
|
||||
printf '%s\n' "$section"
|
||||
else
|
||||
previous=$(git describe --tags --abbrev=0 "$tag^" 2>/dev/null || true)
|
||||
echo "## Mudanças${previous:+ desde $previous}"
|
||||
echo
|
||||
git log --no-merges --format='- %s (%h)' "${previous:+$previous..}$tag"
|
||||
fi
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
# Teste de fumaça da imagem: a SPA serve o index, cai no index em rotas internas
|
||||
# e entrega os assets com cache longo.
|
||||
#
|
||||
# scripts/smoke-imagem.sh http://127.0.0.1:3998
|
||||
#
|
||||
# Cada falha é impressa e o script sai com 1 no fim, para mostrar tudo de uma vez.
|
||||
set -uo pipefail
|
||||
|
||||
base=${1:?uso: smoke-imagem.sh <url-base>}
|
||||
falhas=0
|
||||
falhou() { echo "FALHOU $1"; falhas=$((falhas + 1)); }
|
||||
|
||||
# O nginx leva um instante para subir.
|
||||
for _ in $(seq 1 30); do curl -fsS -o /dev/null "$base/" 2>/dev/null && break; sleep 1; done
|
||||
|
||||
index=$(curl -fsS "$base/") || { echo "FALHOU /: sem resposta"; exit 1; }
|
||||
grep -q 'id="root"' <<< "$index" || falhou "/: o index não tem o #root"
|
||||
|
||||
# Rota interna da SPA devolve o mesmo index (try_files), não 404.
|
||||
[ "$(curl -s -o /dev/null -w '%{http_code}' "$base/qualquer/rota")" = 200 ] || falhou "/qualquer/rota: esperado 200"
|
||||
|
||||
# Todo asset que o index referencia existe e tem cache imutável.
|
||||
assets=$(grep -oE '(src|href)="/assets/[^"]+"' <<< "$index" | cut -d'"' -f2)
|
||||
[ -n "$assets" ] || falhou "o index não referencia nenhum /assets/"
|
||||
for a in $assets; do
|
||||
head=$(curl -sI "$base$a")
|
||||
grep -q '^HTTP/[0-9.]* 200' <<< "$head" || falhou "$a: esperado 200"
|
||||
grep -qi 'cache-control:.*immutable' <<< "$head" || falhou "$a: sem cache imutável"
|
||||
done
|
||||
|
||||
[ "$falhas" = 0 ] && echo "ok: $(wc -w <<< "$assets") assets e rotas conferidos"
|
||||
[ "$falhas" = 0 ]
|
||||
@@ -12,7 +12,7 @@ const Sidebar = () => {
|
||||
</div>
|
||||
|
||||
<div className="h-12 border-t border-slate-700 flex items-center justify-center text-xs text-slate-500">
|
||||
PSS v1.3.2
|
||||
PSS v1.3.3
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user