Deepthi
Deepthi

Reputation: 1

# GitHub Actions Workflow: Excluded folders still appearing in generated Pull Request despite using filtered tree

** Description:

I'm experiencing an issue with a GitHub Actions workflow that creates Pull Requests while attempting to exclude specific folders.

** Current Behavior:

Expected Behavior:

Technical Details:

Code Implementation:

// Filtering implementation in the workflow

const excludedPaths = ['.github/workflows', 'tests'];

const filteredTree = baseTree.data.tree.filter(item => {

    return !excludedPaths.some(excludedPath => 

        item.path === excludedPath || 

        item.path.startsWith(excludedPath + '/')

    );

});

Here's the complete workflow file:

   name: Deploy to Environment
     
    permissions:
    
      contents: write
    
      actions: write
    
      pull-requests: write
     
    on:
    
      workflow_dispatch:
    
        inputs:
    
          base_branch:
    
            description: 'Base Branch to deploy from'
    
            required: true
    
            default: 'Feature/Auto-Unit-Testing-Main'
    
            type: choice
    
            options:
    
              - Feature/Auto-Unit-Testing-Main
    
              - Feature/Auto-Unit-Testing-Dev
    
              - Feature/Auto-Unit-Testing-qa
     
          environment:
    
            description: 'Target Environment'
    
            required: true
    
            default: 'Feature/Auto-Unit-Testing-Dev'
    
            type: choice
    
            options:
    
              - Feature/Auto-Unit-Testing-Dev
    
              - Feature/Auto-Unit-Testing-qa
     
          pr_title:
    
            description: 'Pull Request Title'
    
            required: true
    
            type: string
    
            default: 'Deploy to target environment'
     
          pr_description:
    
            description: 'Initial Pull Request Description'
    
            required: true
    
            type: string
    
            default: 'Deployment changes from source to target environment'
     
      push:
    
        branches:
    
          - Feature/Auto-Unit-Testing-Main
    
          - Feature/Auto-Unit-Testing-Dev
    
          - Feature/Auto-Unit-Testing-qa
     
    jobs:
    
      prepare-deployment:
    
        runs-on: self-hosted
    
        outputs:
    
          target_branch: ${{ steps.set-target.outputs.branch }}
    
        steps:
    
          - name: Set Target Branch
    
            id: set-target
    
            run: |
    
              if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
    
                TARGET_BRANCH="${{ github.event.inputs.environment }}"
    
              else
    
                TARGET_BRANCH="Feature/Auto-Unit-Testing-Dev"
    
              fi
    
              echo "branch=$TARGET_BRANCH" >> $GITHUB_OUTPUT
    
              echo "Deploying to: $TARGET_BRANCH"
     
      create-pr:
    
        needs: prepare-deployment
    
        runs-on: self-hosted
    
        if: github.event_name == 'workflow_dispatch'
    
        outputs:
    
          pr_url: ${{ steps.create-pr.outputs.pr_url }}
    
          pr_number: ${{ steps.create-pr.outputs.pr_number }}
    
        steps:
    
          - name: Create Pull Request with Excluded Paths
    
            id: create-pr
    
            uses: actions/github-script@v6
    
            with:
    
              script: |
    
                try {
    
                  // Get the base branch reference
    
                  const baseRef = await github.rest.git.getRef({
    
                    owner: context.repo.owner,
    
                    repo: context.repo.repo,
    
                    ref: `heads/${{ github.event.inputs.base_branch }}`
    
                  });
     
                  // Get the commit for the base branch
    
                  const baseCommit = await github.rest.git.getCommit({
    
                    owner: context.repo.owner,
    
                    repo: context.repo.repo,
    
                    commit_sha: baseRef.data.object.sha
    
                  });
     
                  // Get the tree for the base commit
    
                  const baseTree = await github.rest.git.getTree({
    
                    owner: context.repo.owner,
    
                    repo: context.repo.repo,
    
                    tree_sha: baseCommit.data.tree.sha,
    
                    recursive: true
    
                  });
     
                  // Define paths to exclude
    
                  const excludedPaths = ['.github/workflows', 'tests'];
     
                  // Filter the tree to exclude specified paths
    
                  const filteredTree = baseTree.data.tree.filter(item => {
    
                    return !excludedPaths.some(excludedPath => 
    
                      item.path === excludedPath || // Exact match
    
                      item.path.startsWith(excludedPath + '/') // Files within folder
    
                    );
    
                  });
     
                  // Create a new tree with the filtered content
    
                  const newTree = await github.rest.git.createTree({
    
                    owner: context.repo.owner,
    
                    repo: context.repo.repo,
    
                    base_tree: baseCommit.data.tree.sha,
    
                    tree: filteredTree.map(item => ({
    
                      path: item.path,
    
                      mode: item.mode,
    
                      type: item.type,
    
                      sha: item.sha
    
                    }))
    
                  });
     
                  // Create a new commit with the new tree
    
                  const newCommit = await github.rest.git.createCommit({
    
                    owner: context.repo.owner,
    
                    repo: context.repo.repo,
    
                    message: 'Filtered deployment commit (excluding workflows and tests)',
    
                    tree: newTree.data.sha,
    
                    parents: [baseRef.data.object.sha]
    
                  });
     
                  // Create a new branch for the PR
    
                  const timestamp = Date.now();
    
                  const branchName = `deploy-${timestamp}`;
    
                  await github.rest.git.createRef({
    
                    owner: context.repo.owner,
    
                    repo: context.repo.repo,
    
                    ref: `refs/heads/${branchName}`,
    
                    sha: newCommit.data.sha
    
                  });
     
                  // Create the PR
    
                  const pr = await github.rest.pulls.create({
    
                    owner: context.repo.owner,
    
                    repo: context.repo.repo,
    
                    title: '${{ github.event.inputs.pr_title }}',
    
                    body: `Deploying changes from ${{ github.event.inputs.base_branch }} to ${{ needs.prepare-deployment.outputs.target_branch }}
     
                    ${{ github.event.inputs.pr_description }}
     
                    Note: The following paths have been excluded from this PR:
    
                    - .github/workflows/
    
                    - tests/`,
    
                    head: branchName,
    
                    base: '${{ needs.prepare-deployment.outputs.target_branch }}'
    
                  });
     
                  await github.rest.issues.addLabels({
    
                    owner: context.repo.owner,
    
                    repo: context.repo.repo,
    
                    issue_number: pr.data.number,
    
                    labels: ['deployment', '${{ needs.prepare-deployment.outputs.target_branch }}']
    
                  });
     
                  console.log('PR created successfully:', pr.data.html_url);
    
                  core.setOutput('pr_url', pr.data.html_url);
    
                  core.setOutput('pr_number', pr.data.number);
     
                  // Log the filtered paths for debugging
    
                  console.log('Filtered tree paths:');
    
                  filteredTree.forEach(item => console.log(item.path));
     
                } catch (error) {
    
                  console.error('Error creating PR:', error);
    
                  core.setFailed(error.message);
    
                }
     
          - name: PR Summary
    
            if: success()
    
            run: |
    
              echo "## Pull Request Created" >> $GITHUB_STEP_SUMMARY
    
              echo "- PR URL: ${{ steps.create-pr.outputs.pr_url }}" >> $GITHUB_STEP_SUMMARY
    
              echo "- PR Number: ${{ steps.create-pr.outputs.pr_number }}" >> $GITHUB_STEP_SUMMARY
    
              echo "- Source Branch: ${{ github.event.inputs.base_branch }}" >> $GITHUB_STEP_SUMMARY
    
              echo "- Target Branch: ${{ needs.prepare-deployment.outputs.target_branch }}" >> $GITHUB_STEP_SUMMARY
     
      deploy-after-merge:
    
        needs: [prepare-deployment, create-pr]
    
        runs-on: self-hosted
    
        if: github.event.pull_request.merged == true
    
        steps:
    
          - name: Deploy Merged Changes
    
            run: |
    
              echo "Deployment completed to ${{ needs.prepare-deployment.outputs.target_branch }}"

** Troubleshooting Steps Taken:

  1. Verified that the folders are properly removed from the target branch

  2. Confirmed that the filtered tree logs don't show the excluded paths

  3. Created a new branch from filtered content to avoid history issues

** Additional Context:

** Questions:

  1. How can I achieve my requirement? What am I missing?

  2. Are there alternative approaches to exclude specific folders when creating PRs through the API?

  3. Could this be related to how GitHub handles file history in PRs?

** Repository Information:

Please let me know if you need any additional information or clarification.

Upvotes: -3

Views: 50

Answers (0)

Related Questions