Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ef2c1931d8 | |||
| d027459678 | |||
| 4d6efe791b |
15
Dockerfile
15
Dockerfile
@@ -1,6 +1,10 @@
|
||||
# Build stage
|
||||
FROM node:24-alpine AS builder
|
||||
|
||||
# Accept build arguments for version info
|
||||
ARG VERSION=""
|
||||
ARG IS_RELEASE="false"
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
@@ -16,6 +20,17 @@ COPY public/ ./public/
|
||||
COPY scripts/ ./scripts/
|
||||
COPY server.js ./server.js
|
||||
|
||||
# Generate version.js if version info provided, otherwise run normal build
|
||||
RUN if [ -n "$VERSION" ]; then \
|
||||
echo "// Auto-generated version file - do not edit manually" > src/version.js && \
|
||||
echo "// Generated at: $(date -Iseconds)" >> src/version.js && \
|
||||
echo "" >> src/version.js && \
|
||||
echo "export const VERSION = '$VERSION';" >> src/version.js && \
|
||||
echo "export const IS_RELEASE = $IS_RELEASE;" >> src/version.js && \
|
||||
echo "export const BUILD_TIME = '$(date -Iseconds)';" >> src/version.js && \
|
||||
echo "📝 Generated version.js with VERSION=$VERSION, IS_RELEASE=$IS_RELEASE"; \
|
||||
fi
|
||||
|
||||
# Build the application
|
||||
RUN npm run build
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jmespath-playground",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.4",
|
||||
"description": "A React-based web application for testing JMESPath expressions against JSON data",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -33,7 +33,31 @@ npm run build
|
||||
# Optional container build with Docker
|
||||
if command -v docker &> /dev/null; then
|
||||
echo "🐳 Building Docker container (optional)..."
|
||||
docker build -t jmespath-playground .
|
||||
|
||||
# Determine version information for Docker build
|
||||
VERSION=$(git tag --points-at HEAD 2>/dev/null | sed 's/^v//' | head -n 1)
|
||||
|
||||
if [ -n "$VERSION" ]; then
|
||||
# We're at a tagged commit - release build
|
||||
echo "📦 Building release version: $VERSION"
|
||||
docker build \
|
||||
--build-arg VERSION="$VERSION" \
|
||||
--build-arg IS_RELEASE="true" \
|
||||
-t skoszewski/jmespath-playground:$VERSION \
|
||||
-t skoszewski/jmespath-playground:latest .
|
||||
echo "✅ Built Docker images: skoszewski/jmespath-playground:$VERSION, skoszewski/jmespath-playground:latest"
|
||||
else
|
||||
# Development build
|
||||
PACKAGE_VERSION=$(grep '"version"' package.json | cut -d'"' -f4)
|
||||
DEV_VERSION="${PACKAGE_VERSION}-dev"
|
||||
echo "📦 Building development version: $DEV_VERSION"
|
||||
docker build \
|
||||
--build-arg VERSION="$DEV_VERSION" \
|
||||
--build-arg IS_RELEASE="false" \
|
||||
-t skoszewski/jmespath-playground:dev \
|
||||
-t skoszewski/jmespath-playground:latest .
|
||||
echo "✅ Built Docker images: skoszewski/jmespath-playground:dev, skoszewski/jmespath-playground:latest"
|
||||
fi
|
||||
else
|
||||
echo "💡 Docker not found. Container build is optional."
|
||||
echo " Install Docker if you want to build containers."
|
||||
@@ -42,8 +66,13 @@ fi
|
||||
echo "✅ Build completed successfully!"
|
||||
echo ""
|
||||
echo "To run the application:"
|
||||
echo " npm run serve # Serve production build locally"
|
||||
echo " docker run -p 3000:3000 jmespath-playground # Run container (if built)"
|
||||
echo " npm run server # Run integrated server locally"
|
||||
if command -v docker &> /dev/null; then
|
||||
echo " docker run -p 3000:3000 jmespath-playground # Run with Docker"
|
||||
VERSION=$(git tag --points-at HEAD 2>/dev/null | sed 's/^v//' | head -n 1)
|
||||
if [ -n "$VERSION" ]; then
|
||||
echo " docker run -p 3000:3000 skoszewski/jmespath-playground:$VERSION # Run release container"
|
||||
else
|
||||
echo " docker run -p 3000:3000 skoszewski/jmespath-playground:dev # Run dev container"
|
||||
fi
|
||||
echo " docker run -p 3000:3000 skoszewski/jmespath-playground:latest # Run latest container"
|
||||
fi
|
||||
@@ -4,37 +4,216 @@ const fs = require('fs');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
function showUsage() {
|
||||
console.log('Usage: node scripts/new-version.js <version>');
|
||||
console.log('Usage: node scripts/new-version.js <version> [--force] [-m|--message "commit message"]');
|
||||
console.log(' node scripts/new-version.js --check <version>');
|
||||
console.log('');
|
||||
console.log('Creates a new version by updating package.json, committing, and tagging.');
|
||||
console.log('Creates a new version by tagging the current commit.');
|
||||
console.log('');
|
||||
console.log('Options:');
|
||||
console.log(' --force Force version creation even with dirty repo or package.json mismatch');
|
||||
console.log(' --check Analyze repository status and report what would happen for specified version');
|
||||
console.log(' -m, --message TEXT Custom commit message (only used when commit is needed)');
|
||||
console.log('');
|
||||
console.log('Example:');
|
||||
console.log(' node scripts/new-version.js 1.2.0');
|
||||
console.log(' node scripts/new-version.js 2.0.0-beta.1');
|
||||
console.log(' node scripts/new-version.js 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.js --check 1.3.0');
|
||||
}
|
||||
|
||||
function performCheck(targetVersion) {
|
||||
console.log('🔍 Repository Analysis Report');
|
||||
console.log('============================');
|
||||
|
||||
try {
|
||||
// Read package.json
|
||||
const packagePath = './package.json';
|
||||
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
||||
const currentVersion = pkg.version;
|
||||
|
||||
console.log(`📦 Package.json version: ${currentVersion}`);
|
||||
|
||||
// Check repository status
|
||||
let isRepoDirty = false;
|
||||
let dirtyFiles = '';
|
||||
try {
|
||||
const status = execSync('git status --porcelain', { encoding: 'utf8' });
|
||||
isRepoDirty = status.trim() !== '';
|
||||
dirtyFiles = status.trim();
|
||||
} catch (error) {
|
||||
console.log('⚠️ Cannot determine git status');
|
||||
}
|
||||
|
||||
if (isRepoDirty) {
|
||||
console.log('🔄 Repository status: DIRTY');
|
||||
console.log(' Uncommitted changes:');
|
||||
dirtyFiles.split('\n').forEach(line => {
|
||||
if (line.trim()) console.log(` ${line}`);
|
||||
});
|
||||
} else {
|
||||
console.log('✅ Repository status: CLEAN');
|
||||
}
|
||||
|
||||
// Check current commit info
|
||||
try {
|
||||
const currentCommit = execSync('git rev-parse 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})`);
|
||||
|
||||
// Check if current commit is tagged
|
||||
const tagsOnHead = execSync('git tag --points-at HEAD', { encoding: 'utf8' }).trim();
|
||||
if (tagsOnHead) {
|
||||
console.log(`🏷️ Current commit tags: ${tagsOnHead.split('\n').join(', ')}`);
|
||||
} else {
|
||||
console.log('🏷️ Current commit: No tags');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('⚠️ Cannot determine commit info');
|
||||
}
|
||||
|
||||
// List recent tags
|
||||
try {
|
||||
const recentTags = execSync('git tag --sort=-version:refname | head -5', { encoding: 'utf8' }).trim();
|
||||
if (recentTags) {
|
||||
console.log('📋 Recent tags:');
|
||||
recentTags.split('\n').forEach(tag => {
|
||||
if (tag.trim()) console.log(` ${tag}`);
|
||||
});
|
||||
} else {
|
||||
console.log('📋 No tags found in repository');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('⚠️ Cannot list tags');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
|
||||
// Analysis for target version (if provided)
|
||||
if (targetVersion) {
|
||||
const tagName = `v${targetVersion}`;
|
||||
console.log(`🎯 Analysis for version ${targetVersion}:`);
|
||||
console.log('=====================================');
|
||||
|
||||
// Check if target tag exists
|
||||
try {
|
||||
const existingTags = execSync('git tag -l', { encoding: 'utf8' });
|
||||
const tagExists = existingTags.split('\n').includes(tagName);
|
||||
|
||||
if (tagExists) {
|
||||
console.log(`❌ Tag '${tagName}' already exists - CANNOT CREATE`);
|
||||
return;
|
||||
}
|
||||
console.log(`✅ Tag '${tagName}' available`);
|
||||
} catch (error) {
|
||||
console.log('⚠️ Cannot check tag availability');
|
||||
return;
|
||||
}
|
||||
|
||||
// Analyze what actions would be needed
|
||||
const packageJsonMatches = currentVersion === targetVersion;
|
||||
const needsPackageUpdate = !packageJsonMatches;
|
||||
const needsCommit = isRepoDirty || needsPackageUpdate;
|
||||
|
||||
console.log(`📝 Package.json: ${packageJsonMatches ? 'MATCHES' : `NEEDS UPDATE (${currentVersion} → ${targetVersion})`}`);
|
||||
|
||||
if (needsCommit) {
|
||||
console.log('⚡ Actions needed:');
|
||||
if (needsPackageUpdate) {
|
||||
console.log(' • Update package.json');
|
||||
}
|
||||
if (isRepoDirty) {
|
||||
console.log(' • Stage uncommitted changes');
|
||||
}
|
||||
console.log(' • Create commit');
|
||||
console.log(` • Create tag ${tagName}`);
|
||||
console.log('');
|
||||
console.log('📋 Commands that would work:');
|
||||
if (isRepoDirty || needsPackageUpdate) {
|
||||
console.log(` node scripts/new-version.js ${targetVersion} --force`);
|
||||
} else {
|
||||
console.log(` node scripts/new-version.js ${targetVersion}`);
|
||||
console.log(` node scripts/new-version.js ${targetVersion} --force`);
|
||||
}
|
||||
} else {
|
||||
console.log('⚡ Actions needed:');
|
||||
console.log(` • Create tag ${tagName} (no commit needed)`);
|
||||
console.log('');
|
||||
console.log('📋 Commands that would work:');
|
||||
console.log(` node scripts/new-version.js ${targetVersion}`);
|
||||
console.log(` node scripts/new-version.js ${targetVersion} --force`);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('🚦 Default mode requirements:');
|
||||
if (isRepoDirty) {
|
||||
console.log(' ❌ Repository must be clean (currently dirty)');
|
||||
} else {
|
||||
console.log(' ✅ Repository is clean');
|
||||
}
|
||||
if (!packageJsonMatches) {
|
||||
console.log(` ❌ Package.json must match version (currently ${currentVersion})`);
|
||||
} else {
|
||||
console.log(' ✅ Package.json version matches');
|
||||
}
|
||||
|
||||
} else {
|
||||
// This should never happen since version is now required
|
||||
console.error('Internal error: No version provided to performCheck');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error during analysis:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
// Parse command line arguments
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.length === 0 || args[0] === '-h' || args[0] === '--help') {
|
||||
if (args.length === 0 || args.includes('-h') || args.includes('--help')) {
|
||||
showUsage();
|
||||
process.exit(args.length === 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
if (args.length !== 1) {
|
||||
console.error('Error: Exactly one version argument required');
|
||||
const isCheck = args.includes('--check');
|
||||
const isForce = args.includes('--force');
|
||||
|
||||
// Parse custom commit message
|
||||
let customMessage = null;
|
||||
const messageIndex = args.findIndex(arg => arg === '-m' || arg === '--message');
|
||||
if (messageIndex !== -1 && messageIndex + 1 < args.length) {
|
||||
customMessage = args[messageIndex + 1];
|
||||
}
|
||||
|
||||
let newVersion;
|
||||
if (isCheck) {
|
||||
// For --check, version is required
|
||||
newVersion = args.find(arg => !arg.startsWith('--') && arg !== '-m' && arg !== customMessage);
|
||||
if (!newVersion) {
|
||||
console.error('Error: Version argument required for --check');
|
||||
showUsage();
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
// For normal operation, version is required
|
||||
newVersion = args.find(arg => !arg.startsWith('--') && arg !== '-m' && arg !== customMessage);
|
||||
if (!newVersion) {
|
||||
}
|
||||
}
|
||||
|
||||
if (isCheck) {
|
||||
performCheck(newVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
const newVersion = args[0];
|
||||
const tagName = `v${newVersion}`;
|
||||
|
||||
console.log(`🏷️ Creating new version: ${newVersion}`);
|
||||
console.log(`🏷️ Creating new version: ${newVersion}${isForce ? ' (forced)' : ''}`);
|
||||
|
||||
try {
|
||||
// Check if tag already exists
|
||||
// 1. Check if tag already exists - Always ERROR
|
||||
try {
|
||||
const existingTags = execSync('git tag -l', { encoding: 'utf8' });
|
||||
if (existingTags.split('\n').includes(tagName)) {
|
||||
@@ -46,34 +225,63 @@ function main() {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if working directory is clean
|
||||
// 2. Check repository status
|
||||
let isRepoDirty = false;
|
||||
try {
|
||||
const status = execSync('git status --porcelain', { encoding: 'utf8' });
|
||||
if (status.trim()) {
|
||||
console.error('❌ Error: Working directory has uncommitted changes');
|
||||
console.error('Please commit or stash your changes first');
|
||||
process.exit(1);
|
||||
}
|
||||
isRepoDirty = status.trim() !== '';
|
||||
} catch (error) {
|
||||
console.error('❌ Error: Failed to check git status');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Read and update package.json
|
||||
// 3. Check package.json version
|
||||
const packagePath = './package.json';
|
||||
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
||||
const oldVersion = pkg.version;
|
||||
const currentVersion = pkg.version;
|
||||
const packageJsonMatches = currentVersion === newVersion;
|
||||
|
||||
// 4. Determine what action is needed
|
||||
const needsPackageUpdate = !packageJsonMatches;
|
||||
const needsCommit = isRepoDirty || needsPackageUpdate;
|
||||
|
||||
// 5. Check if force is required
|
||||
if (!isForce) {
|
||||
if (isRepoDirty) {
|
||||
console.error('❌ Error: Working directory has uncommitted changes');
|
||||
console.error('Please commit your changes first or use --force');
|
||||
process.exit(1);
|
||||
}
|
||||
if (needsPackageUpdate) {
|
||||
console.error(`❌ Error: Package.json version is ${currentVersion}, requested ${newVersion}`);
|
||||
console.error('Use --force to update package.json');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Execute the versioning
|
||||
if (needsCommit) {
|
||||
console.log(`📦 Needs commit: ${needsPackageUpdate ? 'package.json update' : ''}${needsPackageUpdate && isRepoDirty ? ' + ' : ''}${isRepoDirty ? 'uncommitted changes' : ''}`);
|
||||
|
||||
// Update package.json if needed
|
||||
if (needsPackageUpdate) {
|
||||
pkg.version = newVersion;
|
||||
fs.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + '\n');
|
||||
console.log(`📦 Updated package.json: ${oldVersion} → ${newVersion}`);
|
||||
console.log(`📝 Updated package.json: ${currentVersion} → ${newVersion}`);
|
||||
}
|
||||
|
||||
// Commit the package.json change
|
||||
execSync('git add package.json', { stdio: 'inherit' });
|
||||
execSync(`git commit -m "Bump version to ${newVersion}"`, { stdio: 'inherit' });
|
||||
console.log(`✅ Committed version change`);
|
||||
// Stage all changes
|
||||
execSync('git add .', { stdio: 'inherit' });
|
||||
|
||||
// Tag the commit
|
||||
// Commit
|
||||
const commitMessage = customMessage || (needsPackageUpdate ? `Version ${newVersion}` : `Prepare for version ${newVersion}`);
|
||||
execSync(`git commit -m "${commitMessage}"`, { stdio: 'inherit' });
|
||||
console.log(`✅ Committed changes`);
|
||||
} else {
|
||||
console.log(`✅ Repository clean, package.json matches - tagging current commit`);
|
||||
}
|
||||
|
||||
// 7. Tag the commit
|
||||
execSync(`git tag ${tagName}`, { stdio: 'inherit' });
|
||||
console.log(`🏷️ Created tag: ${tagName}`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user