React 应用程序未获取 Jenkins Pipeline 的状态

问题描述 投票:0回答:1

我正在创建一个应用程序,其中有一个 Jenkins Pipeline 负责克隆存储库并在其上运行 megalinter,然后当该过程完成时,megalinter.log 文件将被清理,问题将显示在 Issues.jsx 页面中。直到管道构建过程正在进行时,才会有一个动画,其中显示管道状态,但会看到以下错误

- 即使管道成功触发,几秒钟后也会在控制台日志中看到这些错误。 -即使构建完成,也不会获取任何工件 - 动画的阶段在几秒钟内显示失败,但管道在杰宁斯中触发,所以我不知道是什么导致了这些错误。 Erros(All these errors are just after few seconds)

network tab

我不知道 147 从哪里来,我什至没有使用该网址

我在代码中尝试了这些东西 詹金斯管道

pipeline {
    agent any

    environment {
        NODEJS_HOME = tool name: 'NodeJS', type: 'jenkins.plugins.nodejs.tools.NodeJSInstallation'
        PATH = "${env.NODEJS_HOME}/bin:${env.PATH}"
    }

    parameters {
        string(name: 'REPO_URL', defaultValue: '', description: 'URL of the Git repository to analyze')
    }

    stages {
        stage('Clone Repository') {
            steps {
                script {
                    try {
                        git url: "${params.REPO_URL}", branch: 'main'
                    } catch (Exception e) {
                        echo "Main branch not found, trying master branch"
                        git url: "${params.REPO_URL}", branch: 'master'
                    }
                }
            }
        }
        stage('Run MegaLinter') {
            steps {
                script {
                    try {
                        bat "npx mega-linter-runner --flavor cupcake --release v6"
                    } catch (Exception e) {
                        echo "MegaLinter found issues, but continuing pipeline"
                    }
                }
            }
        }
    }

    post {
        always {
            archiveArtifacts artifacts: 'megalinter-reports/**', allowEmptyArchive: true
            cleanWs()
        }
    }
}

Issues.jsx页面代码

const Issues = () => {
  const { repoName } = useParams();
  const [buildStage, setBuildStage] = useState('Initializing');
  const [issues, setIssues] = useState([]);
  const [filteredIssues, setFilteredIssues] = useState([]);
  const [filters, setFilters] = useState({
    severity: "",
    language: "",
    linter: ""
  });

  useEffect(() => {
    let isMounted = true;
    let intervalId;
  
    const runPipeline = async () => {
      try {
        setBuildStage('Triggering Pipeline');
        await triggerPipeline({ name: repoName });
        
        if (!isMounted) return;
        setBuildStage('Waiting for Build');
        
        let lastBuildNumber = null;
  
        const pollBuildStatus = async () => {
          try {
            const { isBuilding, result, number } = await checkBuildStatus();
            
            if (number !== lastBuildNumber) {
              lastBuildNumber = number;
              console.log(`New build started: #${number}`);
            }
  
            if (!isBuilding && result) {
              clearInterval(intervalId);
              if (result === 'SUCCESS') {
                if (isMounted) {
                  setBuildStage('Fetching Results');
                  const results = await getBuildResults(number);
                  await processMegaLinterResults(results.megaLinterLog);
                  setBuildStage('Complete');
                }
              } else {
                if (isMounted) setBuildStage(`Failed: ${result}`);
              }
            }
          } catch (error) {
            console.error('Error in pollBuildStatus:', error);
            if (isMounted) setBuildStage('Failed: Error checking status');
          }
        };
  
        intervalId = setInterval(pollBuildStatus, 5000); // Check every 5 seconds
      } catch (error) {
        console.error('Error in pipeline process:', error);
        if (isMounted) setBuildStage('Failed: Error triggering pipeline');
      }
    };
  
    runPipeline();
  
    return () => {
      isMounted = false;
      if (intervalId) clearInterval(intervalId);
    };
  }, [repoName]);

  const processMegaLinterResults = (logContent) => {
    try {
      const processedIssues = [];
      const lines = logContent.split('\n');
      
      let currentLinter = '';
      let currentFile = '';
  
      for (const line of lines) {
        if (line.startsWith('Linter:')) {
          currentLinter = line.split(':')[1].trim();
        } else if (line.startsWith('File:')) {
          currentFile = line.split(':')[1].trim();
        } else if (line.includes('|')) {
          const [lineNumber, column, level, message] = line.split('|').map(item => item.trim());
          processedIssues.push({
            message,
            linter: currentLinter,
            file: currentFile,
            severity: level,
            line: lineNumber,
            column
          });
        }
      }
  
      setIssues(processedIssues);
      setFilteredIssues(processedIssues);
    } catch (error) {
      console.error('Error processing MegaLinter results:', error);
    }
  };


  useEffect(() => {
    const filtered = issues.filter(issue => 
      (!filters.severity || issue.severity === filters.severity) &&
      (!filters.language || issue.language === filters.language) &&
      (!filters.linter || issue.linter === filters.linter)
    );
    setFilteredIssues(filtered);
  }, [issues, filters]);

  const handleFilterChange = (filterType, value) => {
    setFilters(prev => ({ ...prev, [filterType]: value }));
  };

  return (
    <div className='flex'>
      <Sidebar>
        <SideBarItem link="/user/dashboard" icon={<Home size={20} />} text="Home" alert />
        <SideBarItem link={`/user/dashboard/repos/${repoName}`} icon={<BarChart4 size={20} />} text="Details" alert />
        <SideBarItem link={`/user/dashboard/repos/${repoName}/issues`} icon={<Bug size={20} />} text="Issues" />
        <SideBarItem link={`/user/dashboard/repos/${repoName}/commits`} icon={<GitCommitVertical size={20} />} text="Commits" />
        <SideBarItem link={`/user/dashboard/repos/${repoName}/pull-requests`} icon={<GitPullRequestIcon size={20} />} text="Pull Requests" />
        <SideBarItem link="/user/dashboard/help" icon={<HandHelping size={20} />} text="Help" />
      </Sidebar>
      <div className="p-4 flex-grow">
        <h1 className="text-2xl font-bold mb-4">Issues of {repoName}</h1>
        {buildStage !== 'Complete' ? (
          <div className="flex flex-col items-center justify-center h-64">
            <div className="loader"></div>
            <p className="mt-4">Status: {buildStage}</p>
          </div>
        ) : (
          <div className="flex flex-col md:flex-row gap-4">
            <div className="flex-grow bg-black shadow-md rounded-lg p-6">
              <h2 className="text-xl font-semibold mb-4">Mega Linter Results</h2>
              <div className="overflow-x-auto">
                <table className="min-w-full bg-black">
                  <thead className="bg-gray-100">
                    <tr>
                      <th className="py-2 px-4 border-b text-left">S.No</th>
                      <th className="py-2 px-4 border-b text-left">Issues</th>
                      <th className="py-2 px-4 border-b text-left">Linter</th>
                      <th className="py-2 px-4 border-b text-left">File</th>
                      <th className="py-2 px-4 border-b text-left">Severity</th>
                    </tr>
                  </thead>
                  <tbody>
                    {filteredIssues.map((issue, index) => (
                      <tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-black'}>
                        <td className="py-2 px-4 border-b">{index + 1}</td>
                        <td className="py-2 px-4 border-b">{issue.message}</td>
                        <td className="py-2 px-4 border-b">{issue.linter}</td>
                        <td className="py-2 px-4 border-b">{issue.file}</td>
                        <td className="py-2 px-4 border-b">{issue.severity}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </div>
            
            <div className="w-full md:w-64 bg-black shadow-md rounded-lg p-6">
              <h2 className="text-xl font-semibold mb-4">Filters</h2>
              <div className="space-y-4">
                <div>
                  <label htmlFor="severity" className="block text-sm font-medium text-gray-700">Severity</label>
                  <select
                    id="severity"
                    className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
                    onChange={(e) => handleFilterChange('severity', e.target.value)}
                  >
                    <option value="">Select severity</option>
                    {['Low', 'Medium', 'High'].map((option) => (
                      <option key={option} value={option}>{option}</option>
                    ))}
                  </select>
                </div>
                
                <div>
                  <label htmlFor="language" className="block text-sm font-medium text-gray-700">Language</label>
                  <select
                    id="language"
                    className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
                    onChange={(e) => handleFilterChange('language', e.target.value)}
                  >
                    <option value="">Select language</option>
                    {[...new Set(issues.map(issue => issue.language))].map((option) => (
                      <option key={option} value={option}>{option}</option>
                    ))}
                  </select>
                </div>
                
                <div>
                  <label htmlFor="linter" className="block text-sm font-medium text-gray-700">Linter</label>
                  <select
                    id="linter"
                    className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
                    onChange={(e) => handleFilterChange('linter', e.target.value)}
                  >
                    <option value="">Select linter</option>
                    {[...new Set(issues.map(issue => issue.linter))].map((option) => (
                      <option key={option} value={option}>{option}</option>
                    ))}
                  </select>
                </div>
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

export default Issues;

控制器功能

export const triggerPipeline = async (repo) => {
  try {
    if (!repo || !repo.name) {
      throw new Error('Invalid repository information');
    }

    const { data: { user }, error } = await supabase.auth.getUser();
    if (error) {
      throw new Error('Failed to fetch user data');
    }

    const githubUsername = user.user_metadata.user_name;
    if (!githubUsername) {
      throw new Error('GitHub username not found in user metadata');
    }

    const response = await fetch('http://localhost:8080/job/generate-issues/buildWithParameters', {
      method: 'POST',
      headers: {
        'Authorization': 'Basic ' + btoa('username:password'),
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      body: `REPO_URL=https://github.com/${githubUsername}/${repo.name}.git`,
    });

    console.log('Response status:', response.status);
    console.log('Response headers:', JSON.stringify(Object.fromEntries(response.headers)));

    if (response.status === 201 || response.status === 303) {
      console.log('Jenkins pipeline triggered successfully');
      return { message: 'Pipeline triggered successfully' };
    } else {
      throw new Error(`Failed to trigger Jenkins pipeline: ${response.status}`);
    }
  } catch (error) {
    console.error('Error triggering Jenkins pipeline:', error);
    throw error;
  }
};

export const checkBuildStatus = async () => {
  const buildUrl = 'http://localhost:8080/job/generate-issues/lastBuild/api/json';
  const authHeader = 'Basic ' + btoa('username:password');

  try {
    const response = await fetch(buildUrl, {
      headers: {
        'Authorization': authHeader
      }
    });

    if (!response.ok) {
      throw new Error(`Failed to fetch build status: ${response.status}`);
    }

    const buildData = await response.json();
    console.log('Build data:', buildData);

    return { 
      isBuilding: buildData.building,
      result: buildData.result,
      number: buildData.number
    };
  } catch (error) {
    console.error('Error checking build status:', error);
    return { isBuilding: false, result: 'ERROR', number: null };
  }
};

export const getBuildResults = async (buildNumber) => {
  const logUrl = `http://localhost:8080/job/generate-issues/${buildNumber}/artifact/megalinter-reports/megalinter.log`;
  const authHeader = 'Basic ' + btoa('username:password');

  try {
    const response = await fetch(logUrl, {
      headers: {
        'Authorization': authHeader
      }
    });

    if (!response.ok) {
      throw new Error(`Failed to fetch MegaLinter log: ${response.status}`);
    }

    const megaLinterLog = await response.text();
    return { megaLinterLog };
  } catch (error) {
    console.error('Error fetching MegaLinter log:', error);
    throw error;
  }
};
javascript reactjs jenkins automation
1个回答
0
投票

当您使用此 API 触发构建时,Jenkins 不会立即启动构建 - 而是将请求排队并告知队列项 URL。 这篇文章可能会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.