From bc40daa7ad4dc2f5865bd6e3545527452c0de446 Mon Sep 17 00:00:00 2001 From: yuan li Date: Mon, 22 Sep 2025 13:41:41 +0800 Subject: [PATCH] Add github workflow into v1.17 --- .github/workflows/issue-auto-assign.yml | 74 +++++++ .github/workflows/merge-build-push.yml | 269 ++++++++++++++++++++++++ .github/workflows/pr-preview.yml | 187 ++++++++++++++++ 3 files changed, 530 insertions(+) create mode 100644 .github/workflows/issue-auto-assign.yml create mode 100644 .github/workflows/merge-build-push.yml create mode 100644 .github/workflows/pr-preview.yml diff --git a/.github/workflows/issue-auto-assign.yml b/.github/workflows/issue-auto-assign.yml new file mode 100644 index 00000000..40dadc37 --- /dev/null +++ b/.github/workflows/issue-auto-assign.yml @@ -0,0 +1,74 @@ +name: Auto Assign Issue on Command + +on: + issue_comment: + types: [created] + +jobs: + assign_on_command: + runs-on: ubuntu-latest + permissions: + issues: write + contents: read + steps: + - name: Assign to user on /assign command + uses: actions/github-script@v6 + with: + github-token: ${{secrets.IVORY_TOKEN}} + script: | + const commentBody = context.payload.comment.body.trim().toLowerCase(); + const commenter = context.payload.comment.user.login; + const issueNumber = context.issue.number; + const repoOwner = context.repo.owner; + const repoName = context.repo.repo; + + if (commentBody === '/assign') { + console.log(`User @${commenter} commented "/assign" on issue #${issueNumber}. Attempting to assign.`); + + if (commenter.endsWith('[bot]') || commenter === 'github-actions[bot]') { + console.log(`Skipping assignment for bot user: ${commenter}`); + return; + } + + const { data: issue } = await github.rest.issues.get({ + owner: repoOwner, + repo: repoName, + issue_number: issueNumber + }); + + if (issue.assignees && issue.assignees.some(a => a.login === commenter)) { + console.log(`Issue #${issueNumber} is already assigned to @${commenter}. No action needed.`); + return; + } + + if (issue.state === 'closed') { + console.log(`Issue #${issueNumber} is closed. No assignment will be made.`); + await github.rest.issues.createComment({ + owner: repoOwner, + repo: repoName, + issue_number: issueNumber, + body: `Hi @${commenter}, issue #${issueNumber} is closed and cannot be assigned.` + }); + return; + } + + try { + await github.rest.issues.addAssignees({ + owner: repoOwner, + repo: repoName, + issue_number: issueNumber, + assignees: [commenter] + }); + console.log(`Successfully assigned issue #${issueNumber} to @${commenter}.`); + } catch (error) { + console.error(`Error assigning issue #${issueNumber} to @${commenter}:`, error); + await github.rest.issues.createComment({ + owner: repoOwner, + repo: repoName, + issue_number: issueNumber, + body: `Hi @${commenter}, I encountered an error trying to assign you to issue #${issueNumber}. Please check permissions or assign manually. \nError: ${error.message}` + }); + } + } else { + console.log(`Comment by @${commenter} on issue #${issueNumber} was not an "/assign" command. Body: "${context.payload.comment.body.trim()}"`); + } diff --git a/.github/workflows/merge-build-push.yml b/.github/workflows/merge-build-push.yml new file mode 100644 index 00000000..607fe56a --- /dev/null +++ b/.github/workflows/merge-build-push.yml @@ -0,0 +1,269 @@ +name: Build , Push to web, Deploy Antora Docs + +on: + pull_request_target: + types: + - closed + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + if: github.event.pull_request.merged == true + permissions: + contents: write + pull-requests: write + + steps: + - name: PR was merged + run: | + echo "PR #${{ github.event.pull_request.number }} was merged into ${{ github.event.pull_request.base.ref }}." + echo "Head commit was: ${{ github.event.pull_request.head.sha }}" + + - name: Checkout Documentation Repository (ivorysql_doc) + uses: actions/checkout@v4 + with: + path: ivorysql_doc + + - name: Checkout Doc Builder Repository (doc_builder) + uses: actions/checkout@v4 + with: + repository: ${{ github.repository_owner }}/ivory-doc-builder + path: ivory-doc-builder + + - name: Determine Latest Version from ivorysql_docs branches + id: latest_version_step + shell: bash + run: | + echo "Detecting latest version from remote branches of IvorySQL/ivorysql_docs..." + LATEST_VERSION_NUMBER=$( \ + git ls-remote --heads --refs "https://github.com/IvorySQL/ivorysql_docs.git" 'refs/heads/v*.*' | \ + sed 's_^[^\t]*\trefs/heads/v__g' | \ + grep -E '^[0-9]+\.[0-9]+(\.[0-9]+)?$' | \ + sort -V | \ + tail -n1 \ + ) + + if [[ -z "$LATEST_VERSION_NUMBER" ]]; then + echo "::error::Could not determine latest version from branches. Please check git ls-remote command and repo accessibility." + exit 1 + fi + + echo "Detected latest version number: $LATEST_VERSION_NUMBER" + echo "version=$LATEST_VERSION_NUMBER" >> "$GITHUB_OUTPUT" + + - name: Install yq + run: | + sudo apt-get update -y + sudo apt-get install -y jq + sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq + sudo chmod +x /usr/bin/yq + yq --version + + - name: Modify Antora Playbooks + working-directory: ./ivory-doc-builder + env: + DETECTED_VERSION: '${{ steps.latest_version_step.outputs.version }}' + START_PAGE_COMPONENT_NAME: "ivorysql-doc" + START_PAGE_FILE_PATH: "welcome.adoc" + run: | + PLAYBOOK_FILES=("antora-playbook-CN.yml" "antora-playbook-EN.yml") + + for PLAYBOOK_FILE in "${PLAYBOOK_FILES[@]}"; do + if [ -f "$PLAYBOOK_FILE" ]; then + echo "--- Modifying Playbook: $PLAYBOOK_FILE ---" + echo "Original content of $PLAYBOOK_FILE:" + cat "$PLAYBOOK_FILE" + echo # Newline for better readability + + if [[ -n "$DETECTED_VERSION" ]]; then + NEW_START_PAGE="${START_PAGE_COMPONENT_NAME}::v${DETECTED_VERSION}/${START_PAGE_FILE_PATH}" + yq -i ".site.start_page = \"$NEW_START_PAGE\"" "$PLAYBOOK_FILE" + echo "Updated .site.start_page in $PLAYBOOK_FILE to: $NEW_START_PAGE" + else + echo "WARNING: DETECTED_VERSION is empty. Skipping start_page update for $PLAYBOOK_FILE." + fi + echo "Modified content of $PLAYBOOK_FILE:" + cat "$PLAYBOOK_FILE" + echo "--- Finished modification for $PLAYBOOK_FILE ---" + echo # Newline + else + echo "WARNING: Playbook file $PLAYBOOK_FILE not found in $(pwd)." + fi + done + + - name: Checkout Web Repository (web) + uses: actions/checkout@v4 + with: + repository: ${{ github.repository_owner }}/ivorysql_web + path: www_publish_target + token: ${{ secrets.WEB_TOKEN }} + + - name: Setup Ruby and Bundler + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.0' + + - name: Install Asciidoctor PDF and related Gems + run: | + echo "Installing Asciidoctor PDF gems..." + gem install asciidoctor-pdf --version "~>2.3.19" + gem install rouge + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.15' + + - name: Install Antora CLI + run: | + echo "Installing Antora packages local..." + npm install --global antora@3.1.7 @antora/lunr-extension @antora/pdf-extension @node-rs/jieba + + - name: Build English Documentation + working-directory: ./ivory-doc-builder + run: | + echo "Current directory: $(pwd)" + echo "Building English site..." + ls ../www_publish_target/ + npx antora generate --stacktrace --to-dir ../www_publish_target/docs/en antora-playbook-EN.yml + + - name: Build Chinese Documentation + working-directory: ./ivory-doc-builder + run: | + echo "Building Chinese site..." + npx antora generate --stacktrace --to-dir ../www_publish_target/docs/cn antora-playbook-CN.yml + + - name: Move and Rename PDF Files + id: process_pdfs + working-directory: ./www_publish_target + run: | + echo "--- Searching for PDF files to move and rename ---" + + PDF_FILES_FOUND=$(find . -type f -path '*/_exports/index.pdf') + + if [ -z "${PDF_FILES_FOUND}" ]; then + echo "No PDF files found to move. Skipping." + else + echo "Found PDF files to process:" + echo "${PDF_FILES_FOUND}" + + echo "${PDF_FILES_FOUND}" | while read PDF_FILE; do + # ./docs/cn/ivorysql-doc/master/_exports/index.pdf -> ./docs/cn/ivorysql-doc/master + BASE_DIR="${PDF_FILE%/_exports/index.pdf}" + + NEW_PDF_PATH="${BASE_DIR}/ivorysql.pdf" + + echo "Moving '${PDF_FILE}' to '${NEW_PDF_PATH}'" + mv "${PDF_FILE}" "${NEW_PDF_PATH}" + done + + echo "--- Cleaning up empty _exports directories ---" + find . -type d -name '_exports' -empty -delete + fi + + echo "--- PDF processing complete ---" + + - name: Commit and Push to web Repository new branch , pull request + id: commit_push_new_branch + working-directory: ./www_publish_target + env: + OPEN_PUSH_PR: true + run: | + echo "push_pr=${OPEN_PUSH_PR}" >> $GITHUB_OUTPUT + echo "--- Preparing to commit and push changes ---" + echo "--- Git status ---" + GIT_STATUS_OUTPUT=$(git status --porcelain) + echo "${GIT_STATUS_OUTPUT}" + echo "--- End of git status --porcelain output ---" + + git config user.name "IvorySQL Actions Bot" + git config user.email "actions-bot@users.noreply.github.com" + + if [ -z "${GIT_STATUS_OUTPUT}" ]; then + echo "No changes to commit." + echo "changes_detected=false" >> $GITHUB_OUTPUT + else + echo "Changes detected. Proceeding with add, commit, and push." + if [[ "${OPEN_PUSH_PR}" == "true" ]]; then + NEW_BRANCH_NAME="docs-update-${{ github.run_attempt }}-$(date +'%Y-%m-%d-%H%M%S')" + echo "Generated new branch name: ${NEW_BRANCH_NAME}" + echo "new_branch_name=${NEW_BRANCH_NAME}" >> $GITHUB_OUTPUT + echo "changes_detected=true" >> $GITHUB_OUTPUT + git checkout -b "${NEW_BRANCH_NAME}" + git add . + COMMIT_MESSAGE="docs: Regenerate Antora site from IvorySQL/ivorysql_docs commit ${{ github.event.head_commit.id || github.sha }}" + git commit -m "${COMMIT_MESSAGE}" + git push origin "${NEW_BRANCH_NAME}" + else + echo "Pushing changes to master branch." + git add . + COMMIT_MESSAGE="docs: Regenerate Antora site from IvorySQL/ivorysql_docs commit ${{ github.event.head_commit.id || github.sha }}" + git commit -m "${COMMIT_MESSAGE}" + git push origin master + fi + fi + + - name: Create or Update Pull Request with GitHub CLI + id: cpr + if: steps.commit_push_new_branch.outputs.push_pr == 'true' && steps.commit_push_new_branch.outputs.changes_detected == 'true' && steps.commit_push_new_branch.outputs.new_branch_name != '' + working-directory: ./www_publish_target + env: + GH_TOKEN: ${{ secrets.WEB_TOKEN }} + PARAM_BASE_BRANCH: master + PARAM_HEAD_BRANCH: ${{ steps.commit_push_new_branch.outputs.new_branch_name }} + PARAM_TITLE: "Docs: Automated update from IvorySQL/ivorysql_docs commit ${{ github.event.head_commit.id || github.sha }}" + PARAM_BODY: | + Automated Antora site regeneration based on changes in the IvorySQL/ivorysql_docs repository. + + Source commit: `${{ github.server_url }}/${{ github.repository_owner }}/ivorysql_docs/commit/${{ github.event.head_commit.id || github.sha }}` + + - Auto-generated by gh pr create + PARAM_DRAFT: "false" + run: | + echo "Attempting to create or update Pull Request for branch '${PARAM_HEAD_BRANCH}' into '${PARAM_BASE_BRANCH}'" + + DRAFT_FLAG_STRING="" + if [[ "${PARAM_DRAFT}" == "true" ]]; then + DRAFT_FLAG_STRING="--draft" + fi + + echo "Executing: gh pr create --base \"${PARAM_BASE_BRANCH}\" --head \"${PARAM_HEAD_BRANCH}\" --title --body-file <(echo body) ${DRAFT_FLAG_STRING}" + + if gh pr create \ + --base "${PARAM_BASE_BRANCH}" \ + --head "${PARAM_HEAD_BRANCH}" \ + --title "${PARAM_TITLE}" \ + --body-file <(echo "${PARAM_BODY}") \ + ${DRAFT_FLAG_STRING}; then + echo "Pull Request created or already exists and metadata might have been updated." + else + echo "'gh pr create' command indicated an issue or no action was taken." + + EXISTING_PR_URL=$(gh pr view "${PARAM_HEAD_BRANCH}" --json url -q ".url" 2>/dev/null || echo "") + if [[ -n "$EXISTING_PR_URL" ]]; then + echo "An existing PR was found for branch '${PARAM_HEAD_BRANCH}': ${EXISTING_PR_URL}" + echo "Proceeding to enable auto-merge for this existing PR." + else + echo "::error::Failed to create PR and no existing PR found for branch '${PARAM_HEAD_BRANCH}'. Cannot enable auto-merge." + exit 1 + fi + fi + + - name: Enable Auto-Merge for PR + if: steps.cpr.outcome == 'success' && steps.commit_push_new_branch.outputs.push_pr == 'true' && steps.commit_push_new_branch.outputs.changes_detected == 'true' && steps.commit_push_new_branch.outputs.new_branch_name != '' + working-directory: ./www_publish_target + env: + GH_TOKEN: ${{ secrets.WEB_TOKEN }} + PR_HEAD_BRANCH: ${{ steps.commit_push_new_branch.outputs.new_branch_name }} + PR_BASE_BRANCH: master + MERGE_STRATEGY: MERGE + run: | + echo "Attempting to enable auto-merge for PR from branch '$PR_HEAD_BRANCH' to '$PR_BASE_BRANCH'" + if gh pr merge "$PR_HEAD_BRANCH" \ + --${MERGE_STRATEGY,,} \ + --delete-branch; then + echo "Auto-merge enabled successfully for PR from branch '$PR_HEAD_BRANCH'." + else + echo "::warning::Failed to enable auto-merge for PR from branch '$PR_HEAD_BRANCH'." + echo "This might be because the PR is not mergeable (e.g., has conflicts, is a draft PR), requires reviews, auto-merge is already enabled, or the PR could not be uniquely identified by branch name." + fi diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml new file mode 100644 index 00000000..d1214851 --- /dev/null +++ b/.github/workflows/pr-preview.yml @@ -0,0 +1,187 @@ +name: Pr preview + +on: + pull_request_target: + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + deployments: write + statuses: write + + steps: + - name: Checkout Documentation Repository (ivorysql_doc) + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + path: ivorysql_doc + + - name: Fetch All Relevant Branches into Local Docs Repo + working-directory: ./ivorysql_doc + run: | + echo "Fetching all branches from origin to update local remote-tracking branches..." + git fetch origin --prune --no-tags + + echo "--- Fetched Remote-Tracking Branches ---" + git branch -r + + - name: Checkout Doc Builder Repository (doc_builder) + uses: actions/checkout@v4 + with: + repository: ${{ github.repository_owner }}/ivory-doc-builder + path: ivory-doc-builder + + - name: Determine Latest Version from ivorysql_docs branches + id: latest_version_step + shell: bash + run: | + echo "Detecting latest version from remote branches of ${{ github.repository_owner }}/ivorysql_docs..." + LATEST_VERSION_NUMBER=$( \ + git ls-remote --heads --refs "https://github.com/${{ github.repository_owner }}/ivorysql_docs.git" 'refs/heads/v*.*' | \ + sed 's_^[^\t]*\trefs/heads/v__g' | \ + grep -E '^[0-9]+\.[0-9]+(\.[0-9]+)?$' | \ + sort -V | \ + tail -n1 \ + ) + + if [[ -z "$LATEST_VERSION_NUMBER" ]]; then + echo "::error::Could not determine latest version from branches. Please check git ls-remote command and repo accessibility." + exit 1 + fi + + echo "Detected latest version number: $LATEST_VERSION_NUMBER" + echo "version=$LATEST_VERSION_NUMBER" >> "$GITHUB_OUTPUT" + + - name: Install yq + run: | + sudo apt-get update -y + sudo apt-get install -y jq + sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq + sudo chmod +x /usr/bin/yq + yq --version + + - name: Modify Antora Playbooks for Local PR Build + working-directory: ./ivory-doc-builder + env: + DETECTED_VERSION: '${{ steps.latest_version_step.outputs.version }}' + START_PAGE_COMPONENT_NAME: "ivorysql-doc" + START_PAGE_FILE_PATH: "welcome.adoc" + run: | + PLAYBOOK_FILES=("antora-playbook-CN.yml" "antora-playbook-EN.yml") + NEW_LOCAL_URL="../ivorysql_doc" + + for PLAYBOOK_FILE in "${PLAYBOOK_FILES[@]}"; do + if [ -f "$PLAYBOOK_FILE" ]; then + echo "--- Modifying Playbook: $PLAYBOOK_FILE ---" + echo "Original content of $PLAYBOOK_FILE:" + cat "$PLAYBOOK_FILE" + echo # Newline for better readability + + yq -i ".content.sources[0].url = \"$NEW_LOCAL_URL\"" "$PLAYBOOK_FILE" + + yq -i ".content.sources[0].branches = [\"HEAD\"]" "$PLAYBOOK_FILE" + + yq -i ".content.sources[0].edit_url = false" "$PLAYBOOK_FILE" + if [[ -n "$DETECTED_VERSION" ]]; then + NEW_START_PAGE="${START_PAGE_COMPONENT_NAME}::v${DETECTED_VERSION}/${START_PAGE_FILE_PATH}" + yq -i ".site.start_page = \"$NEW_START_PAGE\"" "$PLAYBOOK_FILE" + echo "Updated .site.start_page in $PLAYBOOK_FILE to: $NEW_START_PAGE" + else + echo "WARNING: DETECTED_VERSION is empty. Skipping start_page update for $PLAYBOOK_FILE." + fi + yq -i ".site.title = .site.title + \" (PR Preview)\"" "$PLAYBOOK_FILE" + echo "Modified content of $PLAYBOOK_FILE:" + cat "$PLAYBOOK_FILE" + echo "--- Finished modification for $PLAYBOOK_FILE ---" + echo # Newline + else + echo "WARNING: Playbook file $PLAYBOOK_FILE not found in $(pwd)." + fi + done + + - name: Checkout WWW Repository (www) + uses: actions/checkout@v4 + with: + repository: ${{ github.repository_owner }}/ivorysql_web + path: www_publish_target + + - name: Setup Ruby and Bundler + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.0' + + - name: Install Asciidoctor PDF and related Gems + run: | + echo "Installing Asciidoctor PDF gems..." + gem install asciidoctor-pdf --version "~>2.3.19" + gem install rouge + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.15' + + - name: Install Antora CLI + run: | + echo "Installing Antora packages local..." + npm install --global antora@3.1.7 @antora/lunr-extension @antora/pdf-extension @node-rs/jieba + + - name: Build English Documentation + working-directory: ./ivory-doc-builder + run: | + echo "Current directory: $(pwd)" + echo "Building English site..." + #mkdir -p ../www_publish_target/docs/en + npx antora generate --stacktrace --to-dir ../www_publish_target/docs/en antora-playbook-EN.yml + + - name: Build Chinese Documentation + working-directory: ./ivory-doc-builder + run: | + echo "Building Chinese site..." + #mkdir -p ../www_publish_target/docs/cn + npx antora generate --stacktrace --to-dir ../www_publish_target/docs/cn antora-playbook-CN.yml + + - name: Deploy to Netlify + id: netlify_deploy + uses: nwtgck/actions-netlify@v3.0 + with: + publish-dir: './www_publish_target/docs' + production-branch: test + github-token: ${{ secrets.GITHUB_TOKEN }} + deploy-message: "Deploy preview for PR #${{ github.event.number }}" + enable-pull-request-comment: false + enable-commit-comment: false + enable-commit-status: true + alias: pr-${{ github.event.number }}-doc + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + timeout-minutes: 5 + + - name: Post Custom Preview Links Comment + if: steps.netlify_deploy.outputs.deploy-url + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const baseUrl = '${{ steps.netlify_deploy.outputs.deploy-url }}'; + + const enUrl = `${baseUrl}/en`; + + const body = ` + 🚀 **IvorySQL-Docs Preview Ready** + + - **Chinese Preview:** [${baseUrl}](${baseUrl}) + - **English Preview:** [${enUrl}](${enUrl}) + `; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: body + }); \ No newline at end of file