diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..c2f2ea8 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,149 @@ +# GitHub Actions Workflows + +## NPM Publish Workflow + +This workflow automates the process of publishing packages from this monorepo to NPM. + +### Prerequisites + +Before using this workflow, ensure you have set up the following: + +1. **NPM Token**: Add your NPM access token as a GitHub secret + - Go to: Repository Settings → Secrets and variables → Actions + - Create a new secret named `NPM_TOKEN` + - Get your token from: https://www.npmjs.com/settings/[your-username]/tokens + +### How to Use + +1. **Navigate to Actions** + - Go to the "Actions" tab in your GitHub repository + - Select "NPM Publish and Release" workflow + +2. **Run Workflow** + - Click "Run workflow" button + - Fill in the required parameters: + - **Version bump type**: Choose `major`, `minor`, or `patch` + - **Packages**: Enter `all` to publish all packages, or specify packages (e.g., `parser,vue`) + - **Changelog**: Provide detailed release notes + +3. **Monitor Progress** + - The workflow will: + - Validate inputs + - Install dependencies + - Run linting and type checking + - Bump package versions + - Generate changelogs + - Build all packages + - Run tests + - Publish to NPM + - Create GitHub release + - Commit version changes + +### Workflow Parameters + +#### Version Bump Type + +- `major`: Breaking changes (1.0.0 → 2.0.0) +- `minor`: New features (1.0.0 → 1.1.0) +- `patch`: Bug fixes (1.0.0 → 1.0.1) + +#### Packages to Publish + +- `all`: Publish all packages in the monorepo +- `parser`: Only publish @markdown-next/parser +- `vue`: Only publish @markdown-next/vue +- `parser,vue`: Publish multiple specific packages (comma-separated) + +#### Changelog + +Required field describing what changed in this release. This will be added to: + +- Each package's CHANGELOG.md file +- GitHub release notes +- Git commit message + +### Example Usage + +**Publishing all packages with a patch version:** + +``` +Version bump type: patch +Packages: all +Changelog: +- Fixed parsing bug in code blocks +- Improved Vue component performance +- Updated dependencies +``` + +**Publishing only the parser package:** + +``` +Version bump type: minor +Packages: parser +Changelog: +- Added support for custom markdown extensions +- Enhanced error handling +``` + +### What Gets Published + +The workflow publishes only the `packages/*` directories to NPM: + +- `@markdown-next/parser` +- `@markdown-next/vue` + +The `app/*` directories (like `markdown-next-docs`) are not published as they are marked as private. + +### Automatic Prerelease Detection + +If the version contains `alpha` or `beta`, the GitHub release will automatically be marked as a prerelease. + +### Troubleshooting + +**Workflow fails at "Publish packages to NPM":** + +- Verify your `NPM_TOKEN` secret is correctly set +- Ensure the token has publish permissions +- Check if the package version already exists on NPM + +**Type checking fails:** + +- Fix type errors locally first +- Run `pnpm typecheck` to verify + +**Tests fail:** + +- Run `pnpm test` locally to identify issues +- Fix failing tests before publishing + +**Git push fails:** + +- Ensure the GitHub token has write permissions +- Check branch protection rules + +### Post-Release + +After successful publishing: + +1. Version bumps are committed to the repository +2. CHANGELOG.md files are updated for each package +3. A GitHub release is created with release notes +4. Packages are available on NPM within minutes + +### Manual Publishing (Alternative) + +If you prefer to publish manually: + +```bash +# Install dependencies +pnpm install + +# Build all packages +pnpm run build + +# Navigate to specific package +cd packages/parser + +# Publish +pnpm publish --access public +``` diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml new file mode 100644 index 0000000..177c263 --- /dev/null +++ b/.github/workflows/npm-publish.yml @@ -0,0 +1,318 @@ +name: NPM Publish and Release + +on: + workflow_dispatch: + inputs: + version_type: + description: 'Version bump type' + required: true + default: 'patch' + type: choice + options: + - major + - minor + - patch + packages: + description: 'Packages to publish (comma-separated: parser,vue or "all")' + required: true + default: 'all' + type: string + changelog: + description: 'Release changelog (required)' + required: true + type: string + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: Validate changelog input + run: | + if [ -z "${{ github.event.inputs.changelog }}" ]; then + echo "❌ Changelog is required for release" + echo "Please provide a detailed changelog describing the changes in this release." + exit 1 + fi + echo "✅ Changelog provided" + + publish: + runs-on: ubuntu-latest + needs: validate + permissions: + contents: write + packages: write + pull-requests: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + registry-url: 'https://registry.npmjs.org' + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10.17.1 + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run linting + run: pnpm run lint + + - name: Run type checking + run: pnpm run typecheck + + - name: Configure git + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + + - name: Determine packages to publish + id: packages + run: | + INPUT_PACKAGES="${{ github.event.inputs.packages }}" + + if [ "$INPUT_PACKAGES" = "all" ]; then + PACKAGES="parser vue" + else + PACKAGES=$(echo "$INPUT_PACKAGES" | tr ',' ' ') + fi + + echo "packages=$PACKAGES" >> $GITHUB_OUTPUT + echo "📦 Packages to publish: $PACKAGES" + + - name: Bump versions and collect info + id: version + run: | + PACKAGES="${{ steps.packages.outputs.packages }}" + VERSION_TYPE="${{ github.event.inputs.version_type }}" + + VERSIONS_JSON="{" + CHANGED_FILES="" + + for pkg in $PACKAGES; do + PKG_DIR="packages/$pkg" + + if [ ! -d "$PKG_DIR" ]; then + echo "❌ Package directory $PKG_DIR not found" + exit 1 + fi + + cd "$PKG_DIR" + + # Get current version + CURRENT_VERSION=$(node -p "require('./package.json').version") + echo "Current version of @markdown-next/$pkg: $CURRENT_VERSION" + + # Bump version based on input + case "$VERSION_TYPE" in + "major") + NEW_VERSION=$(npm version major --no-git-tag-version) + ;; + "minor") + NEW_VERSION=$(npm version minor --no-git-tag-version) + ;; + "patch") + NEW_VERSION=$(npm version patch --no-git-tag-version) + ;; + esac + + # Remove 'v' prefix from npm version output + NEW_VERSION=${NEW_VERSION#v} + echo "New version of @markdown-next/$pkg: $NEW_VERSION" + + # Add to JSON + if [ "$VERSIONS_JSON" != "{" ]; then + VERSIONS_JSON="${VERSIONS_JSON}," + fi + VERSIONS_JSON="${VERSIONS_JSON}\"$pkg\":\"$NEW_VERSION\"" + + # Track changed files + CHANGED_FILES="$CHANGED_FILES $PKG_DIR/package.json" + + cd ../.. + done + + VERSIONS_JSON="${VERSIONS_JSON}}" + + echo "versions=$VERSIONS_JSON" >> $GITHUB_OUTPUT + echo "changed_files=$CHANGED_FILES" >> $GITHUB_OUTPUT + echo "version_tag=$NEW_VERSION" >> $GITHUB_OUTPUT + + - name: Generate CHANGELOG + run: | + PACKAGES="${{ steps.packages.outputs.packages }}" + + for pkg in $PACKAGES; do + PKG_DIR="packages/$pkg" + cd "$PKG_DIR" + + # Create or update CHANGELOG.md + if [ ! -f CHANGELOG.md ]; then + echo "# Changelog" > CHANGELOG.md + echo "" >> CHANGELOG.md + echo "All notable changes to this project will be documented in this file." >> CHANGELOG.md + echo "" >> CHANGELOG.md + fi + + # Get version from versions JSON + VERSION=$(echo '${{ steps.version.outputs.versions }}' | node -p "JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8'))['$pkg']") + + # Prepare new changelog entry + TODAY=$(date +"%Y-%m-%d") + NEW_ENTRY="## [$VERSION] - $TODAY" + + # Create temporary file with new entry + cat > temp_changelog.md << EOF +# Changelog + +All notable changes to this project will be documented in this file. + +$NEW_ENTRY + +${{ github.event.inputs.changelog }} + +EOF + + # Append existing changelog (skip header) + if [ -f CHANGELOG.md ]; then + tail -n +4 CHANGELOG.md >> temp_changelog.md + fi + + # Replace original changelog + mv temp_changelog.md CHANGELOG.md + + cd ../.. + done + + - name: Build packages + run: pnpm run build + + - name: Run tests + run: pnpm run test + continue-on-error: false + + - name: Publish packages to NPM + run: | + PACKAGES="${{ steps.packages.outputs.packages }}" + + for pkg in $PACKAGES; do + PKG_DIR="packages/$pkg" + cd "$PKG_DIR" + + echo "📦 Publishing @markdown-next/$pkg..." + pnpm publish --access public --no-git-checks + + if [ $? -eq 0 ]; then + echo "✅ Successfully published @markdown-next/$pkg" + else + echo "❌ Failed to publish @markdown-next/$pkg" + exit 1 + fi + + cd ../.. + done + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Commit and push changes + run: | + PACKAGES="${{ steps.packages.outputs.packages }}" + + # Add all package.json and CHANGELOG.md files + for pkg in $PACKAGES; do + git add "packages/$pkg/package.json" + git add "packages/$pkg/CHANGELOG.md" + done + + # Create commit message + COMMIT_MSG="chore: release v${{ steps.version.outputs.version_tag }} + +Published packages: $PACKAGES + +${{ github.event.inputs.changelog }}" + + git commit -m "$COMMIT_MSG" + git push origin main + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ steps.version.outputs.version_tag }} + name: Release v${{ steps.version.outputs.version_tag }} + body: | + ## Release v${{ steps.version.outputs.version_tag }} + + ${{ github.event.inputs.changelog }} + + --- + + ### 📦 Published Packages + + ${{ steps.packages.outputs.packages }} + + **Version Information:** + ```json + ${{ steps.version.outputs.versions }} + ``` + + ### 📥 Installation + + ```bash + # Install parser + npm install @markdown-next/parser@${{ steps.version.outputs.version_tag }} + # or + pnpm add @markdown-next/parser@${{ steps.version.outputs.version_tag }} + + # Install vue renderer + npm install @markdown-next/vue@${{ steps.version.outputs.version_tag }} + # or + pnpm add @markdown-next/vue@${{ steps.version.outputs.version_tag }} + ``` + + ### 🔗 Links + - **NPM - Parser**: https://www.npmjs.com/package/@markdown-next/parser + - **NPM - Vue**: https://www.npmjs.com/package/@markdown-next/vue + - **Repository**: https://github.com/${{ github.repository }} + + ### 📋 Full Changelog + **Full Changelog**: https://github.com/${{ github.repository }}/compare/v${{ steps.version.outputs.version_tag }}...v${{ steps.version.outputs.version_tag }} + draft: false + prerelease: ${{ contains(steps.version.outputs.version_tag, 'alpha') || contains(steps.version.outputs.version_tag, 'beta') }} + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + notify: + runs-on: ubuntu-latest + needs: publish + if: success() + steps: + - name: Release notification + run: | + echo "🎉 Successfully released packages" + echo "📦 NPM Parser: https://www.npmjs.com/package/@markdown-next/parser" + echo "📦 NPM Vue: https://www.npmjs.com/package/@markdown-next/vue" + echo "🏷️ GitHub Release: https://github.com/${{ github.repository }}/releases/tag/v${{ needs.publish.outputs.version_tag }}" diff --git a/README.md b/README.md index 3e415ab..4c7b8c8 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ const markdown = '# Hello World\n\nThis is **markdown**!'; ``` diff --git a/readme/README.zh-CN.md b/readme/README.zh-CN.md index 6687d2b..02c9e1d 100644 --- a/readme/README.zh-CN.md +++ b/readme/README.zh-CN.md @@ -59,7 +59,7 @@ const markdown = '# 你好世界\n\n这是 **markdown**!'; ```