From 39149c950e7bb30707a08e1ff5204e283a4ed94c Mon Sep 17 00:00:00 2001 From: NX1X Date: Sat, 25 Jul 2026 11:23:38 +0300 Subject: [PATCH] feat: add release workflow, footer GitHub link with license notice - .github/workflows/release.yml: on v* tag push or manual dispatch, creates the GitHub Release using the matching CHANGELOG.md section as notes. SHA-pinned checkout, contents:read default with contents:write on the release job only, tag input validated - scripts/release.sh reworked for the PR-based flow: validates main is clean and in sync, requires a CHANGELOG section for the current package.json version, then tags and pushes; the workflow creates the Release (old script pushed to main directly, double-wrote the changelog, and linked a stale repo URL) - Footer: GitHub logo icon linking to the repository and a bilingual Apache License 2.0 notice --- .github/workflows/release.yml | 65 ++++++++++++++ CHANGELOG.md | 3 + public/app.js | 3 + public/index.html | 9 +- public/style.css | 21 +++++ scripts/release.sh | 158 +++++++--------------------------- 6 files changed, 131 insertions(+), 128 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..eb53e55 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,65 @@ +name: Release + +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + tag: + description: 'Existing tag to release (e.g. v1.4.0)' + required: true + type: string + +permissions: + contents: read + +jobs: + release: + name: Create GitHub Release + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Determine tag + id: tag + env: + INPUT_TAG: ${{ inputs.tag }} + REF_NAME: ${{ github.ref_name }} + run: | + TAG="${INPUT_TAG:-$REF_NAME}" + case "$TAG" in + v[0-9]*.[0-9]*.[0-9]*) ;; + *) echo "Not a release tag: $TAG"; exit 1 ;; + esac + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + + - name: Checkout tag + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: ${{ steps.tag.outputs.tag }} + + - name: Extract changelog section + env: + TAG: ${{ steps.tag.outputs.tag }} + run: | + VERSION="${TAG#v}" + awk -v ver="$VERSION" ' + index($0, "## [" ver "]") == 1 { found = 1; next } + found && /^## \[/ { exit } + found { print } + ' CHANGELOG.md > release-notes.md + if [ ! -s release-notes.md ]; then + echo "No CHANGELOG.md section found for version $VERSION" + exit 1 + fi + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.tag.outputs.tag }} + run: | + gh release create "$TAG" \ + --verify-tag \ + --title "$TAG" \ + --notes-file release-notes.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 49d983f..b1c4931 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Excel exports of RTL documents open with a right-to-left sheet view, and the data preview lays out right-to-left for RTL documents - "Include Headers" now adds an Excel autofilter to the header row, making the exported sheet filterable - Fully bilingual status messages: progress, errors, file info, page count, and column labels now follow the selected language +- Footer now shows the GitHub logo linking to the source repository and an Apache License 2.0 notice (bilingual) +- Release workflow (`.github/workflows/release.yml`): pushing a `v*` tag (or a manual dispatch) creates the GitHub Release with the matching CHANGELOG section as notes ### Changed @@ -24,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Cleanup options (Skip Empty Rows, Merge Fragments, Auto-detect Columns) are now non-destructive: unchecking an option restores the original extracted data - Turnstile verification is required once per session instead of once per file - "Hebrew/Arabic RTL Support" is now enabled by default (it only activates on documents detected as RTL) +- `scripts/release.sh` reworked for the PR-based flow: it now only validates and pushes the version tag (the version bump and CHANGELOG entry come from the PR, the GitHub Release comes from the release workflow) ### Fixed diff --git a/public/app.js b/public/app.js index 58e94ec..7ac21b1 100755 --- a/public/app.js +++ b/public/app.js @@ -1135,6 +1135,7 @@ const translations = { footerLink2: "NX1X Lab", footerLink3: "GitHub", footerPrivacy: "Privacy: Your PDFs are processed entirely in your browser. No files are uploaded to any server. Anonymous usage analytics via Cloudflare Analytics.", + footerLicense: 'Open source under the Apache License 2.0', footerCopyright: `© ${currentYear} NX1X.`, statusVerify: "Please complete the security verification below to proceed.", statusLoading: "Loading PDF file...", @@ -1194,6 +1195,7 @@ const translations = { footerLink2: "NX1X Lab", footerLink3: "GitHub", footerPrivacy: "פרטיות: קבצי ה-PDF שלכם מעובדים לחלוטין בדפדפן שלכם. לא מועלים קבצים לשום שרת. אנליטיקה אנונימית בסיסית דרך Cloudflare Analytics.", + footerLicense: 'קוד פתוח תחת רישיון Apache 2.0', footerCopyright: `© ${currentYear} NX1X.`, statusVerify: "אנא השלימו את אימות האבטחה למטה כדי להמשיך.", statusLoading: "טוען קובץ PDF...", @@ -1289,6 +1291,7 @@ function updateLanguage() { updateElement('footerLink2', lang.footerLink2); updateElement('footerLink3', lang.footerLink3); updateElement('footerPrivacy', lang.footerPrivacy, true); + updateElement('footerLicense', lang.footerLicense, true); updateElement('footerCopyright', lang.footerCopyright); const customRangeInput = document.getElementById('customRange'); diff --git a/public/index.html b/public/index.html index 44f882a..818a2e8 100755 --- a/public/index.html +++ b/public/index.html @@ -339,13 +339,20 @@

Found EasyConvert helpful?

+ + diff --git a/public/style.css b/public/style.css index cabe51d..2bd2a93 100755 --- a/public/style.css +++ b/public/style.css @@ -684,6 +684,27 @@ body { margin-bottom: 20px; } +.footer-github-link { + display: inline-flex; + align-items: center; + gap: 6px; +} + +.footer-github-icon { + flex-shrink: 0; +} + +.footer-license { + font-size: 0.85rem; + opacity: 0.8; + margin-bottom: 12px; +} + +.footer-license a { + color: white; + text-decoration: underline; +} + .footer-copyright { font-size: 0.85rem; opacity: 0.7; diff --git a/scripts/release.sh b/scripts/release.sh index 6edc0df..8c271a4 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -1,145 +1,49 @@ -#!/bin/bash +#!/usr/bin/env bash -# EasyConvert Release Script -# Automates version bumping and release process +# EasyConvert release script. +# +# The version bump and CHANGELOG entry land on main through a normal PR +# (package.json, README badge, sw.js CACHE_NAME, CHANGELOG.md). This script +# then tags that version and pushes the tag; the GitHub Release itself is +# created by .github/workflows/release.yml, which uses the matching +# CHANGELOG.md section as the release notes. -set -e # Exit on any error +set -euo pipefail -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -BLUE='\033[0;34m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color +REPO_URL="https://github.com/NX1X/EasyConvert" -# Function to print colored output -print_status() { - echo -e "${BLUE}[INFO]${NC} $1" -} +fail() { echo "ERROR: $1" >&2; exit 1; } -print_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" -} +git rev-parse --git-dir > /dev/null 2>&1 || fail "Not in a git repository." -print_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" -} +BRANCH=$(git rev-parse --abbrev-ref HEAD) +[ "$BRANCH" = "main" ] || fail "Releases are tagged from main (currently on '$BRANCH')." -print_error() { - echo -e "${RED}[ERROR]${NC} $1" -} +[ -z "$(git status --porcelain)" ] || fail "Working tree is not clean. Commit or stash first." -# Check if we're in a git repository -if ! git rev-parse --git-dir > /dev/null 2>&1; then - print_error "Not in a git repository!" - exit 1 -fi - -# Check if there are uncommitted changes -if [[ -n $(git status --porcelain) ]]; then - print_warning "You have uncommitted changes. Please commit or stash them first." - git status --short - exit 1 -fi - -# Parse arguments -if [[ $# -lt 1 ]]; then - echo "Usage: $0 [release-notes]" - echo "" - echo "Examples:" - echo " $0 patch \"Fixed table detection bug\"" - echo " $0 minor \"Added new export format\"" - echo " $0 major \"Complete UI redesign\"" - echo " $0 1.2.3 \"Custom version with release notes\"" - exit 1 -fi +git fetch origin main --tags +[ "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)" ] || \ + fail "Local main is not in sync with origin/main. Pull or push first." -BUMP_TYPE=$1 -RELEASE_NOTES=${2:-"Version bump"} +VERSION=$(node -p "require('./package.json').version") +TAG="v$VERSION" -# Get current version from package.json -CURRENT_VERSION=$(node -p "require('./package.json').version") -print_status "Current version: $CURRENT_VERSION" +grep -q "^## \[$VERSION\]" CHANGELOG.md || \ + fail "CHANGELOG.md has no '## [$VERSION]' section. Add it before releasing." -# Calculate new version -if [[ $BUMP_TYPE =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - # Custom version provided - NEW_VERSION=$BUMP_TYPE -else - # Calculate based on bump type - IFS='.' read -ra VERSION_PARTS <<< "$CURRENT_VERSION" - MAJOR=${VERSION_PARTS[0]} - MINOR=${VERSION_PARTS[1]} - PATCH=${VERSION_PARTS[2]} - - case $BUMP_TYPE in - "patch") - PATCH=$((PATCH + 1)) - ;; - "minor") - MINOR=$((MINOR + 1)) - PATCH=0 - ;; - "major") - MAJOR=$((MAJOR + 1)) - MINOR=0 - PATCH=0 - ;; - *) - print_error "Invalid bump type: $BUMP_TYPE" - exit 1 - ;; - esac - - NEW_VERSION="$MAJOR.$MINOR.$PATCH" +if git rev-parse "$TAG" > /dev/null 2>&1; then + fail "Tag $TAG already exists." fi -print_status "New version: $NEW_VERSION" - -# Confirm the release -echo "" -print_warning "About to release version $NEW_VERSION" -print_status "Release notes: $RELEASE_NOTES" -echo "" +echo "About to tag and push $TAG (version from package.json)." read -p "Continue? (y/N): " -n 1 -r echo "" -if [[ ! $REPLY =~ ^[Yy]$ ]]; then - print_status "Release cancelled." - exit 0 -fi - -# Update version using Node.js script -print_status "Updating version files..." -if [[ -f "scripts/update-version.js" ]]; then - node scripts/update-version.js "$NEW_VERSION" "$RELEASE_NOTES" -else - print_error "Version update script not found!" - exit 1 -fi - -# Commit changes -print_status "Committing version changes..." -git add . -git commit -m "Release v$NEW_VERSION - -$RELEASE_NOTES" - -# Create and push tag -print_status "Creating git tag v$NEW_VERSION..." -git tag -a "v$NEW_VERSION" -m "Release v$NEW_VERSION - -$RELEASE_NOTES" - -# Push changes and tags -print_status "Pushing to remote repository..." -git push origin main -git push origin "v$NEW_VERSION" +[[ $REPLY =~ ^[Yy]$ ]] || { echo "Cancelled."; exit 0; } -print_success "Successfully released version $NEW_VERSION!" -print_status "🎉 Release completed! Version $NEW_VERSION is now live." -print_status "📝 Changelog updated with release notes" -print_status "🏷️ Git tag v$NEW_VERSION created and pushed" -print_status "🚀 All changes pushed to remote repository" +git tag -a "$TAG" -m "Release $TAG" +git push origin "$TAG" echo "" -print_status "View your release at: https://github.com/nx1xlab/easyconvert/releases/tag/v$NEW_VERSION" \ No newline at end of file +echo "Tag $TAG pushed. The release workflow is creating the GitHub Release:" +echo " $REPO_URL/actions/workflows/release.yml" +echo " $REPO_URL/releases/tag/$TAG"