Compare commits
11 Commits
2218581e78
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| dffc480eb9 | |||
| 2358b9fe43 | |||
| 0818f634dc | |||
| ec2f2dbd57 | |||
| 85a67867c9 | |||
| 25d4668661 | |||
| 62f7ec5a7c | |||
| 2d80a9dff1 | |||
| 3f0a7d352d | |||
| 3165432811 | |||
| fd22751e72 |
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
22
.github/copilot-instructions.md
vendored
22
.github/copilot-instructions.md
vendored
@@ -1,22 +0,0 @@
|
|||||||
---
|
|
||||||
description: Instructions for using the JMESPath Testing Tool repository.
|
|
||||||
applyTo: "**/*.md,**/.js"
|
|
||||||
---
|
|
||||||
# AI Agent Instructions for JMESPath Testing Tool
|
|
||||||
|
|
||||||
This repository contains a React-based web application that allows users to test JMESPath expressions against JSON data. The application includes both a frontend and a backend server.
|
|
||||||
|
|
||||||
Coding Guidelines:
|
|
||||||
|
|
||||||
1. Use React, Vite and JavaScript/TypeScript for development.
|
|
||||||
2. Check the current date to establish context for choosing versions and dependencies.
|
|
||||||
3. Use Node.js 24 or higher LTS version.
|
|
||||||
4. When asked, answer the question and provide explanations. Do not guess nor infer missing information. Report lack of information instead.
|
|
||||||
5. When requested to make changes, do not modify unrelated parts of the code nor apply unapproved changes. Always present a change plan first, wait for approval, then implement the changes.
|
|
||||||
6. Do not try to manage the files directly. Instead always use Git mv, rm, etc. commands to ensure proper tracking.
|
|
||||||
7. Do not run the development server(s) unless explicitly instructed to do so. Report the need to run the server for testing purposes and wait for approval.
|
|
||||||
8. When working with MUI components, use the latest stable version and leverage the tools from the MCP server (`mui-mcp`).
|
|
||||||
9. Do not hardcode color values. Use MUI theme palette colors instead.
|
|
||||||
10. Do not use emojis in code comments, program output, or log messages.
|
|
||||||
11. Suggest code commits, but never create them without consent.
|
|
||||||
12. Never push changes.
|
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -31,4 +31,7 @@ yarn-error.log*
|
|||||||
|
|
||||||
# OS
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
|
# Don't store AGENTS.md in git
|
||||||
|
AGENTS.md
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ ARG IS_RELEASE="false"
|
|||||||
# Set working directory
|
# Set working directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install git for version generation
|
||||||
|
RUN apk add --no-cache git
|
||||||
|
|
||||||
# Copy package files
|
# Copy package files
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
@@ -53,4 +56,4 @@ ENV LISTEN_ADDR=0.0.0.0
|
|||||||
ENV LISTEN_PORT=3000
|
ENV LISTEN_PORT=3000
|
||||||
|
|
||||||
# Start the integrated server
|
# Start the integrated server
|
||||||
ENTRYPOINT ["./entrypoint.sh"]
|
ENTRYPOINT ["./entrypoint.sh"]
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ container run -p 3000:3000 jmespath-playground
|
|||||||
|
|
||||||
1. **Enter a JMESPath expression** in the top input field (e.g., `people[*].name`)
|
1. **Enter a JMESPath expression** in the top input field (e.g., `people[*].name`)
|
||||||
2. **Add JSON data** using one of these methods:
|
2. **Add JSON data** using one of these methods:
|
||||||
- **Load an Object**: Click "📄 Load an Object" to upload standard JSON files (.json)
|
- **Load an Object**: Click "Load an Object" to upload standard JSON files (.json)
|
||||||
- **Load a Log File**: Click "📋 Load a Log File" to upload JSON Lines files (.log) - each line converted to array
|
- **Load a Log File**: Click "Load a Log File" to upload JSON Lines files (.log) - each line converted to array
|
||||||
- **Paste or type**: Enter JSON data directly in the bottom-left textarea
|
- **Paste or type**: Enter JSON data directly in the bottom-left textarea
|
||||||
- **Load sample**: Use the "Load Sample" button for quick testing
|
- **Load sample**: Use the "Load Sample" button for quick testing
|
||||||
3. **View the results** in the bottom-right output area
|
3. **View the results** in the bottom-right output area
|
||||||
@@ -87,7 +87,7 @@ container run -p 3000:3000 jmespath-playground
|
|||||||
|
|
||||||
The application includes a REST API for uploading sample data remotely:
|
The application includes a REST API for uploading sample data remotely:
|
||||||
|
|
||||||
1. **Access API Key**: Click the key-lock button (🔒) to view your unique API key
|
1. **Access API Key**: Click the key-lock button to view your unique API key
|
||||||
2. **Upload Data**: Use curl or any HTTP client to upload JSON data:
|
2. **Upload Data**: Use curl or any HTTP client to upload JSON data:
|
||||||
```bash
|
```bash
|
||||||
curl -X POST \
|
curl -X POST \
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
services:
|
services:
|
||||||
jmespath-playground:
|
jmespath-playground:
|
||||||
build: .
|
build: .
|
||||||
image: skoszewski/jmespath-playground
|
image: skoszewski/jmespath-playground:latest
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jmespath-playground",
|
"name": "jmespath-playground",
|
||||||
"version": "1.4.0",
|
"version": "1.4.3",
|
||||||
"description": "A React-based web application for testing JMESPath expressions against JSON data",
|
"description": "A React-based web application for testing JMESPath expressions against JSON data",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"server": "node server.js --dev",
|
"server": "node server.js --dev",
|
||||||
"dev": "concurrently \"npm start\" \"node --watch server.js --dev\"",
|
"dev": "concurrently \"npm start\" \"node --watch server.js --dev\"",
|
||||||
"build-image": "vite build && node scripts/build-image.js"
|
"build-image": "vite build && node scripts/build-image.mjs"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=24.0.0"
|
"node": ">=24.0.0"
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const { execSync } = require('child_process');
|
import { execSync } from 'node:child_process';
|
||||||
const fs = require('fs');
|
import fs from 'node:fs';
|
||||||
const path = require('path');
|
import path from 'node:path';
|
||||||
const { pathToFileURL } = require('url');
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||||
const { parseArgs } = require('util');
|
import { parseArgs } from 'node:util';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
function execCommand(command, description) {
|
function execCommand(command, description) {
|
||||||
try {
|
try {
|
||||||
@@ -33,6 +36,15 @@ function getContainerTool() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isGitRepo() {
|
||||||
|
try {
|
||||||
|
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function generateVersionFile() {
|
async function generateVersionFile() {
|
||||||
const versionModuleUrl = pathToFileURL(path.join(__dirname, 'version.mjs')).href;
|
const versionModuleUrl = pathToFileURL(path.join(__dirname, 'version.mjs')).href;
|
||||||
const { generateVersionFile: generate } = await import(versionModuleUrl);
|
const { generateVersionFile: generate } = await import(versionModuleUrl);
|
||||||
@@ -41,6 +53,26 @@ async function generateVersionFile() {
|
|||||||
return versionFilePath;
|
return versionFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function writeVersionFile(version, isRelease) {
|
||||||
|
const versionFilePath = path.join(__dirname, '..', 'src', 'version.js');
|
||||||
|
const contents = [
|
||||||
|
`export const VERSION = '${version}';`,
|
||||||
|
`export const IS_RELEASE = ${isRelease};`,
|
||||||
|
''
|
||||||
|
].join('\n');
|
||||||
|
fs.writeFileSync(versionFilePath, contents, 'utf8');
|
||||||
|
return versionFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readPackageJsonVersion() {
|
||||||
|
const packagePath = path.join(__dirname, '..', 'package.json');
|
||||||
|
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
||||||
|
if (!pkg.version) {
|
||||||
|
throw new Error('package.json does not contain a version');
|
||||||
|
}
|
||||||
|
return pkg.version;
|
||||||
|
}
|
||||||
|
|
||||||
function readVersionFile(versionFilePath) {
|
function readVersionFile(versionFilePath) {
|
||||||
const contents = fs.readFileSync(versionFilePath, 'utf8');
|
const contents = fs.readFileSync(versionFilePath, 'utf8');
|
||||||
const versionMatch = contents.match(/export const VERSION = '([^']+)';/);
|
const versionMatch = contents.match(/export const VERSION = '([^']+)';/);
|
||||||
@@ -71,19 +103,21 @@ function showHelp() {
|
|||||||
console.log(`Build multi-architecture container images for JMESPath Playground
|
console.log(`Build multi-architecture container images for JMESPath Playground
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
build-image.js [OPTIONS]
|
build-image.mjs [OPTIONS]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--all-arch Build for both arm64 and amd64 (default: build for host architecture only)
|
--all-arch Build for both arm64 and amd64 (default: build for host architecture only)
|
||||||
--arch <arch> Target architecture (arm64 or amd64). Can be specified multiple times.
|
--arch <arch> Target architecture (arm64 or amd64). Can be specified multiple times.
|
||||||
|
--registry <id> Image registry (default: docker.io). Can also set JMESPATH_REGISTRY.
|
||||||
--help, -h Show this help message and exit
|
--help, -h Show this help message and exit
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
build-image.js # Builds for ${hostArch} only (host architecture)
|
build-image.mjs # Builds for ${hostArch} only (host architecture)
|
||||||
build-image.js --all-arch # Builds for both arm64 and amd64
|
build-image.mjs --all-arch # Builds for both arm64 and amd64
|
||||||
build-image.js --arch arm64 # Builds for arm64 only
|
build-image.mjs --arch arm64 # Builds for arm64 only
|
||||||
build-image.js --arch arm64 --arch amd64 # Explicitly specify both
|
build-image.mjs --arch arm64 --arch amd64 # Explicitly specify both
|
||||||
build-image.js -h # Show help`);
|
build-image.mjs --registry docker.io # Use Docker Hub registry explicitly
|
||||||
|
build-image.mjs -h # Show help`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
@@ -102,6 +136,10 @@ async function main() {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
multiple: true,
|
multiple: true,
|
||||||
description: 'Target architecture (arm64 or amd64)'
|
description: 'Target architecture (arm64 or amd64)'
|
||||||
|
},
|
||||||
|
registry: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Image registry (default: docker.io)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
strict: true,
|
strict: true,
|
||||||
@@ -114,8 +152,19 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const containerTool = getContainerTool();
|
const containerTool = getContainerTool();
|
||||||
const versionFilePath = await generateVersionFile();
|
let version;
|
||||||
const { version, isRelease } = readVersionFile(versionFilePath);
|
let isRelease;
|
||||||
|
|
||||||
|
if (isGitRepo()) {
|
||||||
|
const versionFilePath = await generateVersionFile();
|
||||||
|
const versionInfo = readVersionFile(versionFilePath);
|
||||||
|
version = versionInfo.version;
|
||||||
|
isRelease = versionInfo.isRelease;
|
||||||
|
} else {
|
||||||
|
version = readPackageJsonVersion();
|
||||||
|
isRelease = true;
|
||||||
|
writeVersionFile(version, isRelease);
|
||||||
|
}
|
||||||
|
|
||||||
let architectures;
|
let architectures;
|
||||||
if (values['all-arch']) {
|
if (values['all-arch']) {
|
||||||
@@ -130,14 +179,16 @@ async function main() {
|
|||||||
console.log(`Target architectures: ${architectures.join(', ')}`);
|
console.log(`Target architectures: ${architectures.join(', ')}`);
|
||||||
|
|
||||||
// Build container image
|
// Build container image
|
||||||
|
const registry = values.registry || process.env.JMESPATH_REGISTRY || 'docker.io';
|
||||||
|
const imageName = `${registry.replace(/\/$/, '')}/skoszewski/jmespath-playground`;
|
||||||
const tags = isRelease
|
const tags = isRelease
|
||||||
? [
|
? [
|
||||||
`-t skoszewski/jmespath-playground:${version}`,
|
`-t ${imageName}:${version}`,
|
||||||
`-t skoszewski/jmespath-playground:latest`
|
`-t ${imageName}:latest`
|
||||||
].join(' ')
|
].join(' ')
|
||||||
: [
|
: [
|
||||||
`-t skoszewski/jmespath-playground:dev`,
|
`-t ${imageName}:dev`,
|
||||||
`-t skoszewski/jmespath-playground:latest`
|
`-t ${imageName}:latest`
|
||||||
].join(' ');
|
].join(' ');
|
||||||
|
|
||||||
const archFlags = architectures.map(arch => `--arch ${arch}`).join(' ');
|
const archFlags = architectures.map(arch => `--arch ${arch}`).join(' ');
|
||||||
@@ -150,26 +201,29 @@ async function main() {
|
|||||||
|
|
||||||
// Show usage instructions
|
// Show usage instructions
|
||||||
console.log(`\nUsage examples:`);
|
console.log(`\nUsage examples:`);
|
||||||
console.log(` build-image.js # Builds for host architecture only`);
|
console.log(` build-image.mjs # Builds for host architecture only`);
|
||||||
console.log(` build-image.js --all-arch # Builds for both arm64 and amd64`);
|
console.log(` build-image.mjs --all-arch # Builds for both arm64 and amd64`);
|
||||||
console.log(` build-image.js --arch arm64 # Builds for arm64 only`);
|
console.log(` build-image.mjs --arch arm64 # Builds for arm64 only`);
|
||||||
console.log(` build-image.js --arch arm64 --arch amd64 # Explicitly specify both`);
|
console.log(` build-image.mjs --arch arm64 --arch amd64 # Explicitly specify both`);
|
||||||
|
|
||||||
if (isRelease) {
|
if (isRelease) {
|
||||||
console.log(`\nTo run the container:`);
|
console.log(`\nTo run the container:`);
|
||||||
console.log(` ${containerTool} run --arch arm64 --name jmespathpg -p 3000:3000 skoszewski/jmespath-playground:${version}`);
|
console.log(` ${containerTool} run --arch arm64 --name jmespathpg -p 3000:3000 ${imageName}:${version}`);
|
||||||
if (containerTool === 'docker') {
|
if (containerTool === 'docker') {
|
||||||
console.log(`\nTo push to Docker Hub:`);
|
console.log(`\nTo push to Docker Hub:`);
|
||||||
console.log(` docker push skoszewski/jmespath-playground:${version}`);
|
console.log(` docker push ${imageName}:${version}`);
|
||||||
console.log(` docker push skoszewski/jmespath-playground:latest`);
|
console.log(` docker push ${imageName}:latest`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(`\nTo run the container:`);
|
console.log(`\nTo run the container:`);
|
||||||
console.log(` ${containerTool} run --arch arm64 --name jmespathpg -p 3000:3000 skoszewski/jmespath-playground:dev`);
|
console.log(` ${containerTool} run --arch arm64 --name jmespathpg -p 3000:3000 ${imageName}:dev`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (require.main === module) {
|
const isDirectRun = process.argv[1]
|
||||||
|
&& fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
|
||||||
|
|
||||||
|
if (isDirectRun) {
|
||||||
main().catch((error) => {
|
main().catch((error) => {
|
||||||
console.error(`Error: ${error.message}`);
|
console.error(`Error: ${error.message}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@@ -1,13 +1,46 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const fs = require('fs');
|
import { execSync } from 'node:child_process';
|
||||||
const { execSync } = require('child_process');
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import semver from 'semver';
|
||||||
|
|
||||||
|
function tagMatchesVersion(tag, version) {
|
||||||
|
if (!tag) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tag === version) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (tag.startsWith('v')) {
|
||||||
|
return tag.slice(1) === version;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasMatchingTag(tagsOutput, version) {
|
||||||
|
return tagsOutput
|
||||||
|
.split('\n')
|
||||||
|
.map(tag => tag.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.some(tag => tagMatchesVersion(tag, version));
|
||||||
|
}
|
||||||
|
|
||||||
|
function findMatchingTag(tagsOutput, version) {
|
||||||
|
return tagsOutput
|
||||||
|
.split('\n')
|
||||||
|
.map(tag => tag.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.find(tag => tagMatchesVersion(tag, version)) || null;
|
||||||
|
}
|
||||||
|
|
||||||
function showUsage() {
|
function showUsage() {
|
||||||
console.log('Usage: node scripts/new-version.js <version> [--force] [-m|--message "commit message"]');
|
console.log('Usage: node scripts/new-version.mjs <version> [--force] [-m|--message "commit message"]');
|
||||||
console.log(' node scripts/new-version.js --check <version>');
|
console.log(' node scripts/new-version.mjs --check <version>');
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('Creates a new version by tagging the current commit.');
|
console.log('Creates a new version by tagging the current commit.');
|
||||||
|
console.log('Version must be valid semver (e.g., 1.2.3).');
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('Options:');
|
console.log('Options:');
|
||||||
console.log(' --force Force version creation even with dirty repo or package.json mismatch');
|
console.log(' --force Force version creation even with dirty repo or package.json mismatch');
|
||||||
@@ -15,14 +48,14 @@ function showUsage() {
|
|||||||
console.log(' -m, --message TEXT Custom commit message (only used when commit is needed)');
|
console.log(' -m, --message TEXT Custom commit message (only used when commit is needed)');
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('Example:');
|
console.log('Example:');
|
||||||
console.log(' node scripts/new-version.js 1.2.0');
|
console.log(' node scripts/new-version.mjs 1.2.0');
|
||||||
console.log(' node scripts/new-version.js 1.2.0 --force');
|
console.log(' node scripts/new-version.mjs 1.2.0 --force');
|
||||||
console.log(' node scripts/new-version.js 1.2.0 -m "Add new feature XYZ"');
|
console.log(' node scripts/new-version.mjs 1.2.0 -m "Add new feature XYZ"');
|
||||||
console.log(' node scripts/new-version.js --check 1.3.0');
|
console.log(' node scripts/new-version.mjs --check 1.3.0');
|
||||||
}
|
}
|
||||||
|
|
||||||
function performCheck(targetVersion) {
|
function performCheck(targetVersion) {
|
||||||
console.log('🔍 Repository Analysis Report');
|
console.log('Repository Analysis Report');
|
||||||
console.log('============================');
|
console.log('============================');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -31,7 +64,7 @@ function performCheck(targetVersion) {
|
|||||||
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
||||||
const currentVersion = pkg.version;
|
const currentVersion = pkg.version;
|
||||||
|
|
||||||
console.log(`📦 Package.json version: ${currentVersion}`);
|
console.log(`Package.json version: ${currentVersion}`);
|
||||||
|
|
||||||
// Check repository status
|
// Check repository status
|
||||||
let isRepoDirty = false;
|
let isRepoDirty = false;
|
||||||
@@ -41,71 +74,71 @@ function performCheck(targetVersion) {
|
|||||||
isRepoDirty = status.trim() !== '';
|
isRepoDirty = status.trim() !== '';
|
||||||
dirtyFiles = status.trim();
|
dirtyFiles = status.trim();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('⚠️ Cannot determine git status');
|
console.log('Warning: Cannot determine git status');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRepoDirty) {
|
if (isRepoDirty) {
|
||||||
console.log('🔄 Repository status: DIRTY');
|
console.log('Repository status: DIRTY');
|
||||||
console.log(' Uncommitted changes:');
|
console.log(' Uncommitted changes:');
|
||||||
dirtyFiles.split('\n').forEach(line => {
|
dirtyFiles.split('\n').forEach(line => {
|
||||||
if (line.trim()) console.log(` ${line}`);
|
if (line.trim()) console.log(` ${line}`);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log('✅ Repository status: CLEAN');
|
console.log('Repository status: CLEAN');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check current commit info
|
// Check current commit info
|
||||||
try {
|
try {
|
||||||
const currentCommit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();
|
const currentCommit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();
|
||||||
const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();
|
const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();
|
||||||
console.log(`🌟 Current commit: ${currentCommit.substring(0, 7)} (${currentBranch})`);
|
console.log(`Current commit: ${currentCommit.substring(0, 7)} (${currentBranch})`);
|
||||||
|
|
||||||
// Check if current commit is tagged
|
// Check if current commit is tagged
|
||||||
const tagsOnHead = execSync('git tag --points-at HEAD', { encoding: 'utf8' }).trim();
|
const tagsOnHead = execSync('git tag --points-at HEAD', { encoding: 'utf8' }).trim();
|
||||||
if (tagsOnHead) {
|
if (tagsOnHead) {
|
||||||
console.log(`🏷️ Current commit tags: ${tagsOnHead.split('\n').join(', ')}`);
|
console.log(`Current commit tags: ${tagsOnHead.split('\n').join(', ')}`);
|
||||||
} else {
|
} else {
|
||||||
console.log('🏷️ Current commit: No tags');
|
console.log('Current commit: No tags');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('⚠️ Cannot determine commit info');
|
console.log('Warning: Cannot determine commit info');
|
||||||
}
|
}
|
||||||
|
|
||||||
// List recent tags
|
// List recent tags
|
||||||
try {
|
try {
|
||||||
const recentTags = execSync('git tag --sort=-version:refname | head -5', { encoding: 'utf8' }).trim();
|
const recentTags = execSync('git tag --sort=-version:refname | head -5', { encoding: 'utf8' }).trim();
|
||||||
if (recentTags) {
|
if (recentTags) {
|
||||||
console.log('📋 Recent tags:');
|
console.log('Recent tags:');
|
||||||
recentTags.split('\n').forEach(tag => {
|
recentTags.split('\n').forEach(tag => {
|
||||||
if (tag.trim()) console.log(` ${tag}`);
|
if (tag.trim()) console.log(` ${tag}`);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log('📋 No tags found in repository');
|
console.log('No tags found in repository');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('⚠️ Cannot list tags');
|
console.log('Warning: Cannot list tags');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
// Analysis for target version (if provided)
|
// Analysis for target version (if provided)
|
||||||
if (targetVersion) {
|
if (targetVersion) {
|
||||||
const tagName = `v${targetVersion}`;
|
const tagName = targetVersion;
|
||||||
console.log(`🎯 Analysis for version ${targetVersion}:`);
|
console.log(`Analysis for version ${targetVersion}:`);
|
||||||
console.log('=====================================');
|
console.log('=====================================');
|
||||||
|
|
||||||
// Check if target tag exists
|
// Check if target tag exists
|
||||||
try {
|
try {
|
||||||
const existingTags = execSync('git tag -l', { encoding: 'utf8' });
|
const existingTags = execSync('git tag -l', { encoding: 'utf8' });
|
||||||
const tagExists = existingTags.split('\n').includes(tagName);
|
const matchingTag = findMatchingTag(existingTags, targetVersion);
|
||||||
|
|
||||||
if (tagExists) {
|
if (matchingTag) {
|
||||||
console.log(`❌ Tag '${tagName}' already exists - CANNOT CREATE`);
|
console.log(`Error: Tag '${matchingTag}' already exists - CANNOT CREATE`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(`✅ Tag '${tagName}' available`);
|
console.log(`Tag '${tagName}' available`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('⚠️ Cannot check tag availability');
|
console.log('Warning: Cannot check tag availability');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,46 +147,46 @@ function performCheck(targetVersion) {
|
|||||||
const needsPackageUpdate = !packageJsonMatches;
|
const needsPackageUpdate = !packageJsonMatches;
|
||||||
const needsCommit = isRepoDirty || needsPackageUpdate;
|
const needsCommit = isRepoDirty || needsPackageUpdate;
|
||||||
|
|
||||||
console.log(`📝 Package.json: ${packageJsonMatches ? 'MATCHES' : `NEEDS UPDATE (${currentVersion} → ${targetVersion})`}`);
|
console.log(`Package.json: ${packageJsonMatches ? 'MATCHES' : `NEEDS UPDATE (${currentVersion} -> ${targetVersion})`}`);
|
||||||
|
|
||||||
if (needsCommit) {
|
if (needsCommit) {
|
||||||
console.log('⚡ Actions needed:');
|
console.log('Actions needed:');
|
||||||
if (needsPackageUpdate) {
|
if (needsPackageUpdate) {
|
||||||
console.log(' • Update package.json');
|
console.log(' - Update package.json');
|
||||||
}
|
}
|
||||||
if (isRepoDirty) {
|
if (isRepoDirty) {
|
||||||
console.log(' • Stage uncommitted changes');
|
console.log(' - Stage uncommitted changes');
|
||||||
}
|
}
|
||||||
console.log(' • Create commit');
|
console.log(' - Create commit');
|
||||||
console.log(` • Create tag ${tagName}`);
|
console.log(` - Create tag ${tagName}`);
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('📋 Commands that would work:');
|
console.log('Commands that would work:');
|
||||||
if (isRepoDirty || needsPackageUpdate) {
|
if (isRepoDirty || needsPackageUpdate) {
|
||||||
console.log(` node scripts/new-version.js ${targetVersion} --force`);
|
console.log(` node scripts/new-version.mjs ${targetVersion} --force`);
|
||||||
} else {
|
} else {
|
||||||
console.log(` node scripts/new-version.js ${targetVersion}`);
|
console.log(` node scripts/new-version.mjs ${targetVersion}`);
|
||||||
console.log(` node scripts/new-version.js ${targetVersion} --force`);
|
console.log(` node scripts/new-version.mjs ${targetVersion} --force`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log('⚡ Actions needed:');
|
console.log('Actions needed:');
|
||||||
console.log(` • Create tag ${tagName} (no commit needed)`);
|
console.log(` - Create tag ${tagName} (no commit needed)`);
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('📋 Commands that would work:');
|
console.log('Commands that would work:');
|
||||||
console.log(` node scripts/new-version.js ${targetVersion}`);
|
console.log(` node scripts/new-version.mjs ${targetVersion}`);
|
||||||
console.log(` node scripts/new-version.js ${targetVersion} --force`);
|
console.log(` node scripts/new-version.mjs ${targetVersion} --force`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('🚦 Default mode requirements:');
|
console.log('Default mode requirements:');
|
||||||
if (isRepoDirty) {
|
if (isRepoDirty) {
|
||||||
console.log(' ❌ Repository must be clean (currently dirty)');
|
console.log(' Repository must be clean (currently dirty)');
|
||||||
} else {
|
} else {
|
||||||
console.log(' ✅ Repository is clean');
|
console.log(' Repository is clean');
|
||||||
}
|
}
|
||||||
if (!packageJsonMatches) {
|
if (!packageJsonMatches) {
|
||||||
console.log(` ❌ Package.json must match version (currently ${currentVersion})`);
|
console.log(` Package.json must match version (currently ${currentVersion})`);
|
||||||
} else {
|
} else {
|
||||||
console.log(' ✅ Package.json version matches');
|
console.log(' Package.json version matches');
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -163,7 +196,7 @@ function performCheck(targetVersion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error during analysis:', error.message);
|
console.error('Error during analysis:', error.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,28 +233,43 @@ function main() {
|
|||||||
// For normal operation, version is required
|
// For normal operation, version is required
|
||||||
newVersion = args.find(arg => !arg.startsWith('--') && arg !== '-m' && arg !== customMessage);
|
newVersion = args.find(arg => !arg.startsWith('--') && arg !== '-m' && arg !== customMessage);
|
||||||
if (!newVersion) {
|
if (!newVersion) {
|
||||||
|
console.error('Error: Version argument required');
|
||||||
|
showUsage();
|
||||||
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newVersion && newVersion.startsWith('v')) {
|
||||||
|
console.error('Error: Version must not start with "v". Use plain semver like 1.2.3.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedVersion = newVersion;
|
||||||
|
if (!semver.valid(normalizedVersion)) {
|
||||||
|
console.error('Error: Version must be valid semver (e.g., 1.2.3)');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
if (isCheck) {
|
if (isCheck) {
|
||||||
performCheck(newVersion);
|
performCheck(normalizedVersion);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagName = `v${newVersion}`;
|
const tagName = normalizedVersion;
|
||||||
|
|
||||||
console.log(`🏷️ Creating new version: ${newVersion}${isForce ? ' (forced)' : ''}`);
|
console.log(`Creating new version: ${normalizedVersion}${isForce ? ' (forced)' : ''}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. Check if tag already exists - Always ERROR
|
// 1. Check if tag already exists - Always ERROR
|
||||||
try {
|
try {
|
||||||
const existingTags = execSync('git tag -l', { encoding: 'utf8' });
|
const existingTags = execSync('git tag -l', { encoding: 'utf8' });
|
||||||
if (existingTags.split('\n').includes(tagName)) {
|
const matchingTag = findMatchingTag(existingTags, normalizedVersion);
|
||||||
console.error(`❌ Error: Tag '${tagName}' already exists`);
|
if (matchingTag) {
|
||||||
|
console.error(`Error: Tag '${matchingTag}' already exists`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error: Failed to check existing tags');
|
console.error('Error: Failed to check existing tags');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +279,7 @@ function main() {
|
|||||||
const status = execSync('git status --porcelain', { encoding: 'utf8' });
|
const status = execSync('git status --porcelain', { encoding: 'utf8' });
|
||||||
isRepoDirty = status.trim() !== '';
|
isRepoDirty = status.trim() !== '';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error: Failed to check git status');
|
console.error('Error: Failed to check git status');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +287,7 @@ function main() {
|
|||||||
const packagePath = './package.json';
|
const packagePath = './package.json';
|
||||||
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
||||||
const currentVersion = pkg.version;
|
const currentVersion = pkg.version;
|
||||||
const packageJsonMatches = currentVersion === newVersion;
|
const packageJsonMatches = currentVersion === normalizedVersion;
|
||||||
|
|
||||||
// 4. Determine what action is needed
|
// 4. Determine what action is needed
|
||||||
const needsPackageUpdate = !packageJsonMatches;
|
const needsPackageUpdate = !packageJsonMatches;
|
||||||
@@ -248,12 +296,12 @@ function main() {
|
|||||||
// 5. Check if force is required
|
// 5. Check if force is required
|
||||||
if (!isForce) {
|
if (!isForce) {
|
||||||
if (isRepoDirty) {
|
if (isRepoDirty) {
|
||||||
console.error('❌ Error: Working directory has uncommitted changes');
|
console.error('Error: Working directory has uncommitted changes');
|
||||||
console.error('Please commit your changes first or use --force');
|
console.error('Please commit your changes first or use --force');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
if (needsPackageUpdate) {
|
if (needsPackageUpdate) {
|
||||||
console.error(`❌ Error: Package.json version is ${currentVersion}, requested ${newVersion}`);
|
console.error(`Error: Package.json version is ${currentVersion}, requested ${normalizedVersion}`);
|
||||||
console.error('Use --force to update package.json');
|
console.error('Use --force to update package.json');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@@ -261,40 +309,45 @@ function main() {
|
|||||||
|
|
||||||
// 6. Execute the versioning
|
// 6. Execute the versioning
|
||||||
if (needsCommit) {
|
if (needsCommit) {
|
||||||
console.log(`📦 Needs commit: ${needsPackageUpdate ? 'package.json update' : ''}${needsPackageUpdate && isRepoDirty ? ' + ' : ''}${isRepoDirty ? 'uncommitted changes' : ''}`);
|
console.log(`Needs commit: ${needsPackageUpdate ? 'package.json update' : ''}${needsPackageUpdate && isRepoDirty ? ' + ' : ''}${isRepoDirty ? 'uncommitted changes' : ''}`);
|
||||||
|
|
||||||
// Update package.json if needed
|
// Update package.json if needed
|
||||||
if (needsPackageUpdate) {
|
if (needsPackageUpdate) {
|
||||||
pkg.version = newVersion;
|
pkg.version = normalizedVersion;
|
||||||
fs.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + '\n');
|
fs.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + '\n');
|
||||||
console.log(`📝 Updated package.json: ${currentVersion} → ${newVersion}`);
|
console.log(`Updated package.json: ${currentVersion} -> ${normalizedVersion}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stage all changes
|
// Stage all changes
|
||||||
execSync('git add .', { stdio: 'inherit' });
|
execSync('git add .', { stdio: 'inherit' });
|
||||||
|
|
||||||
// Commit
|
// Commit
|
||||||
const commitMessage = customMessage || (needsPackageUpdate ? `Version ${newVersion}` : `Prepare for version ${newVersion}`);
|
const commitMessage = customMessage || (needsPackageUpdate ? `Version ${normalizedVersion}` : `Prepare for version ${normalizedVersion}`);
|
||||||
execSync(`git commit -m "${commitMessage}"`, { stdio: 'inherit' });
|
execSync(`git commit -m "${commitMessage}"`, { stdio: 'inherit' });
|
||||||
console.log(`✅ Committed changes`);
|
console.log('Committed changes');
|
||||||
} else {
|
} else {
|
||||||
console.log(`✅ Repository clean, package.json matches - tagging current commit`);
|
console.log('Repository clean, package.json matches - tagging current commit');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. Tag the commit
|
// 7. Tag the commit
|
||||||
execSync(`git tag ${tagName}`, { stdio: 'inherit' });
|
execSync(`git tag ${tagName}`, { stdio: 'inherit' });
|
||||||
console.log(`🏷️ Created tag: ${tagName}`);
|
console.log(`Created tag: ${tagName}`);
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('🎉 Version created successfully!');
|
console.log('Version created successfully!');
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('Next steps:');
|
console.log('Next steps:');
|
||||||
console.log(` git push origin main --tags # Push the commit and tag`);
|
console.log(` git push origin main --tags # Push the commit and tag`);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error during version creation:', error.message);
|
console.error('Error during version creation:', error.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
const isDirectRun = process.argv[1]
|
||||||
|
&& fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
|
||||||
|
|
||||||
|
if (isDirectRun) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "Alice Johnson",
|
|
||||||
"email": "alice@example.com",
|
|
||||||
"role": "admin",
|
|
||||||
"skills": ["JavaScript", "Python", "SQL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 2,
|
|
||||||
"name": "Bob Wilson",
|
|
||||||
"email": "bob@example.com",
|
|
||||||
"role": "developer",
|
|
||||||
"skills": ["Java", "Spring", "React"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"name": "Carol Davis",
|
|
||||||
"email": "carol@example.com",
|
|
||||||
"role": "designer",
|
|
||||||
"skills": ["Figma", "Photoshop", "CSS"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"total": 3,
|
|
||||||
"created": "2026-01-21",
|
|
||||||
"version": "1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,24 @@ import { readFileSync, write, writeFileSync } from "fs";
|
|||||||
import { execSync } from "child_process";
|
import { execSync } from "child_process";
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
|
|
||||||
|
export function isGitAvailable() {
|
||||||
|
try {
|
||||||
|
execSync("git --version", { stdio: "ignore" });
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isGitRepo() {
|
||||||
|
try {
|
||||||
|
execSync("git rev-parse --is-inside-work-tree", { stdio: "ignore" });
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getGitVersion() {
|
export function getGitVersion() {
|
||||||
let rawGitVersion;
|
let rawGitVersion;
|
||||||
let gitVersion;
|
let gitVersion;
|
||||||
@@ -28,26 +46,38 @@ export function getGitVersion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function generateVersionFile(versionFilePath) {
|
export function generateVersionFile(versionFilePath) {
|
||||||
|
if (!isGitAvailable()) {
|
||||||
|
throw new Error("Git is required to generate version info.");
|
||||||
|
}
|
||||||
|
|
||||||
// Read package.json version
|
// Read package.json version
|
||||||
const packageVersion = JSON.parse(
|
const packageVersion = JSON.parse(
|
||||||
readFileSync("package.json", { encoding: "utf-8" }),
|
readFileSync("package.json", { encoding: "utf-8" }),
|
||||||
).version;
|
).version;
|
||||||
// Get version from git repository
|
let gitVersion = packageVersion;
|
||||||
const gitVersion = getGitVersion();
|
let gitBaseVersion = packageVersion;
|
||||||
const gitBaseVersion = semver.coerce(gitVersion)?.version;
|
let isRelease = true;
|
||||||
|
|
||||||
// if git returned malformed version, throw error
|
if (isGitRepo()) {
|
||||||
if (!gitBaseVersion || gitBaseVersion === "0.0.0") {
|
// Get version from git repository
|
||||||
throw new Error(
|
gitVersion = getGitVersion();
|
||||||
"Cannot determine git version. Make sure the script is run in a git repository with tags.",
|
gitBaseVersion = semver.coerce(gitVersion)?.version;
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare git version with package.json version
|
// if git returned malformed version, throw error
|
||||||
if (semver.neq(gitBaseVersion, packageVersion)) {
|
if (!gitBaseVersion || gitBaseVersion === "0.0.0") {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Version mismatch: package.json version is ${packageVersion}, but git version is ${gitBaseVersion}`,
|
"Cannot determine git version. Make sure the script is run in a git repository with tags.",
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare git version with package.json version
|
||||||
|
if (semver.neq(gitBaseVersion, packageVersion)) {
|
||||||
|
throw new Error(
|
||||||
|
`Version mismatch: package.json version is ${packageVersion}, but git version is ${gitBaseVersion}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
isRelease = gitVersion === packageVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate version file
|
// Generate version file
|
||||||
@@ -58,7 +88,7 @@ export function generateVersionFile(versionFilePath) {
|
|||||||
// Generated at: ${buildDate}
|
// Generated at: ${buildDate}
|
||||||
|
|
||||||
export const VERSION = '${packageVersion}';
|
export const VERSION = '${packageVersion}';
|
||||||
export const IS_RELEASE = ${gitVersion === packageVersion};
|
export const IS_RELEASE = ${isRelease};
|
||||||
export const BUILD_TIME = '${buildDate}';
|
export const BUILD_TIME = '${buildDate}';
|
||||||
`,
|
`,
|
||||||
);
|
);
|
||||||
|
|||||||
22
server.js
22
server.js
@@ -29,7 +29,7 @@ function encrypt(data, key) {
|
|||||||
tag: authTag.toString("hex"),
|
tag: authTag.toString("hex"),
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("⚠️ Encryption exception:", {
|
console.error("Encryption exception:", {
|
||||||
message: error.message,
|
message: error.message,
|
||||||
algorithm: "aes-256-gcm",
|
algorithm: "aes-256-gcm",
|
||||||
keyLength: key ? key.length : "undefined",
|
keyLength: key ? key.length : "undefined",
|
||||||
@@ -56,7 +56,7 @@ function decrypt(encryptedObj, key) {
|
|||||||
|
|
||||||
return JSON.parse(decrypted);
|
return JSON.parse(decrypted);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("⚠️ Decryption exception:", {
|
console.error("Decryption exception:", {
|
||||||
message: error.message,
|
message: error.message,
|
||||||
algorithm: "aes-256-gcm",
|
algorithm: "aes-256-gcm",
|
||||||
keyLength: key ? key.length : "undefined",
|
keyLength: key ? key.length : "undefined",
|
||||||
@@ -100,7 +100,7 @@ function createApp(devMode = false) {
|
|||||||
if (devMode) {
|
if (devMode) {
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = new Date().toISOString();
|
||||||
console.log(`📨 [${timestamp}] ${req.method} ${req.path}`);
|
console.log(`[${timestamp}] ${req.method} ${req.path}`);
|
||||||
if (req.method !== "GET" && Object.keys(req.body).length > 0) {
|
if (req.method !== "GET" && Object.keys(req.body).length > 0) {
|
||||||
const bodySize = Buffer.byteLength(JSON.stringify(req.body), "utf8");
|
const bodySize = Buffer.byteLength(JSON.stringify(req.body), "utf8");
|
||||||
console.log(` Request body size: ${(bodySize / 1024).toFixed(2)}KB`);
|
console.log(` Request body size: ${(bodySize / 1024).toFixed(2)}KB`);
|
||||||
@@ -108,7 +108,7 @@ function createApp(devMode = false) {
|
|||||||
|
|
||||||
const originalJson = res.json;
|
const originalJson = res.json;
|
||||||
res.json = function (data) {
|
res.json = function (data) {
|
||||||
console.log(` ✓ Response: ${res.statusCode}`);
|
console.log(` Response: ${res.statusCode}`);
|
||||||
return originalJson.call(this, data);
|
return originalJson.call(this, data);
|
||||||
};
|
};
|
||||||
next();
|
next();
|
||||||
@@ -125,7 +125,7 @@ function createApp(devMode = false) {
|
|||||||
if (now - session.createdAt > MAX_SESSION_TTL) {
|
if (now - session.createdAt > MAX_SESSION_TTL) {
|
||||||
sessions.delete(sessionId);
|
sessions.delete(sessionId);
|
||||||
console.log(
|
console.log(
|
||||||
`🧹 Cleaned up expired session: ${sessionId.substring(0, 8)}...`,
|
`Cleaned up expired session: ${sessionId.substring(0, 8)}...`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,12 +192,12 @@ function createApp(devMode = false) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`📁 Session created: ${sessionId.substring(0, 8)}... (${sessions.size}/${MAX_SESSIONS})`,
|
`Session created: ${sessionId.substring(0, 8)}... (${sessions.size}/${MAX_SESSIONS})`,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.json({ message: "OK" });
|
res.json({ message: "OK" });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("⚠️ Upload endpoint exception occurred:", {
|
console.error("Upload endpoint exception occurred:", {
|
||||||
message: error.message,
|
message: error.message,
|
||||||
stack: error.stack,
|
stack: error.stack,
|
||||||
sessionCount: sessions.size,
|
sessionCount: sessions.size,
|
||||||
@@ -257,12 +257,12 @@ function createApp(devMode = false) {
|
|||||||
// Remove session after first access (one-time use)
|
// Remove session after first access (one-time use)
|
||||||
sessions.delete(sessionId);
|
sessions.delete(sessionId);
|
||||||
console.log(
|
console.log(
|
||||||
`📤 Sample data retrieved and session cleared: ${sessionId.substring(0, 8)}...`,
|
`Sample data retrieved and session cleared: ${sessionId.substring(0, 8)}...`,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.json(decryptedData);
|
res.json(decryptedData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("⚠️ Sample retrieval exception occurred:", {
|
console.error("Sample retrieval exception occurred:", {
|
||||||
message: error.message,
|
message: error.message,
|
||||||
stack: error.stack,
|
stack: error.stack,
|
||||||
sessionCount: sessions.size,
|
sessionCount: sessions.size,
|
||||||
@@ -318,7 +318,7 @@ function createApp(devMode = false) {
|
|||||||
|
|
||||||
res.json({ state: session.state });
|
res.json({ state: session.state });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("⚠️ State retrieval exception occurred:", {
|
console.error("State retrieval exception occurred:", {
|
||||||
message: error.message,
|
message: error.message,
|
||||||
stack: error.stack,
|
stack: error.stack,
|
||||||
sessionCount: sessions.size,
|
sessionCount: sessions.size,
|
||||||
@@ -402,7 +402,7 @@ if (require.main === module) {
|
|||||||
app.listen(PORT, HOST, () => {
|
app.listen(PORT, HOST, () => {
|
||||||
console.log(`JMESPath Playground Server running`);
|
console.log(`JMESPath Playground Server running`);
|
||||||
if (DEV_MODE) {
|
if (DEV_MODE) {
|
||||||
console.log(` 🔧 Development Mode Enabled`);
|
console.log(" Development Mode Enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show actual accessible URLs
|
// Show actual accessible URLs
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Box, Typography, Container, Link, Grid } from "@mui/material";
|
import { Box, Typography, Container, Link, Grid } from "@mui/material";
|
||||||
import { VERSION } from "../version";
|
import { IS_RELEASE, VERSION } from "../version";
|
||||||
|
|
||||||
function Footer() {
|
function Footer() {
|
||||||
return (
|
return (
|
||||||
@@ -19,7 +19,7 @@ function Footer() {
|
|||||||
<Grid size={{ xs: 12, md: 6 }}>
|
<Grid size={{ xs: 12, md: 6 }}>
|
||||||
<Typography variant="body2" color="text.secondary">
|
<Typography variant="body2" color="text.secondary">
|
||||||
<strong>JMESPath Testing Tool</strong>{" "}
|
<strong>JMESPath Testing Tool</strong>{" "}
|
||||||
{VERSION === "unknown" ? VERSION : `v${VERSION}`} - Created for
|
{IS_RELEASE ? VERSION : `${VERSION}-dev`} - Created for
|
||||||
testing and validating JMESPath expressions
|
testing and validating JMESPath expressions
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -55,4 +55,4 @@ function Footer() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Footer;
|
export default Footer;
|
||||||
|
|||||||
@@ -214,7 +214,6 @@ function MainPage({
|
|||||||
|
|
||||||
<Paper
|
<Paper
|
||||||
sx={{
|
sx={{
|
||||||
mb: 1,
|
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
bgcolor: "background.paper",
|
bgcolor: "background.paper",
|
||||||
border: 1,
|
border: 1,
|
||||||
|
|||||||
7
terraform/.gitignore
vendored
Normal file
7
terraform/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Terraform
|
||||||
|
*.tfstate
|
||||||
|
*.tfstate.*
|
||||||
|
.terraform/
|
||||||
|
.terraform.lock.hcl
|
||||||
|
.terraform.lock.hcl.backup
|
||||||
|
*tfplan
|
||||||
41
terraform/main.tf
Normal file
41
terraform/main.tf
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Create Cloud Run service
|
||||||
|
resource "google_cloud_run_v2_service" "jppg" {
|
||||||
|
name = "jmespath-playground"
|
||||||
|
location = var.default_region
|
||||||
|
invoker_iam_disabled = true
|
||||||
|
|
||||||
|
template {
|
||||||
|
containers {
|
||||||
|
image = "skoszewski/jmespath-playground:${var.image_version}"
|
||||||
|
name = "jmespath-playground-1"
|
||||||
|
ports {
|
||||||
|
container_port = 3000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scaling {
|
||||||
|
max_instance_count = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
deletion_protection = var.deletion_protection
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
ignore_changes = [
|
||||||
|
client
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_cloud_run_domain_mapping" "jppg" {
|
||||||
|
name = "jmespath-playground.gcp-lab.koszewscy.waw.pl"
|
||||||
|
location = var.default_region
|
||||||
|
|
||||||
|
spec {
|
||||||
|
route_name = google_cloud_run_v2_service.jppg.name
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata {
|
||||||
|
namespace = var.project_id
|
||||||
|
}
|
||||||
|
}
|
||||||
13
terraform/providers.tf
Normal file
13
terraform/providers.tf
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
google = {
|
||||||
|
source = "hashicorp/google"
|
||||||
|
version = "~>7.17.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "google" {
|
||||||
|
project = var.project_id
|
||||||
|
region = var.default_region
|
||||||
|
}
|
||||||
5
terraform/terraform.tfvars.json
Normal file
5
terraform/terraform.tfvars.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"project_id": "dom-lab",
|
||||||
|
"image_version": "1.4.3",
|
||||||
|
"deletion_protection": true
|
||||||
|
}
|
||||||
21
terraform/variables.tf
Normal file
21
terraform/variables.tf
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
variable "project_id" {
|
||||||
|
description = "Google project id"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "default_region" {
|
||||||
|
description = "Default Google Cloud region"
|
||||||
|
type = string
|
||||||
|
default = "europe-west1" # Belgium
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "image_version" {
|
||||||
|
description = "Version of the Docker image"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "deletion_protection" {
|
||||||
|
type = bool
|
||||||
|
description = "Protect resources from deletion using terraform destroy and apply."
|
||||||
|
default = true
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user