Daily LeetCode Challenge #108
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: Daily LeetCode Challenge | |
| on: | |
| schedule: | |
| # Run at 00:30 UTC every day (08:30 Beijing time) | |
| - cron: '30 0 * * *' | |
| workflow_dispatch: | |
| inputs: | |
| problem_id: | |
| description: 'Problem ID to solve (optional)' | |
| required: false | |
| default: '' | |
| # Prevent concurrent runs | |
| concurrency: | |
| group: daily-challenge | |
| cancel-in-progress: false | |
| jobs: | |
| solve: | |
| name: Solve Daily Challenge | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y cmake build-essential ccache ninja-build just | |
| - name: Setup ccache | |
| uses: hendrikmuhs/ccache-action@v1.2 | |
| with: | |
| # Daily challenge uses its own primary cache key | |
| # but can restore from CI's full build cache for faster initial builds | |
| key: ${{ runner.os }}-gcc-daily-challenge-${{ github.run_id }} | |
| restore-keys: | | |
| ${{ runner.os }}-gcc-daily-challenge- | |
| ${{ runner.os }}-gcc-full- | |
| ${{ runner.os }}-gcc-incremental- | |
| ${{ runner.os }}-gcc- | |
| max-size: 500M | |
| - name: Set up Python virtual environment | |
| run: | | |
| python3 -m venv venv | |
| source venv/bin/activate | |
| pip install --upgrade pip | |
| pip install -r requirements.txt | |
| - name: Run AI solver | |
| env: | |
| MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }} | |
| AI_SOLVER_GENERATE_REPORT: 'true' | |
| LEETCODE_COOKIE: ${{ secrets.LEETCODE_COOKIE }} | |
| run: | | |
| source venv/bin/activate | |
| if [ -n "${{ github.event.inputs.problem_id }}" ]; then | |
| python -m script.leetcode.ai.solver ${{ github.event.inputs.problem_id }} --report | |
| else | |
| python -m script.leetcode.ai.solver --report | |
| fi | |
| continue-on-error: true | |
| - name: Get problem info | |
| id: get_info | |
| run: | | |
| # Check SKIP_PR flag first | |
| if [ -f "SKIP_PR" ]; then | |
| echo "should_skip=true" >> $GITHUB_OUTPUT | |
| echo "skip_reason=$(cat SKIP_PR)" >> $GITHUB_OUTPUT | |
| echo "Skipping PR creation - $(cat SKIP_PR)" | |
| exit 0 | |
| else | |
| echo "should_skip=false" >> $GITHUB_OUTPUT | |
| fi | |
| REPORT_FILE=$(ls SOLUTION_REPORT_*.md 2>/dev/null | head -1) | |
| PROBLEM_ID=$(echo ${REPORT_FILE#SOLUTION_REPORT_} | sed 's/\.md$//') | |
| echo "problem_id=${PROBLEM_ID:-}" >> $GITHUB_OUTPUT | |
| echo "report_file=${REPORT_FILE:-}" >> $GITHUB_OUTPUT | |
| echo "has_solution=false" >> $GITHUB_OUTPUT | |
| [ -z "$REPORT_FILE" ] && echo "No solution report found" && exit 0 | |
| echo "Found report: $REPORT_FILE (ID: $PROBLEM_ID)" | |
| # Check both new files (??) and modified files (M) | |
| SOURCE_FILE=$(git status --porcelain | grep -E '^(\?\?| M)' | grep 'src/leetcode/problems/.*\.cpp$' | awk '{print $2}' | head -1) | |
| HEADER_FILE=$(git status --porcelain | grep -E '^(\?\?| M)' | grep 'include/leetcode/problems/.*\.h$' | awk '{print $2}' | head -1) | |
| TEST_FILE=$(git status --porcelain | grep -E '^(\?\?| M)' | grep 'test/leetcode/problems/.*\.cpp$' | awk '{print $2}' | head -1) | |
| if [ -n "$SOURCE_FILE" ] && [ -n "$HEADER_FILE" ] && [ -n "$TEST_FILE" ]; then | |
| PROBLEM_SLUG=$(basename "$SOURCE_FILE" .cpp) | |
| echo "problem_slug=$PROBLEM_SLUG" >> $GITHUB_OUTPUT | |
| echo "has_solution=true" >> $GITHUB_OUTPUT | |
| echo "source_file=$SOURCE_FILE" >> $GITHUB_OUTPUT | |
| echo "header_file=$HEADER_FILE" >> $GITHUB_OUTPUT | |
| echo "test_file=$TEST_FILE" >> $GITHUB_OUTPUT | |
| echo "All required files found for: $PROBLEM_SLUG" | |
| else | |
| echo "Incomplete files generated" | |
| [ -z "$SOURCE_FILE" ] && echo " - Missing source file" | |
| [ -z "$HEADER_FILE" ] && echo " - Missing header file" | |
| [ -z "$TEST_FILE" ] && echo " - Missing test file" | |
| fi | |
| - name: Build and test solution | |
| if: steps.get_info.outputs.has_solution == 'true' | |
| run: | | |
| PROBLEM_SLUG="${{ steps.get_info.outputs.problem_slug }}" | |
| echo "Building and testing: $PROBLEM_SLUG" | |
| mkdir -p build && cd build | |
| cmake .. -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=Debug \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ | |
| -DLEETCODE_SINGLE_PROBLEM="$PROBLEM_SLUG" | |
| cmake --build . -j | |
| ./bin/single_problem_test | |
| - name: Update documentation | |
| if: steps.get_info.outputs.has_solution == 'true' | |
| run: | | |
| # Generate updated SOLVED.md | |
| source venv/bin/activate | |
| just doc | |
| # Check if SOLVED.md was updated | |
| if git diff --quiet SOLVED.md 2>/dev/null; then | |
| echo "No changes to SOLVED.md" | |
| else | |
| echo "SOLVED.md updated" | |
| fi | |
| - name: Upload artifacts | |
| if: steps.get_info.outputs.report_file != '' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: solution-problem-${{ steps.get_info.outputs.problem_id }} | |
| path: | | |
| ${{ steps.get_info.outputs.report_file }} | |
| ${{ steps.get_info.outputs.source_file }} | |
| ${{ steps.get_info.outputs.header_file }} | |
| ${{ steps.get_info.outputs.test_file }} | |
| retention-days: 7 | |
| if-no-files-found: ignore | |
| - name: Create Pull Request | |
| if: steps.get_info.outputs.has_solution == 'true' && steps.get_info.outputs.should_skip != 'true' && success() | |
| uses: peter-evans/create-pull-request@v5 | |
| with: | |
| commit-message: "feat: Add solution for LeetCode #${{ steps.get_info.outputs.problem_id }}" | |
| title: "🤖 Daily Challenge: Problem #${{ steps.get_info.outputs.problem_id }}" | |
| body-path: ${{ steps.get_info.outputs.report_file }} | |
| branch: daily-challenge/${{ steps.get_info.outputs.problem_id }} | |
| base: main | |
| labels: | | |
| daily-challenge | |
| ai-generated | |
| draft: false | |
| delete-branch: true | |
| # Include all changes: new problem files + updated SOLVED.md | |
| add-paths: | | |
| src/leetcode/problems/ | |
| include/leetcode/problems/ | |
| test/leetcode/problems/ | |
| SOLVED.md |