diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 84b7cb6dc..9faf71704 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -70,7 +70,7 @@ body: validations: required: false - type: textarea - id: systemetails + id: systemdetails attributes: label: System Details description: Please add the output of `wails doctor`. diff --git a/.github/workflows/nightly-release-v3.yml b/.github/workflows/nightly-release-v3.yml index 426e45589..ae56ba7bc 100644 --- a/.github/workflows/nightly-release-v3.yml +++ b/.github/workflows/nightly-release-v3.yml @@ -1,4 +1,3 @@ - name: Nightly Release v3-alpha on: @@ -32,33 +31,20 @@ jobs: with: ref: v3-alpha fetch-depth: 0 - token: ${{ github.token }} + token: ${{ secrets.WAILS_REPO_TOKEN || github.token }} - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v4 with: - go-version: '1.23' + go-version: '1.24' + cache: true cache-dependency-path: 'v3/go.sum' - name: Install Task uses: arduino/setup-task@v2 with: version: 3.x - repo-token: ${{ github.token }} - - - name: Verify Go and Task installation - run: | - echo "Go version:" - go version - echo "" - echo "Task version:" - task --version - echo "" - echo "Working directory:" - pwd - echo "" - echo "v3 directory contents:" - ls -la v3/ + repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Git run: | @@ -66,7 +52,7 @@ jobs: git config --global user.email "github-actions[bot]@users.noreply.github.com" # Configure git to use the token for authentication - git config --global url."https://x-access-token:${{ github.token }}@github.com/".insteadOf "https://github.com/" + git config --global url."https://x-access-token:${{ secrets.WAILS_REPO_TOKEN || github.token }}@github.com/".insteadOf "https://github.com/" - name: Check for existing release tag id: check_tag @@ -84,24 +70,16 @@ jobs: run: | echo "๐Ÿ” Checking UNRELEASED_CHANGELOG.md for content..." - # Check if the file exists and has content - if [ -f "v3/UNRELEASED_CHANGELOG.md" ]; then - echo "Found v3/UNRELEASED_CHANGELOG.md" - - # Run the release script in check mode to see if there's content - cd v3/tasks/release - - # Use the release script itself to check for content - if go run release.go --check-only 2>/dev/null; then - echo "has_unreleased_content=true" >> $GITHUB_OUTPUT - echo "โœ… Found unreleased changelog content" - else - echo "has_unreleased_content=false" >> $GITHUB_OUTPUT - echo "โ„น๏ธ No unreleased changelog content found" - fi + # Run the release script in check mode to see if there's content + cd v3/tasks/release + + # Use the release script itself to check for content + if go run release.go --check-only 2>/dev/null; then + echo "has_unreleased_content=true" >> $GITHUB_OUTPUT + echo "โœ… Found unreleased changelog content" else - echo "โš ๏ธ v3/UNRELEASED_CHANGELOG.md not found" echo "has_unreleased_content=false" >> $GITHUB_OUTPUT + echo "โ„น๏ธ No unreleased changelog content found" fi - name: Quick change detection and early exit @@ -126,441 +104,107 @@ jobs: CURRENT_TAG=$(git describe --tags --exact-match HEAD) echo "Current commit has release tag: $CURRENT_TAG" - # Get the tag creation date - TAG_DATE=$(git log -1 --format=%aI "$CURRENT_TAG") - if [ -z "$TAG_DATE" ]; then - echo "Failed to obtain tag date, proceeding with conservative fallback" - TAG_DATE="1970-01-01T00:00:00Z" - fi - echo "Tag date: $TAG_DATE" - - # Compare this commit date with tag date - COMMIT_DATE=$(git log -1 --format=%aI HEAD) - echo "Commit date: $COMMIT_DATE" - - # If the commit is newer than the tag, then it means there are changes - if [ "$COMMIT_DATE" \> "$TAG_DATE" ]; then - echo "Commit is newer than the tag. Proceeding with release." - echo "has_changes=true" >> $GITHUB_OUTPUT - echo "should_continue=true" >> $GITHUB_OUTPUT - echo "reason=Commit newer than tag" >> $GITHUB_OUTPUT - else - echo "Commit is the same as the tag. No new changes." + # For tagged commits, check if there are changes since the tag + COMMIT_COUNT=$(git rev-list ${CURRENT_TAG}..HEAD --count) + if [ "$COMMIT_COUNT" -eq 0 ]; then echo "has_changes=false" >> $GITHUB_OUTPUT echo "should_continue=false" >> $GITHUB_OUTPUT echo "reason=No changes since existing tag $CURRENT_TAG and no unreleased changelog content" >> $GITHUB_OUTPUT + else + echo "has_changes=true" >> $GITHUB_OUTPUT + echo "should_continue=true" >> $GITHUB_OUTPUT fi - exit 0 - fi - - echo "Checking against the latest existing release tag..." - - # Find the latest release tag matching v3-alpha - LATEST_TAG=$(git tag --list 'v3.0.0-alpha.*' --sort=-v:refname | head -n 1) - echo "Latest tag: $LATEST_TAG" - - if [ -z "$LATEST_TAG" ]; then - echo "No previous release found, proceeding with release" - echo "has_changes=true" >> $GITHUB_OUTPUT - echo "should_continue=true" >> $GITHUB_OUTPUT - echo "reason=No previous tag found" >> $GITHUB_OUTPUT - exit 0 - fi - - # Compare against the latest release tag - if git diff --quiet "$LATEST_TAG"..HEAD -- v3; then - echo "No changes detected since latest release $LATEST_TAG and no unreleased changelog content" - echo "has_changes=false" >> $GITHUB_OUTPUT - echo "should_continue=false" >> $GITHUB_OUTPUT - echo "reason=No changes since latest release $LATEST_TAG and no unreleased changelog content" >> $GITHUB_OUTPUT else - echo "Changes detected since latest release $LATEST_TAG" - echo "has_changes=true" >> $GITHUB_OUTPUT - echo "should_continue=true" >> $GITHUB_OUTPUT - echo "reason=Changes detected since latest release $LATEST_TAG" >> $GITHUB_OUTPUT + # No current tag, check against latest release + LATEST_TAG=$(git tag --list "v3.0.0-alpha.*" | sort -V | tail -1) + if [ -z "$LATEST_TAG" ]; then + echo "No previous release found, proceeding with release" + echo "has_changes=true" >> $GITHUB_OUTPUT + echo "should_continue=true" >> $GITHUB_OUTPUT + else + COMMIT_COUNT=$(git rev-list ${LATEST_TAG}..HEAD --count) + if [ "$COMMIT_COUNT" -gt 0 ]; then + echo "Found $COMMIT_COUNT commits since $LATEST_TAG" + echo "has_changes=true" >> $GITHUB_OUTPUT + echo "should_continue=true" >> $GITHUB_OUTPUT + else + echo "has_changes=false" >> $GITHUB_OUTPUT + echo "should_continue=false" >> $GITHUB_OUTPUT + echo "reason=No changes since latest release $LATEST_TAG and no unreleased changelog content" >> $GITHUB_OUTPUT + fi + fi fi - - - name: Early exit if no changes and not forced - if: >- - steps.quick_check.outputs.should_continue == 'false' && + + - name: Early exit - No changes detected + if: | + steps.quick_check.outputs.should_continue == 'false' && github.event.inputs.force_release != 'true' run: | + echo "๐Ÿ›‘ EARLY EXIT: ${{ steps.quick_check.outputs.reason }}" + echo "" echo "โ„น๏ธ No changes detected since last release and force_release is not enabled." - echo " Skipping release to avoid unnecessary version churn." + echo " Workflow will exit early to save resources." + echo "" echo " To force a release anyway, run this workflow with 'force_release=true'" - - # Add summary to GITHUB_STEP_SUMMARY - echo "### Nightly Release Skipped" >> $GITHUB_STEP_SUMMARY - echo "- Reason: ${{ steps.quick_check.outputs.reason }}" >> $GITHUB_STEP_SUMMARY - echo "- Has unreleased changelog content: ${{ steps.changelog_check.outputs.has_unreleased_content }}" >> $GITHUB_STEP_SUMMARY - echo "- Force release: ${{ github.event.inputs.force_release || 'false' }}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + echo "" + echo "## ๐Ÿ›‘ Early Exit Summary" >> $GITHUB_STEP_SUMMARY + echo "**Reason:** ${{ steps.quick_check.outputs.reason }}" >> $GITHUB_STEP_SUMMARY + echo "**Action:** Workflow exited early to save resources" >> $GITHUB_STEP_SUMMARY echo "**Force Release:** Set 'force_release=true' to override this behavior" >> $GITHUB_STEP_SUMMARY - exit 0 - + - name: Continue with release process - if: >- - steps.quick_check.outputs.should_continue == 'true' || + if: | + steps.quick_check.outputs.should_continue == 'true' || github.event.inputs.force_release == 'true' run: | echo "โœ… Proceeding with release process..." if [ "${{ github.event.inputs.force_release }}" == "true" ]; then - echo "๐Ÿšจ FORCE RELEASE: Overriding change detection" + echo "๐Ÿ”จ FORCE RELEASE: Overriding change detection" fi - - - name: Extract changelog content before release - if: >- - steps.changelog_check.outputs.has_unreleased_content == 'true' || + + - name: Run release script + id: release + if: | + steps.quick_check.outputs.should_continue == 'true' || github.event.inputs.force_release == 'true' + env: + WAILS_REPO_TOKEN: ${{ secrets.WAILS_REPO_TOKEN || github.token }} + GITHUB_TOKEN: ${{ secrets.WAILS_REPO_TOKEN || github.token }} run: | - echo "๐Ÿ“ Extracting changelog content before release..." - - # Use the new --create-release-notes flag cd v3/tasks/release - if go run release.go --create-release-notes ../../release_notes.md; then - echo "โœ… Successfully created release notes" - cd ../.. - - # Show release notes preview - echo "Release notes preview:" - head -10 ../../release_notes.md - else - echo "โ„น๏ธ Could not create release notes, continuing without them" - cd ../.. - fi - - - name: Process release and bump version - id: process_release - run: | - echo "๐Ÿ”ข Processing release: updating changelog and bumping version.txt" - cd v3/tasks/release - # Run release processing (updates internal/version/version.txt and changelog) - if go run release.go; then - echo "โœ… Release processing complete" - else - echo "โŒ Release processing failed" - exit 1 - fi - cd ../.. - # Read the new version from version.txt - NEW_VERSION=$(cat v3/internal/version/version.txt | tr -d '\r\n') - if [ -z "$NEW_VERSION" ]; then - echo "โŒ Could not read new version from v3/internal/version/version.txt" - exit 1 - fi - # Ensure tag starts with 'v' - case "$NEW_VERSION" in - v*) NEW_TAG="$NEW_VERSION" ;; - *) NEW_TAG="v$NEW_VERSION" ;; - esac - echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT - echo "tag=$NEW_TAG" >> $GITHUB_OUTPUT - # Nightly v3-alpha are prereleases - echo "is_prerelease=true" >> $GITHUB_OUTPUT - echo "is_latest=false" >> $GITHUB_OUTPUT - echo "version_changed=true" >> $GITHUB_OUTPUT - - - name: Commit updated version and changelog - env: - GITHUB_TOKEN: ${{ secrets.WAILS_REPO_TOKEN }} - run: | - echo "๐Ÿ“ Committing updated version and changelog to v3-alpha" - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add v3/internal/version/version.txt v3/docs/src/content/docs/changelog.mdx v3/UNRELEASED_CHANGELOG.md || true - if git diff --cached --quiet; then - echo "No changes to commit" - else - git commit -m "chore(v3): bump to ${{ steps.process_release.outputs.version }} and update changelog [skip ci]" - git push "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git" HEAD:v3-alpha - fi - - - name: Create and push Git tag - if: >- - steps.process_release.outputs.version_changed == 'true' - env: - GITHUB_TOKEN: ${{ secrets.WAILS_REPO_TOKEN }} - run: | - echo "๐Ÿท๏ธ Creating and pushing git tag: ${{ steps.process_release.outputs.tag }}" - - # Try pushing the tag with debugging and error capture - PUSH_SUCCESS=false - PUSH_OUTPUT=$(cat << 'EOF' - $( - git tag -f "${{ steps.process_release.outputs.tag }}" && - if git push "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git" "${{ steps.process_release.outputs.tag }}" 2>&1; then - echo "SUCCESS" - else - echo "FAILURE" - fi) - EOF - ) - - if echo "$PUSH_OUTPUT" | grep -q "SUCCESS"; then - echo "โœ… Successfully pushed git tag to origin" - PUSH_SUCCESS=true - else - echo "โŒ Failed to push tag. Output:" - echo "$PUSH_OUTPUT" - - # Check if tag already exists on remote - echo "Checking if tag already exists on remote..." - if git ls-remote --tags origin | grep -q "refs/tags/${{ steps.process_release.outputs.tag }}$"; then - echo "โ„น๏ธ Tag already exists on remote, treating as success" - PUSH_SUCCESS=true - else - echo "โŒ Tag does not exist on remote" - fi - fi - - if [ "$PUSH_SUCCESS" != "true" ]; then - echo "โŒ Could not push tag even after retries" - exit 1 - fi - - - name: Create GitHub Release - if: >- - steps.process_release.outputs.version_changed == 'true' - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - echo "๐Ÿš€ Creating GitHub release for tag: ${{ steps.process_release.outputs.tag }}" - - # Prepare release notes content - RELEASE_NOTES_FILE="release_notes.md" - if [ -f "$RELEASE_NOTES_FILE" ]; then - echo "Using generated release notes from $RELEASE_NOTES_FILE" - else - echo "No release notes file found, generating basic notes" - echo "# Release ${{ steps.release.outputs.version }}" > $RELEASE_NOTES_FILE - echo "Generated by nightly release workflow" >> $RELEASE_NOTES_FILE - fi - - echo "Creating release via GitHub API..." - API_URL="https://api.github.com/repos/${{ github.repository }}/releases" - AUTH_HEADER="Authorization: Bearer ${GITHUB_TOKEN}" - ACCEPT_HEADER="Accept: application/vnd.github+json" - USER_AGENT_HEADER="User-Agent: nightly-release-script" - - # Create GitHub release using gh cli if available, fallback to API - if command -v gh >/dev/null 2>&1; then - echo "Using gh CLI to create release" - if gh release create "${{ steps.process_release.outputs.tag }}" \ - --title "${{ steps.process_release.outputs.version }}" \ - --notes-file "$RELEASE_NOTES_FILE" \ - $([ "${{ steps.process_release.outputs.is_prerelease }}" == "true" ] && echo "--prerelease") \ - $([ "${{ steps.process_release.outputs.is_latest }}" == "true" ] && echo "--latest"); then - echo "โœ… GitHub release created successfully using gh CLI" - else - echo "โŒ Failed to create GitHub release using gh CLI" - exit 1 - fi - else - echo "gh CLI not available, using GitHub API" - - RELEASE_DATA=$(jq -n \ - --arg tag_name "${{ steps.process_release.outputs.tag }}" \ - --arg name "${{ steps.process_release.outputs.version }}" \ - --arg body "$(cat "$RELEASE_NOTES_FILE" | sed 's/"/\\"/g')" \ - --argjson prerelease $([ "${{ steps.process_release.outputs.is_prerelease }}" == "true" ] && echo true || echo false) \ - --argjson make_latest $([ "${{ steps.process_release.outputs.is_latest }}" == "true" ] && echo true || echo false) \ - '{ tag_name: $tag_name, name: $name, body: $body, prerelease: $prerelease, make_latest: $make_latest }') - - echo "Release data payload:" - echo "$RELEASE_DATA" | jq '.' - - RESPONSE=$(curl -sS -X POST -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -H "$USER_AGENT_HEADER" -d "$RELEASE_DATA" "$API_URL") - echo "GitHub API response:" - echo "$RESPONSE" | jq '.' - - if echo "$RESPONSE" | jq -e '.id' >/dev/null; then - echo "โœ… GitHub release created successfully via API" - else - echo "โŒ Failed to create GitHub release via API" - exit 1 - fi - fi - - - name: Read generated release notes - id: read_notes - if: >- - steps.process_release.outputs.version_changed == 'true' - run: | - if [ -f "release_notes.md" ]; then - echo "Reading release notes content..." - echo "release_notes<> $GITHUB_OUTPUT - cat release_notes.md >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - else - echo "No release notes file found" - echo "release_notes=" >> $GITHUB_OUTPUT - fi - - - name: Handle GitHub Release Creation Result - id: release_result - if: >- - steps.process_release.outputs.version_changed == 'true' - run: | - echo "๐Ÿ” Checking release result..." - - # Initialize variables - HAS_GITHUB_ERRORS=false - GITHUB_ERRORS="" - - # Check if we can access the release via API - if command -v gh >/dev/null 2>&1; then - echo "Checking release via gh CLI..." - if gh release view "${{ steps.release.outputs.tag }}" >/dev/null 2>&1; then - echo "โœ… Release is accessible via gh CLI" - else - echo "โš ๏ธ Release not accessible via gh CLI" - HAS_GITHUB_ERRORS=true - GITHUB_ERRORS="$GITHUB_ERRORS\n- Release not accessible via gh CLI" - fi - else - echo "gh CLI not available, skipping CLI checks" - fi - - echo "has_github_errors=$HAS_GITHUB_ERRORS" >> $GITHUB_OUTPUT - if [ -n "$GITHUB_ERRORS" ]; then - echo "github_errors=$GITHUB_ERRORS" >> $GITHUB_OUTPUT - else - echo "github_errors=" >> $GITHUB_OUTPUT - fi - - - name: Error Summary and Reporting - id: error_summary - if: always() - run: | - echo "๐Ÿงฎ Generating comprehensive error summary..." - - # Initialize error tracking - TOTAL_ERRORS=0 - ERROR_SUMMARY="" - OVERALL_SUCCESS=true - - # Check for changelog errors - if [ "${{ steps.changelog_check.outputs.has_errors }}" == "true" ]; then - echo "โŒ Changelog processing errors detected" - ERROR_SUMMARY="$ERROR_SUMMARY\n### ๐Ÿ“„ Changelog Processing Errors\n${{ steps.changelog_check.outputs.changelog_errors }}\n" - TOTAL_ERRORS=$((TOTAL_ERRORS + 1)) - OVERALL_SUCCESS=false - fi - - # Check for release script errors - if [ "${{ steps.release.outputs.has_release_errors }}" == "true" ]; then - echo "โŒ Release script errors detected" - ERROR_SUMMARY="$ERROR_SUMMARY\n### ๐Ÿš€ Release Script Errors\n${{ steps.release.outputs.release_errors }}\n" - TOTAL_ERRORS=$((TOTAL_ERRORS + 1)) - OVERALL_SUCCESS=false - fi - - # Check for GitHub release errors - if [ "${{ steps.release_result.outputs.has_github_errors }}" == "true" ]; then - echo "โŒ GitHub release errors detected" - ERROR_SUMMARY="$ERROR_SUMMARY\n### ๐Ÿ™ GitHub Release Errors\n${{ steps.release_result.outputs.github_errors }}\n" - TOTAL_ERRORS=$((TOTAL_ERRORS + 1)) - OVERALL_SUCCESS=false - fi - - # Set outputs for final summary - echo "total_errors=$TOTAL_ERRORS" >> $GITHUB_OUTPUT - echo "overall_success=$OVERALL_SUCCESS" >> $GITHUB_OUTPUT - - if [ -n "$ERROR_SUMMARY" ]; then - echo "error_summary<> $GITHUB_OUTPUT - echo -e "$ERROR_SUMMARY" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - fi - - # Log summary - if [ "$OVERALL_SUCCESS" == "true" ]; then - echo "โœ… Workflow completed successfully with no errors" - else - echo "โš ๏ธ Workflow completed with $TOTAL_ERRORS error categories" + ARGS=() + if [ "${{ github.event.inputs.dry_run }}" == "true" ]; then + ARGS+=(--dry-run) fi + go run release.go "${ARGS[@]}" - name: Summary if: always() run: | if [ "${{ github.event.inputs.dry_run }}" == "true" ]; then - echo "## ๐Ÿงช DRY RUN Release Test Summary" >> $GITHUB_STEP_SUMMARY + echo "## ๐Ÿงช DRY RUN Release Summary" >> $GITHUB_STEP_SUMMARY else echo "## ๐Ÿš€ Nightly Release Summary" >> $GITHUB_STEP_SUMMARY fi echo "================================" >> $GITHUB_STEP_SUMMARY - echo "- **Version:** ${{ steps.process_release.outputs.version }}" >> $GITHUB_STEP_SUMMARY - echo "- **Tag:** ${{ steps.process_release.outputs.tag }}" >> $GITHUB_STEP_SUMMARY - echo "- **Version Changed:** ${{ steps.process_release.outputs.version_changed }}" >> $GITHUB_STEP_SUMMARY - echo "- **Has existing tag:** ${{ steps.check_tag.outputs.has_tag }}" >> $GITHUB_STEP_SUMMARY - echo "- **Has unreleased changelog content:** ${{ steps.changelog_check.outputs.has_unreleased_content }}" >> $GITHUB_STEP_SUMMARY - echo "- **Has changes:** true" >> $GITHUB_STEP_SUMMARY - echo "- **Is prerelease:** ${{ steps.process_release.outputs.is_prerelease }}" >> $GITHUB_STEP_SUMMARY - echo "- **Is latest:** ${{ steps.process_release.outputs.is_latest }}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - # Overall status - if [ "${{ steps.error_summary.outputs.overall_success }}" == "true" ]; then - if [ "${{ github.event.inputs.dry_run }}" == "true" ]; then - echo "- **Mode:** ๐Ÿงช DRY RUN (no actual release created)" >> $GITHUB_STEP_SUMMARY - echo "- **Status:** โœ… Test completed successfully" >> $GITHUB_STEP_SUMMARY + + if [ -n "${{ steps.release.outputs.release_version }}" ]; then + echo "- **Version:** ${{ steps.release.outputs.release_version }}" >> $GITHUB_STEP_SUMMARY + echo "- **Tag:** ${{ steps.release.outputs.release_tag }}" >> $GITHUB_STEP_SUMMARY + echo "- **Status:** ${{ steps.release.outcome == 'success' && 'โœ… Success' || 'โš ๏ธ Failed' }}" >> $GITHUB_STEP_SUMMARY + echo "- **Mode:** ${{ steps.release.outputs.release_dry_run == 'true' && '๐Ÿงช Dry Run' || '๐Ÿš€ Live release' }}" >> $GITHUB_STEP_SUMMARY + if [ -n "${{ steps.release.outputs.release_url }}" ]; then + echo "- **Release URL:** ${{ steps.release.outputs.release_url }}" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Changelog" >> $GITHUB_STEP_SUMMARY + if [ "${{ steps.changelog_check.outputs.has_unreleased_content }}" == "true" ]; then + echo "โœ… Unreleased changelog processed and reset." >> $GITHUB_STEP_SUMMARY else - echo "- **Mode:** ๐Ÿš€ Live release" >> $GITHUB_STEP_SUMMARY - echo "- **Status:** โœ… Release created successfully" >> $GITHUB_STEP_SUMMARY + echo "โ„น๏ธ No unreleased changelog content detected." >> $GITHUB_STEP_SUMMARY fi else - echo "- **Mode:** ${{ github.event.inputs.dry_run == 'true' && '๐Ÿงช DRY RUN' || '๐Ÿš€ Live release' }}" >> $GITHUB_STEP_SUMMARY - echo "- **Status:** โš ๏ธ Completed with ${{ steps.error_summary.outputs.total_errors }} error(s)" >> $GITHUB_STEP_SUMMARY - fi - - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Release Processing" >> $GITHUB_STEP_SUMMARY - if [ "${{ steps.process_release.outputs.version_changed }}" == "true" ]; then - echo "โœ… **Version was incremented** and release created" >> $GITHUB_STEP_SUMMARY - else - echo "โ„น๏ธ **Version was not changed** - no release created" >> $GITHUB_STEP_SUMMARY - fi - - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Changelog Processing" >> $GITHUB_STEP_SUMMARY - if [ "${{ steps.changelog_check.outputs.has_unreleased_content }}" == "true" ]; then - echo "โœ… **UNRELEASED_CHANGELOG.md** had content and was processed" >> $GITHUB_STEP_SUMMARY - echo "- Content moved to main changelog" >> $GITHUB_STEP_SUMMARY - echo "- UNRELEASED_CHANGELOG.md reset with template" >> $GITHUB_STEP_SUMMARY - else - echo "โ„น๏ธ **UNRELEASED_CHANGELOG.md** had no content to process" >> $GITHUB_STEP_SUMMARY - fi - - # Error reporting section - if [ "${{ steps.error_summary.outputs.total_errors }}" -gt 0 ]; then - echo "" >> $GITHUB_STEP_SUMMARY - echo "## โš ๏ธ Error Report" >> $GITHUB_STEP_SUMMARY - echo "**Total Error Categories:** ${{ steps.error_summary.outputs.total_errors }}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "${{ steps.error_summary.outputs.error_summary }}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### ๐Ÿ”ง Troubleshooting Tips" >> $GITHUB_STEP_SUMMARY - echo "- Check the individual step logs above for detailed error messages" >> $GITHUB_STEP_SUMMARY - echo "- Verify GitHub token permissions (contents: write, pull-requests: read)" >> $GITHUB_STEP_SUMMARY - echo "- Ensure UNRELEASED_CHANGELOG.md follows the expected format" >> $GITHUB_STEP_SUMMARY - echo "- Check for network connectivity issues if git/GitHub operations failed" >> $GITHUB_STEP_SUMMARY - echo "- Re-run the workflow with 'force_release=true' if needed" >> $GITHUB_STEP_SUMMARY - fi - - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Release Notes Preview" >> $GITHUB_STEP_SUMMARY - if [ -n "${{ steps.read_notes.outputs.release_notes }}" ]; then - echo "${{ steps.read_notes.outputs.release_notes }}" >> $GITHUB_STEP_SUMMARY - else - echo "No specific release notes generated" >> $GITHUB_STEP_SUMMARY - fi - echo "" >> $GITHUB_STEP_SUMMARY - echo "---" >> $GITHUB_STEP_SUMMARY - echo "*Generated by automated nightly release workflow with enhanced error handling and changelog integration*" >> $GITHUB_STEP_SUMMARY - - # Set final workflow status - if [ "${{ steps.error_summary.outputs.overall_success }}" != "true" ]; then - echo "โš ๏ธ Workflow completed with errors. Check the summary above for details." - exit 1 + echo "- Release script did not run (skipped or failed before execution)." >> $GITHUB_STEP_SUMMARY fi + diff --git a/.github/workflows/pr-master.yml b/.github/workflows/pr-master.yml index 00c0f9103..c961b4434 100644 --- a/.github/workflows/pr-master.yml +++ b/.github/workflows/pr-master.yml @@ -1,17 +1,26 @@ -name: PR Checks (master) - +# Updated to ensure "Run Go Tests" runs for pull requests as expected. +# Key fix: the test_go job previously required github.event.review.state == 'approved' +# which only exists on pull_request_review events. That prevented the job from +# running for regular pull_request events (opened / synchronize / reopened). +# New logic: run tests for pull_request events, and also allow running when a +# pull_request_review is submitted with state == 'approved'. on: pull_request: + types: [opened, synchronize, reopened] branches: - master pull_request_review: types: [submitted] branches: - master + workflow_dispatch: {} + +name: PR Checks (master) + jobs: check_docs: name: Check Docs - if: ${{github.repository == 'wailsapp/wails' && github.base_ref == 'master'}} + if: ${{ github.repository == 'wailsapp/wails' && github.base_ref == 'master' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -23,7 +32,6 @@ jobs: files: | website/**/*.mdx website/**/*.md - - name: Run step only when files change. if: steps.verify-changed-files.outputs.files_changed != 'true' run: | @@ -32,11 +40,18 @@ jobs: test_go: name: Run Go Tests runs-on: ${{ matrix.os }} + # Run when: + # - the event is a pull_request (opened/synchronize/reopened) OR + # - the event is a pull_request_review AND the review state is 'approved' + # plus other existing filters (not the update-sponsors branch, repo and base_ref) if: > + github.repository == 'wailsapp/wails' && + github.base_ref == 'master' && github.event.pull_request.head.ref != 'update-sponsors' && - github.event.review.state == 'approved' && - github.repository == 'wailsapp/wails' && - github.base_ref == 'master' + ( + github.event_name == 'pull_request' || + (github.event_name == 'pull_request_review' && github.event.review.state == 'approved') + ) strategy: matrix: os: [ubuntu-22.04, windows-latest, macos-latest, ubuntu-24.04] diff --git a/README.de.md b/README.de.md index b1616d2f9..5df35de5b 100644 --- a/README.de.md +++ b/README.de.md @@ -25,7 +25,7 @@ Erschaffe Desktop Anwendungen mit Go & Web Technologien. Awesome - Discord + Discord
diff --git a/README.es.md b/README.es.md index 59cbcf132..277d1c1fd 100644 --- a/README.es.md +++ b/README.es.md @@ -25,7 +25,7 @@ Awesome - Discord + Discord
diff --git a/README.fr.md b/README.fr.md index 2f405b46a..61230f353 100644 --- a/README.fr.md +++ b/README.fr.md @@ -25,7 +25,7 @@ Awesome - Discord + Discord
diff --git a/README.ja.md b/README.ja.md index d4edb662c..ffd9f8103 100644 --- a/README.ja.md +++ b/README.ja.md @@ -27,7 +27,7 @@ Awesome - Discord + Discord
diff --git a/README.ko.md b/README.ko.md index fc27dfbe1..075e04229 100644 --- a/README.ko.md +++ b/README.ko.md @@ -27,7 +27,7 @@ Awesome - Discord + Discord
diff --git a/README.md b/README.md index 12ff1d6dc..dd46cf8d0 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Awesome - Discord + Discord
diff --git a/README.pt-br.md b/README.pt-br.md index 8129ac853..0e3883352 100644 --- a/README.pt-br.md +++ b/README.pt-br.md @@ -25,7 +25,7 @@ Awesome - Discord + Discord
diff --git a/README.ru.md b/README.ru.md index 4a24b9bcb..76fa59d07 100644 --- a/README.ru.md +++ b/README.ru.md @@ -25,7 +25,7 @@ Awesome - Discord + Discord
diff --git a/README.tr.md b/README.tr.md index b9e88c0b9..e9b16ca76 100644 --- a/README.tr.md +++ b/README.tr.md @@ -25,7 +25,7 @@ Awesome - Discord + Discord
diff --git a/README.uz.md b/README.uz.md index 88744e94e..807262405 100644 --- a/README.uz.md +++ b/README.uz.md @@ -25,7 +25,7 @@ Awesome - Discord + Discord
diff --git a/README.zh-Hans.md b/README.zh-Hans.md index baeeb420e..4c09d0c45 100644 --- a/README.zh-Hans.md +++ b/README.zh-Hans.md @@ -27,7 +27,7 @@ Awesome - Discord + Discord
diff --git a/v2/examples/customlayout/go.mod b/v2/examples/customlayout/go.mod index c7ead2202..e1a17304e 100644 --- a/v2/examples/customlayout/go.mod +++ b/v2/examples/customlayout/go.mod @@ -27,7 +27,7 @@ require ( github.com/tkrajina/go-reflector v0.5.8 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/wailsapp/go-webview2 v1.0.19 // indirect + github.com/wailsapp/go-webview2 v1.0.22 // indirect github.com/wailsapp/mimetype v1.4.1 // indirect golang.org/x/crypto v0.33.0 // indirect golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect diff --git a/v2/examples/customlayout/go.sum b/v2/examples/customlayout/go.sum index d5caf9fef..f1995affb 100644 --- a/v2/examples/customlayout/go.sum +++ b/v2/examples/customlayout/go.sum @@ -72,6 +72,7 @@ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/wailsapp/go-webview2 v1.0.10 h1:PP5Hug6pnQEAhfRzLCoOh2jJaPdrqeRgJKZhyYyDV/w= github.com/wailsapp/go-webview2 v1.0.10/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc= +github.com/wailsapp/go-webview2 v1.0.22/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc= github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= diff --git a/v2/internal/frontend/desktop/linux/menu.go b/v2/internal/frontend/desktop/linux/menu.go index 557a24b37..a61d190bd 100644 --- a/v2/internal/frontend/desktop/linux/menu.go +++ b/v2/internal/frontend/desktop/linux/menu.go @@ -34,8 +34,11 @@ void addAccelerator(GtkWidget* menuItem, GtkAccelGroup* group, guint key, GdkMod } */ import "C" -import "github.com/wailsapp/wails/v2/pkg/menu" -import "unsafe" +import ( + "unsafe" + + "github.com/wailsapp/wails/v2/pkg/menu" +) var menuIdCounter int var menuItemToId map[*menu.MenuItem]int @@ -81,8 +84,10 @@ func (w *Window) SetApplicationMenu(inmenu *menu.Menu) { func processMenu(window *Window, menu *menu.Menu) { for _, menuItem := range menu.Items { - submenu := processSubmenu(menuItem, window.accels) - C.gtk_menu_shell_append(C.toGtkMenuShell(unsafe.Pointer(window.menubar)), submenu) + if menuItem.SubMenu != nil { + submenu := processSubmenu(menuItem, window.accels) + C.gtk_menu_shell_append(C.toGtkMenuShell(unsafe.Pointer(window.menubar)), submenu) + } } } diff --git a/v2/internal/frontend/desktop/windows/frontend.go b/v2/internal/frontend/desktop/windows/frontend.go index c052fc228..28b97b239 100644 --- a/v2/internal/frontend/desktop/windows/frontend.go +++ b/v2/internal/frontend/desktop/windows/frontend.go @@ -28,11 +28,13 @@ import ( "github.com/wailsapp/wails/v2/internal/frontend/originvalidator" wailsruntime "github.com/wailsapp/wails/v2/internal/frontend/runtime" "github.com/wailsapp/wails/v2/internal/logger" + w32consts "github.com/wailsapp/wails/v2/internal/platform/win32" "github.com/wailsapp/wails/v2/internal/system/operatingsystem" "github.com/wailsapp/wails/v2/pkg/assetserver" "github.com/wailsapp/wails/v2/pkg/assetserver/webview" "github.com/wailsapp/wails/v2/pkg/options" "github.com/wailsapp/wails/v2/pkg/options/windows" + w "golang.org/x/sys/windows" ) const startURL = "http://wails.localhost/" @@ -75,6 +77,13 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger. // Get Windows build number versionInfo, _ := operatingsystem.GetWindowsVersionInfo() + // Apply DLL search path settings if specified + if appoptions.Windows != nil && appoptions.Windows.DLLSearchPaths != 0 { + w.SetDefaultDllDirectories(appoptions.Windows.DLLSearchPaths) + } + // Now initialize packages that load DLLs + w32.Init() + w32consts.Init() result := &Frontend{ frontendOptions: appoptions, logger: myLogger, diff --git a/v2/internal/frontend/desktop/windows/winc/w32/uxtheme.go b/v2/internal/frontend/desktop/windows/winc/w32/uxtheme.go index ed80d487f..8a14f0cb7 100644 --- a/v2/internal/frontend/desktop/windows/winc/w32/uxtheme.go +++ b/v2/internal/frontend/desktop/windows/winc/w32/uxtheme.go @@ -69,7 +69,7 @@ var ( setWindowTheme uintptr ) -func init() { +func Init() { // Library libuxtheme = MustLoadLibrary("uxtheme.dll") diff --git a/v2/internal/platform/win32/consts.go b/v2/internal/platform/win32/consts.go index 03f42b1a6..43149b036 100644 --- a/v2/internal/platform/win32/consts.go +++ b/v2/internal/platform/win32/consts.go @@ -80,7 +80,7 @@ ShouldSystemUseDarkMode = bool () // ordinal 138 SetPreferredAppMode = PreferredAppMode (PreferredAppMode appMode) // ordinal 135, since 18334 IsDarkModeAllowedForApp = bool () // ordinal 139 */ -func init() { +func Init() { if IsWindowsVersionAtLeast(10, 0, 18334) { // AllowDarkModeForWindow is only available on Windows 10+ diff --git a/v2/pkg/options/windows/windows.go b/v2/pkg/options/windows/windows.go index aa065ecd9..1fe351455 100644 --- a/v2/pkg/options/windows/windows.go +++ b/v2/pkg/options/windows/windows.go @@ -35,6 +35,27 @@ const ( Tabbed BackdropType = 4 ) +const ( + // Default is 0, which means no changes to the default Windows DLL search behavior + DLLSearchDefault uint32 = 0 + // LoadLibrary flags for determining from where to search for a DLL + DLLSearchDontResolveDllReferences uint32 = 0x1 // windows.DONT_RESOLVE_DLL_REFERENCES + DLLSearchAsDataFile uint32 = 0x2 // windows.LOAD_LIBRARY_AS_DATAFILE + DLLSearchWithAlteredPath uint32 = 0x8 // windows.LOAD_WITH_ALTERED_SEARCH_PATH + DLLSearchIgnoreCodeAuthzLevel uint32 = 0x10 // windows.LOAD_IGNORE_CODE_AUTHZ_LEVEL + DLLSearchAsImageResource uint32 = 0x20 // windows.LOAD_LIBRARY_AS_IMAGE_RESOURCE + DLLSearchAsDataFileExclusive uint32 = 0x40 // windows.LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE + DLLSearchRequireSignedTarget uint32 = 0x80 // windows.LOAD_LIBRARY_REQUIRE_SIGNED_TARGET + DLLSearchDllLoadDir uint32 = 0x100 // windows.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR + DLLSearchApplicationDir uint32 = 0x200 // windows.LOAD_LIBRARY_SEARCH_APPLICATION_DIR + DLLSearchUserDirs uint32 = 0x400 // windows.LOAD_LIBRARY_SEARCH_USER_DIRS + DLLSearchSystem32 uint32 = 0x800 // windows.LOAD_LIBRARY_SEARCH_SYSTEM32 + DLLSearchDefaultDirs uint32 = 0x1000 // windows.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS + DLLSearchSafeCurrentDirs uint32 = 0x2000 // windows.LOAD_LIBRARY_SAFE_CURRENT_DIRS + DLLSearchSystem32NoForwarder uint32 = 0x4000 // windows.LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER + DLLSearchOsIntegrityContinuity uint32 = 0x8000 // windows.LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY +) + func RGB(r, g, b uint8) int32 { col := int32(b) col = col<<8 | int32(g) @@ -122,6 +143,11 @@ type Options struct { // Class name for the window. If empty, 'wailsWindow' will be used. WindowClassName string + + // DLLSearchPaths controls which directories are searched when loading DLLs + // Set to 0 for default behavior, or combine multiple flags with bitwise OR + // Example: DLLSearchApplicationDir | DLLSearchSystem32 + DLLSearchPaths uint32 } func DefaultMessages() *Messages { diff --git a/website/docs/community/showcase/clustta.mdx b/website/docs/community/showcase/clustta.mdx new file mode 100644 index 000000000..7da3195df --- /dev/null +++ b/website/docs/community/showcase/clustta.mdx @@ -0,0 +1,27 @@ +--- +title: Clustta +description: File manager and project management tool for creative professionals. +slug: /community/showcase/clustta +image: /img/showcase/clustta.png +--- + +
+ Clustta screenshot +
+ +[Clustta](https://clustta.com) is a file manager and project management tool designed for creative professionals. Built with Wails, it simplifies file management, collaboration, and version control for creative workflows. + +## Features + +- **File Management**: Track all projects and files with easy access even months after completion. +- **Version Control**: Save unlimited revisions with descriptive notes, without duplicating files. +- **Collaboration**: Share files or entire projects securely through simple user tags with fine-grained permissions. +- **Recovery**: Restore corrupted files from saved checkpoints if your software crashes. +- **Templates**: Quick start with preset project and task templates. +- **Kanban Boards**: Visual task tracking to keep tasks organized. +- **Dependencies**: Track and version project resources and dependencies. +- **Checkpoints**: Create memorable milestones and explore alternate creative directions non-destructively. +- **Search & Filters**: Powerful instant search with metadata filtering (task types, tags, status, file extensions). +- **Workspaces**: Save search and filter combinations for easy access to specific task sets. +- **Integrations**: Connect with creative software packages and production management tools like Blender and Kitsu. +- **Self-Hosting**: Host private instances for teams or studios on your own servers. diff --git a/website/src/pages/changelog.mdx b/website/src/pages/changelog.mdx index 08bbf4f7f..2213dc516 100644 --- a/website/src/pages/changelog.mdx +++ b/website/src/pages/changelog.mdx @@ -26,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added url validation for BrowserOpenURL by @APshenkin in [PR](https://github.com/wailsapp/wails/pull/4484) - Fixed C compilation error in onWayland on Linux due to declaration after label [#4446](https://github.com/wailsapp/wails/pull/4446) by [@jaesung9507](https://github.com/jaesung9507) - Use computed style when adding 'wails-drop-target-active' [PR](https://github.com/wailsapp/wails/pull/4420) by [@riannucci](https://github.com/riannucci) +- Fixed panic when adding menuroles on Linux [#4558](https://github.com/wailsapp/wails/pull/4558) by [@jaesung9507](https://github.com/jaesung9507) +- Fixed Discord badge in README by @sharkmu in [PR](https://github.com/wailsapp/wails/pull/4626) ## v2.10.2 - 2025-07-06 @@ -42,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated documentation to display the correct copyright year in [#4243](https://github.com/wailsapp/wails/pull/4243) by [@nnashwin](https://github.com/nnashwin) ### Added +- Added DLLSearchPaths option to control DLL search paths on Windows in [#4207](https://github.com/wailsapp/wails/pull/4207) by @ansxuman - Added "Branding" section to `wails doctor` to correctly identify Windows 11 [#3891](https://github.com/wailsapp/wails/pull/3891) by [@ronen25](https://github.com/ronen25) - Added `-skipembedcreate` flag to build and dev command to improve compile and recompile speed [#4143](https://github.com/wailsapp/wails/pull/4143) by @josStorer - Added `DisablePanicRecovery` option to allow handle panics manually [#4136](https://github.com/wailsapp/wails/pull/4136) by [@APshenkin](https://github.com/APshenkin) diff --git a/website/static/img/showcase/clustta.png b/website/static/img/showcase/clustta.png new file mode 100644 index 000000000..6d131b6a8 Binary files /dev/null and b/website/static/img/showcase/clustta.png differ diff --git a/website/static/img/sponsors.svg b/website/static/img/sponsors.svg index 49933a096..805bba4f8 100644 --- a/website/static/img/sponsors.svg +++ b/website/static/img/sponsors.svg @@ -1,4 +1,4 @@ - + -Partner - Galaxy +Silver Sponsors + letheanVPN - - + + - -Silver Sponsors - Webtize - - - - - + - Orb + Orb - + - -Bronze Sponsors - Cody Bentley + +Bronze Sponsors + Cody Bentley - + - + - Kazuya Gokita + Kazuya Gokita - + - - - - Simon Thomas - - - - - + - CodeRabbit + CodeRabbit - - + + - + - Daniel Grice + Daniel Grice - + - + - Argus Labs + Argus Labs - + - -Covering Costs - Marcus + +Covering Costs + Marcus - + - + - John + John - + - + - Iain + Iain - + - + - Michael + Michael - + - -Buying Breakfast - Tai Groot + +Buying Breakfast + Tai Groot - + - + - Tom Wu + Tom Wu - + - - - - igops - - - - - + - vaaski + vaaski - + - + - Sander + Sander - + - + - Kevin + Kevin - + - + - elapse2039 + elapse2039 - + - + - Zach + Zach - + - -Buying Coffee + +Buying Coffee - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - -Helpers + + + + + + + + +Helpers - + - + - + - + - + - + - + - + - + - - - - - - - - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + diff --git a/website/versioned_docs/version-v2.10/community/templates.mdx b/website/versioned_docs/version-v2.10/community/templates.mdx index 9eac30478..776ec1742 100644 --- a/website/versioned_docs/version-v2.10/community/templates.mdx +++ b/website/versioned_docs/version-v2.10/community/templates.mdx @@ -28,6 +28,7 @@ If you are unsure about a template, inspect `package.json` and `wails.json` for - [wails-template-quasar-ts](https://github.com/sgosiaco/wails-template-quasar-ts) - A template using TypeScript + Quasar V2 (Vue 3, Vite, Sass, Pinia, ESLint, Prettier, Composition API with <script setup>) - [wails-template-naive](https://github.com/tk103331/wails-template-naive) - Wails template based on Naive UI (A Vue 3 Component Library) - [wails-template-tdesign-js](https://github.com/tongque0/wails-template-tdesign-js) - Wails template based on TDesign UI (a Vue 3 UI library by Tencent), using Vite, Pinia, Vue Router, ESLint, and Prettier. +- [wails-template-arcodesign-ts](https://github.com/fengfengzhidao/wails-template-arcodesign-ts) - Wails template based on ArcoDesign UI (a Vue 3 UI library by ArcoDesign), using Vite, Pinia, Vue Router. ## Angular