Edit Existing GitHub Releases (One-Time) #2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Edit Existing GitHub Releases (One-Time) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| start_version: | |
| description: 'Start editing from this version (e.g., 0.1.0)' | |
| required: false | |
| default: '0.1.0' # Adjust this to the earliest version you want to edit | |
| end_version: | |
| description: 'End editing at this version (e.g., 0.21.0). Leave empty for all versions from start_version.' | |
| required: false | |
| default: '' # Leave empty to process all versions from start_version onwards | |
| changelog_commit_ref: | |
| description: 'Commit hash or branch where the full changelog.mdx exists (e.g., master or a specific hash). Defaults to current ref.' | |
| required: false | |
| # IMPORTANT: Use the commit hash where your changelog.mdx has all the correct release notes. | |
| # If your 'master' branch has the complete changelog, 'master' is fine. | |
| # If the files were at a specific older commit, use that hash (e.g., '96ead5ee413f83fc58796f1661791122cf1a7f60') | |
| default: 'master' # Change this if your full changelog is on a different branch or specific commit | |
| jobs: | |
| edit_releases: | |
| runs-on: ubuntu-latest | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| steps: | |
| - name: Checkout repository (for changelog) | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.inputs.changelog_commit_ref }} | |
| fetch-depth: 0 # Get full history for accurate changelog parsing | |
| - name: Install GitHub CLI | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gh | |
| - name: Set up Node.js for Changelog Parsing | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Create release body parser script | |
| id: create_parser_script | |
| run: | | |
| cat << 'EOF' > parse_changelog.js | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| const changelogPath = path.join(process.env.GITHUB_WORKSPACE, 'documentation', 'docs', 'pages', 'docs', 'changelog.mdx'); | |
| const rawVersion = process.argv[2]; // Version string passed (e.g., "0.1.0", "0.21.0") | |
| // Determine the exact header format from your changelog | |
| // Your changelog uses "# 0.x.x-beta" for most entries. | |
| // For 0.1.0, it's just "# 0.1.0" | |
| let headerToMatch = ''; | |
| if (rawVersion === '0.1.0') { | |
| headerToMatch = `# ${rawVersion}`; // Matches exactly for 0.1.0 | |
| } else { | |
| headerToMatch = `# ${rawVersion}-beta`; // Matches most other beta versions | |
| } | |
| console.log(`Attempting to parse changelog for header: "${headerToMatch}"`); | |
| try { | |
| const changelogContent = fs.readFileSync(changelogPath, 'utf8'); | |
| const releasesSection = changelogContent.split(/^## Releases/m)[1]; | |
| if (!releasesSection) { | |
| console.error("Could not find '## Releases' section in changelog."); | |
| process.exit(1); | |
| } | |
| // Regex to find the section for the specific version | |
| // It matches the header and captures everything until the next similar header or end of string | |
| const releasePattern = new RegExp(`^${headerToMatch}\\s*-\\s*\\d+(?:st|nd|rd|th) \\w+ \\d{4}([\\s\\S]*?)(?:\\n# \\d+\\.\\d+\\.\\d+|$|^## |$)`, 'm'); | |
| const match = releasesSection.match(releasePattern); | |
| let releaseNotes = "No specific features/bug fixes mentioned in changelog."; | |
| if (match && match[1]) { | |
| releaseNotes = match[1].trim(); | |
| // Clean up specific lines that are just headers or blank lines from your template | |
| releaseNotes = releaseNotes | |
| .replace(/^(github branch - https:\/\/github\.com\/joshstevens19\/rindexer\/tree\/release\/.*)$/gm, '') | |
| .replace(/^- (linux|mac|windows) binary - https:\/\/(github|rindexer\.xyz).*$/gm, '') | |
| .replace(/^### Features\n-------------------------------------------------$/gm, '### Features') | |
| .replace(/^### Bug fixes\n-------------------------------------------------$/gm, '### Bug fixes') | |
| .replace(/^### Breaking changes\n-------------------------------------------------$/gm, '### Breaking changes') | |
| .replace(/^-+\s*$/gm, '') // Remove horizontal rules | |
| .replace(/^\s*[\r\n]+/gm, '') // Remove empty lines | |
| .trim(); | |
| if (releaseNotes === '') { | |
| releaseNotes = "No specific features/bug fixes mentioned in changelog."; | |
| } | |
| } | |
| // Encode the output to handle multi-line strings correctly in GitHub Actions | |
| const encodedNotes = releaseNotes.replace(/%/g, '%25').replace(/\n/g, '%0A').replace(/\r/g, '%0D'); | |
| console.log(`::set-output name=release_body::${encodedNotes}`); | |
| } catch (error) { | |
| console.error(`Error reading or parsing changelog: ${error.message}`); | |
| process.exit(1); | |
| } | |
| EOF | |
| chmod +x parse_changelog.js | |
| - name: Get all existing release tags | |
| id: get_tags | |
| run: | | |
| # Get all tags that start with 'v' and look like versions, then sort them. | |
| # This ensures we only process valid version tags that GitHub created. | |
| ALL_TAGS=$(gh api --paginate "/repos/${{ github.repository }}/tags" --jq '.[].name' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sed 's/^v//' | sort -V | paste -sd ' ' -) | |
| echo "Found tags: $ALL_TAGS" | |
| echo "all_versions=$ALL_TAGS" >> $GITHUB_OUTPUT | |
| - name: Edit Releases | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| START_VERSION: ${{ github.event.inputs.start_version }} | |
| END_VERSION: ${{ github.event.inputs.end_version }} | |
| run: | | |
| #!/bin/bash | |
| set -e | |
| ALL_VERSIONS="${{ steps.get_tags.outputs.all_versions }}" | |
| # Filter versions based on optional inputs | |
| FILTERED_VERSIONS="" | |
| # Function for version comparison using sort -V (semantic versioning) | |
| version_ge() { | |
| local v1="$1" | |
| local v2="$2" | |
| [[ "$v1" = "$v2" ]] || [[ "$(printf '%s\n' "$v1" "$v2" | sort -V | head -n1)" = "$v2" ]] | |
| } | |
| version_le() { | |
| local v1="$1" | |
| local v2="$2" | |
| [[ "$v1" = "$v2" ]] || [[ "$(printf '%s\n' "$v1" "$v2" | sort -V | tail -n1)" = "$v2" ]] | |
| } | |
| for ver in $ALL_VERSIONS; do | |
| if [[ -n "$START_VERSION" ]]; then | |
| if ! version_ge "$ver" "$START_VERSION"; then | |
| continue # Skip if less than start_version | |
| fi | |
| fi | |
| if [[ -n "$END_VERSION" ]]; then | |
| if ! version_le "$ver" "$END_VERSION"; then | |
| continue # Skip if greater than end_version | |
| fi | |
| fi | |
| FILTERED_VERSIONS+=" $ver" | |
| done | |
| if [ -z "$FILTERED_VERSIONS" ]; then | |
| echo "No versions to edit after applying filters. Exiting." | |
| exit 0 | |
| fi | |
| echo "Editing versions: $FILTERED_VERSIONS" | |
| for VERSION in $FILTERED_VERSIONS; do | |
| echo "--- Processing version: $VERSION ---" | |
| TAG="v$VERSION" | |
| # Construct the base installation instructions as a multi-line string within the script | |
| INSTALL_INSTRUCTIONS="## Installation | |
| \`\`\`bash | |
| # Latest version | |
| curl -L https://rindexer.xyz/install.sh | bash | |
| # Specific version | |
| curl -L https://rindexer.xyz/install.sh | bash -s -- --version $VERSION | |
| \`\`\`" | |
| # Call Node.js script to get release body. | |
| RAW_CHANGELOG_BODY=$(node parse_changelog.js "$VERSION") | |
| # Decode the URL-encoded string from the Node.js script | |
| CLEANED_CHANGELOG_BODY=$(echo -e "${RAW_CHANGELOG_BODY//%/\\x}" | sed 's/%0A/\n/g; s/%0D/\r/g') | |
| # Combine all parts for the full release body | |
| FULL_RELEASE_BODY="${INSTALL_INSTRUCTIONS}\n\n${CLEANED_CHANGELOG_BODY}\n\nSee full changelog for details: https://github.com/joshstevens19/rindexer/blob/master/documentation/docs/pages/docs/changelog.mdx" | |
| echo "Attempting to edit release $TAG..." | |
| gh release edit "$TAG" \ | |
| --prerelease=false \ | |
| --notes "$FULL_RELEASE_BODY" \ | |
| --target master # Assuming your release tags point to master/main | |
| # --draft=false # Uncomment this if you accidentally created drafts and want to publish them | |
| echo "Successfully edited release $TAG." | |
| done |