diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..7d99ea0 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @furkando @NGabuaeva @EdiOanceaV2 @sinantalhakosar @rturtu @hikmet-demir @Matteoverzotti @robertbarbu27 @felipe-lighter diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..2d04a37 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ +## Proposed Change + +_Describe what this pull request does?_ + +## To-Do + +_Add to-do items here_ + +- [ ] Does it need backend deployment? +- [ ] Does it need confirmation on calculations? + +## Screenshot + +_Add screenshots or short video_ diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..0a3882d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,24 @@ +version: 2 +updates: +- package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + groups: + patch-updates: + applies-to: version-updates + patterns: ['*'] + update-types: + - "patch" + open-pull-requests-limit: 1 + target-branch: "main" + pull-request-branch-name: + separator: "-" + commit-message: + prefix: "[dependabot] Patch update: " + ignore: + - dependency-name: "react" + - dependency-name: "react-native" + # For all packages, ignore all minor and major updates + - dependency-name: "*" + update-types: ["version-update:semver-major", "version-update:semver-minor"] diff --git a/.github/workflows/cleanup-prereleases.yml b/.github/workflows/cleanup-prereleases.yml new file mode 100644 index 0000000..fcc0caf --- /dev/null +++ b/.github/workflows/cleanup-prereleases.yml @@ -0,0 +1,100 @@ +name: Cleanup Prereleases + +on: + pull_request: + types: [closed] + branches: [main] + +jobs: + cleanup: + runs-on: ubuntu-latest + if: github.event.pull_request.merged == true + permissions: + contents: write + packages: write + pull-requests: write + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set NPM_TOKEN for GitHub Packages + run: echo "NPM_TOKEN=${{ secrets.GH_PACKAGE_TOKEN }}" >> $GITHUB_ENV + + # Setup Node.js and npm + - uses: actions/setup-node@v4 + with: + node-version: "22.19.0" + registry-url: 'https://npm.pkg.github.com' + scope: '@elliottech' + + # Get PR information + - name: Get PR information + id: pr_info + run: | + PR_NUMBER=${{ github.event.number }} + BRANCH_NAME="${{ github.head_ref }}" + + # Clean branch name for npm (same logic as prerelease workflow) + CLEAN_BRANCH_NAME=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g') + + echo "PR Number: $PR_NUMBER" + echo "Branch Name: $BRANCH_NAME" + echo "Clean Branch Name: $CLEAN_BRANCH_NAME" + + echo "clean_branch_name=$CLEAN_BRANCH_NAME" >> $GITHUB_OUTPUT + echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT + + # List and unpublish prerelease versions + - name: Cleanup prerelease versions + run: | + CLEAN_BRANCH_NAME="${{ steps.pr_info.outputs.clean_branch_name }}" + + echo "Cleaning up prerelease versions for branch: $CLEAN_BRANCH_NAME" + + # List all versions with the branch tag + echo "Listing versions with tag: $CLEAN_BRANCH_NAME" + npm view @elliottech/react-native-kline-view@$CLEAN_BRANCH_NAME || echo "No versions found with tag $CLEAN_BRANCH_NAME" + + # Note: npm unpublish by tag is not reliable, so we'll list what would be cleaned up + echo "Note: npm unpublish by tag is not reliable" + echo "Manual cleanup may be needed for tag: $CLEAN_BRANCH_NAME" + + # Also try to unpublish specific prerelease versions that might exist + # Get current version from package.json to construct prerelease version + CURRENT_VERSION=$(node -p "require('./package.json').version") + PRERELEASE_VERSION="${CURRENT_VERSION}-${CLEAN_BRANCH_NAME}.${{ steps.pr_info.outputs.pr_number }}" + + echo "Attempting to unpublish specific version: $PRERELEASE_VERSION" + npm unpublish @elliottech/react-native-kline-view@$PRERELEASE_VERSION || echo "Version $PRERELEASE_VERSION not found or already unpublished" + + echo "Cleanup completed for branch: $CLEAN_BRANCH_NAME" + env: + NODE_AUTH_TOKEN: ${{ secrets.GH_PACKAGE_TOKEN }} + + # Comment on the merged PR + - name: Comment on merged PR + uses: actions/github-script@v7 + with: + script: | + const cleanBranchName = '${{ steps.pr_info.outputs.clean_branch_name }}'; + const prNumber = ${{ steps.pr_info.outputs.pr_number }}; + + const comment = `## ๐Ÿงน Prerelease Cleanup Complete + + All prerelease versions for branch \`${cleanBranchName}\` have been cleaned up. + + The following actions were performed: + - โœ… Unpublished all versions tagged with \`${cleanBranchName}\` + - โœ… Removed prerelease packages from npm registry + + --- + *This cleanup was performed automatically after PR merge.*`; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: comment + }); diff --git a/.github/workflows/manual-cleanup.yml b/.github/workflows/manual-cleanup.yml new file mode 100644 index 0000000..e7d0fcc --- /dev/null +++ b/.github/workflows/manual-cleanup.yml @@ -0,0 +1,84 @@ +name: Manual Prerelease Cleanup + +on: + workflow_dispatch: + inputs: + branch_name: + description: 'Branch name to clean up (without special characters)' + required: true + type: string + pr_number: + description: 'PR number (optional, for specific version cleanup)' + required: false + type: string + +jobs: + manual-cleanup: + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set NPM_TOKEN for GitHub Packages + run: echo "NPM_TOKEN=${{ secrets.GH_PACKAGE_TOKEN }}" >> $GITHUB_ENV + + # Setup Node.js and npm + - uses: actions/setup-node@v4 + with: + node-version: "22.19.0" + registry-url: 'https://npm.pkg.github.com' + scope: '@elliottech' + + # Clean branch name + - name: Clean branch name + id: clean_name + run: | + BRANCH_NAME="${{ github.event.inputs.branch_name }}" + CLEAN_BRANCH_NAME=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g') + echo "Original branch name: $BRANCH_NAME" + echo "Clean branch name: $CLEAN_BRANCH_NAME" + echo "clean_branch_name=$CLEAN_BRANCH_NAME" >> $GITHUB_OUTPUT + + # List and cleanup prerelease versions + - name: List and cleanup prerelease versions + run: | + CLEAN_BRANCH_NAME="${{ steps.clean_name.outputs.clean_branch_name }}" + PR_NUMBER="${{ github.event.inputs.pr_number }}" + + echo "Cleaning up prerelease versions for branch: $CLEAN_BRANCH_NAME" + + # List all versions with the branch tag + echo "=== Listing versions with tag: $CLEAN_BRANCH_NAME ===" + npm view @elliottech/react-native-kline-view@$CLEAN_BRANCH_NAME || echo "No versions found with tag $CLEAN_BRANCH_NAME" + + # Unpublish all versions with this tag + echo "=== Unpublishing versions with tag: $CLEAN_BRANCH_NAME ===" + npm unpublish @elliottech/react-native-kline-view@$CLEAN_BRANCH_NAME || echo "No versions to unpublish with tag $CLEAN_BRANCH_NAME" + + # If PR number is provided, also try to unpublish specific version + if [ -n "$PR_NUMBER" ]; then + CURRENT_VERSION=$(node -p "require('./package.json').version") + PRERELEASE_VERSION="${CURRENT_VERSION}-${CLEAN_BRANCH_NAME}.${PR_NUMBER}" + + echo "=== Attempting to unpublish specific version: $PRERELEASE_VERSION ===" + npm unpublish @elliottech/react-native-kline-view@$PRERELEASE_VERSION || echo "Version $PRERELEASE_VERSION not found or already unpublished" + fi + + echo "=== Cleanup completed for branch: $CLEAN_BRANCH_NAME ===" + env: + NODE_AUTH_TOKEN: ${{ secrets.GH_PACKAGE_TOKEN }} + + # Show cleanup summary + - name: Show cleanup summary + run: | + echo "## ๐Ÿงน Manual Cleanup Summary" + echo "**Branch:** ${{ github.event.inputs.branch_name }}" + echo "**Clean Branch Name:** ${{ steps.clean_name.outputs.clean_branch_name }}" + echo "**PR Number:** ${{ github.event.inputs.pr_number || 'Not specified' }}" + echo "" + echo "โœ… Cleanup completed successfully!" diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml new file mode 100644 index 0000000..9951be5 --- /dev/null +++ b/.github/workflows/prerelease.yml @@ -0,0 +1,207 @@ +name: PR Prerelease Publishing + +on: + pull_request: + types: [opened, synchronize, reopened] + branches: [main] + +jobs: + prerelease: + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + pull-requests: write + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set NPM_TOKEN for GitHub Packages + run: echo "NPM_TOKEN=${{ secrets.GH_PACKAGE_TOKEN }}" >> $GITHUB_ENV + + # Setup Node.js and npm + - uses: actions/setup-node@v4 + with: + node-version: "22.19.0" + registry-url: 'https://npm.pkg.github.com' + scope: '@elliottech' + + # Add initial "In Progress" comment immediately + - name: Add In Progress Comment + uses: actions/github-script@v7 + with: + script: | + const prNumber = ${{ github.event.number }}; + + const inProgressComment = `## ๐Ÿšง Prerelease In Progress + + Building and publishing prerelease version... + + --- + *This comment will be updated when publishing is complete.*`; + + // Check if comment already exists + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber + }); + + const existingComment = comments.data.find(comment => + comment.user.type === 'Bot' && + (comment.body.includes('๐Ÿšง Prerelease In Progress') || comment.body.includes('๐Ÿš€ Prerelease Published')) + ); + + if (existingComment) { + // Update existing comment + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existingComment.id, + body: inProgressComment + }); + } else { + // Create new comment + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: inProgressComment + }); + } + + - run: yarn install --frozen-lockfile + + # Generate prerelease version + - name: Generate prerelease version + id: version + run: | + # Get PR number, branch name, and actor + PR_NUMBER=${{ github.event.number }} + BRANCH_NAME="${{ github.head_ref }}" + ACTOR="${{ github.actor }}" + + # Clean branch name for npm (remove special characters) + CLEAN_BRANCH_NAME=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g') + + # Clean actor name for npm (remove special characters) + CLEAN_ACTOR=$(echo "$ACTOR" | sed 's/[^a-zA-Z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g') + + # Get commit SHA (first 7 characters) for uniqueness + + COMMIT_SHA=$(echo "${{ github.event.pull_request.head.sha }}" | cut -c1-7) + + # Create semver-compatible version: 0.PR_NUMBER.0-ACTOR.COMMIT_SHA.BRANCH_NAME + # This ensures it's always less than 1.0.0 and includes all our info + PRERELEASE_VERSION="0.${PR_NUMBER}.0-${CLEAN_ACTOR}.${COMMIT_SHA}.${CLEAN_BRANCH_NAME}" + + echo "PR Number: $PR_NUMBER" + echo "Branch Name: $BRANCH_NAME" + echo "Actor: $ACTOR" + echo "Clean Branch Name: $CLEAN_BRANCH_NAME" + echo "Clean Actor: $CLEAN_ACTOR" + echo "Commit SHA: $COMMIT_SHA" + echo "Prerelease Version: $PRERELEASE_VERSION" + + echo "prerelease_version=$PRERELEASE_VERSION" >> $GITHUB_OUTPUT + echo "clean_branch_name=$CLEAN_BRANCH_NAME" >> $GITHUB_OUTPUT + echo "clean_actor=$CLEAN_ACTOR" >> $GITHUB_OUTPUT + echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT + + # Create temporary package.json with custom version + - name: Create temporary package.json + run: | + # Create a temporary package.json with our custom version + node -e " + const fs = require('fs'); + const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')); + packageJson.version = '${{ steps.version.outputs.prerelease_version }}'; + fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2) + '\n'); + console.log('Created temporary package.json with version:', packageJson.version); + " + + # Clean up previous prereleases for this PR + - name: Clean up previous prereleases + run: | + CLEAN_BRANCH_NAME="${{ steps.version.outputs.clean_branch_name }}" + + echo "Cleaning up previous prereleases for PR #${{ steps.version.outputs.pr_number }}" + + # List all versions with this tag to find previous ones from this PR + echo "Listing existing versions with tag: $CLEAN_BRANCH_NAME" + npm view @elliottech/react-native-kline-view@$CLEAN_BRANCH_NAME || echo "No existing versions found" + + # Note: npm unpublish by tag is not reliable + echo "Note: npm unpublish by tag is not reliable" + echo "Previous versions with tag $CLEAN_BRANCH_NAME may need manual cleanup" + + echo "Cleanup completed for PR #${{ steps.version.outputs.pr_number }}" + env: + NPM_TOKEN: ${{ secrets.GH_PACKAGE_TOKEN }} + + # Publish prerelease + - name: Publish prerelease + run: | + npm publish --tag ${{ steps.version.outputs.clean_branch_name }} + env: + NPM_TOKEN: ${{ secrets.GH_PACKAGE_TOKEN }} + + # Restore original package.json + - name: Restore original package.json + run: | + git checkout package.json + echo "Restored original package.json" + + # Comment on PR with installation instructions + - name: Update Comment with Results + uses: actions/github-script@v7 + with: + script: | + const prereleaseVersion = '${{ steps.version.outputs.prerelease_version }}'; + const cleanBranchName = '${{ steps.version.outputs.clean_branch_name }}'; + const prNumber = ${{ steps.version.outputs.pr_number }}; + + const comment = `## ๐Ÿš€ Prerelease Published + + **Version:** \`${prereleaseVersion}\` + **Tag:** \`${cleanBranchName}\` + + ### Update package.json: + \`\`\`json + "@elliottech/react-native-kline-view": "${prereleaseVersion}" + \`\`\` + + --- + *Previous prereleases for this PR have been cleaned up. This prerelease will be automatically cleaned up when the PR is merged.*`; + + // Check if "In Progress" comment exists and update it + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber + }); + + const existingComment = comments.data.find(comment => + comment.user.type === 'Bot' && + (comment.body.includes('๐Ÿšง Prerelease In Progress') || comment.body.includes('๐Ÿš€ Prerelease Published')) + ); + + if (existingComment) { + // Update existing comment (either "In Progress" or "Published") + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existingComment.id, + body: comment + }); + } else { + // Fallback: create new comment if somehow no existing comment found + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: comment + }); + } diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..437207a --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,72 @@ +name: Publish package to GitHub Packages +on: + push: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 # Need full history for git tags + + - name: Set NPM_TOKEN for GitHub Packages + run: echo "NPM_TOKEN=${{ secrets.GH_PACKAGE_TOKEN }}" >> $GITHUB_ENV + + # Setup .npmrc file to publish to GitHub Packages + - uses: actions/setup-node@v4 + with: + node-version: "22.19.0" + registry-url: 'https://npm.pkg.github.com' + # Defaults to the user or organization that owns the workflow file + scope: '@elliottech' + + - run: yarn install --frozen-lockfile + + # Get next version based on existing tags + - name: Calculate next version + id: version + run: | + # Get the latest tag - fail if none exist + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null) + + if [ -z "$LATEST_TAG" ]; then + echo "โŒ No Git tags found! Please create an initial tag first." + echo "Example: git tag v1.0.0 && git push origin v1.0.0" + exit 1 + fi + + echo "Latest tag: $LATEST_TAG" + VERSION=${LATEST_TAG#v} # Remove 'v' prefix if present + echo "Current version: $VERSION" + + # Split version into parts + IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION" + + # Increment patch version + NEW_PATCH=$((PATCH + 1)) + NEW_VERSION="$MAJOR.$MINOR.$NEW_PATCH" + + echo "New version: $NEW_VERSION" + echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "tag=v$NEW_VERSION" >> $GITHUB_OUTPUT + # Update package.json with new version + - name: Update package.json + run: | + yarn version --new-version ${{ steps.version.outputs.version }} --no-git-tag-version + echo "Updated package.json to version: $(node -p "require('./package.json').version")" + # Create and push git tag + - name: Create and push tag + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git tag ${{ steps.version.outputs.tag }} + git push origin ${{ steps.version.outputs.tag }} + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.GH_PACKAGE_TOKEN }} diff --git a/.gitignore b/.gitignore index 9cadbfe..2f73aed 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,6 @@ local.properties buck-out/ \.buckd/ *.keystore - \ No newline at end of file + +# Environment +.env diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..3121f5c --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +@elliottech:registry=https://npm.pkg.github.com +//npm.pkg.github.com/:_authToken=${NPM_TOKEN} diff --git a/package.json b/package.json index 4983b90..9a6d674 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,26 @@ { - "name": "react-native-kline-view", + "name": "@elliottech/react-native-kline-view", "version": "1.0.1", - "description": "", + "description": "React Native Kline chart component with native Android and iOS implementations", "main": "index.js", + "repository": "git@github.com:elliottech/react-native-kline-view.git", + "author": "elliottech", + "publishConfig": { + "registry": "https://npm.pkg.github.com/@elliottech" + }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "prepublishOnly": "echo \"Ready to publish\"" }, "keywords": [ - "react-native" + "react-native", + "kline", + "chart", + "candlestick" ], - "author": "", - "license": "", + "license": "MIT", "peerDependencies": { + "react": "*", "react-native": ">=0.66.0" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"