Guidelines for participating in open source projects (towards the front)

Posted by Rulkster on Mon, 24 Jan 2022 22:17:19 +0100

background

I believe many front-end partners have thought about participating in the development of some open source projects, but sometimes they don't know how to start because of some objective reasons, such as no guidance and no perfect process and steps to participate in open source projects. As it happens, the open source framework of antd design / Pro components has been widely used in business recently, and some bug s of the framework itself or inconvenient to use have been encountered during development. Therefore, PR has been proposed to antd design / Pro components for many times, and all of them have been approved. Take this opportunity to sort out some processes and precautions of participating in open source projects, and provide reference for some small partners who have not participated in the development of open source projects, so as not to be like headless flies.

Basic concepts

Contributor

Contributors, that is, the source code contributors of open source projects. Generally speaking, as long as you have submitted PR to an open source project more than once, approved and merged into the main branch of the open source project, you will become the Contributor of the open source project. So, what are the rights and obligations of the Contributor of open source projects? Borrow the contribution of Nacos project team:

Issues

Topic. Here, you can express some opinions, suggestions, raise bugs, ask some detailed questions about the use of the project, etc. the Contributor of the project will check some project bugs or reasonable and feasible functional requirements for repair or demand development.

Fork

That is, branch, that is, copy a copy of the original git project as your own personal project branch (note that this is different from the branch branch. Fork is equivalent to the branch growing from the trunk of a tree, while branch is the branch growing from the branch). After forking a project, you can develop it according to your own needs. If you want to merge it into the trunk branch after development, you need to put forward a Pull request(PR) request in the project forked.

Pull request(PR)

Pull request is to request the trunk branch to pull the code of a branch of the project from the fork and merge it into the trunk branch. The Contributor can only merge the code of its fork project into the trunk branch of the open source project by raising PR. otherwise, no matter how you modify it, it will only modify the copy of your own project and will not affect the trunk. This will eliminate the direct collapse of the project.

Main process

  1. Identify the open source projects you want to participate in

  2. fork a local copy of the project, which can usually be operated in the upper right corner of the GitHub project home page

  3. After fork, you will generate such a copy project on your own project, and then all your development will be submitted to the project

    If it is not the first fork project, synchronize your warehouse with the trunk warehouse before each new function or bug repair development to ensure that the warehouse you fork down is synchronized with the trunk warehouse.

  4. Next, we clone the project locally

  5. Find the bugs or new features you want to fix from Issues, or the bugs you found or the new features you want to do

  6. A new branch is generated based on the checkout of the master branch under the local clone. The branch name is recommended as follows:

    • Fix bug: hotfix/1234, where 1234 represents the ID of the Issues you fixed. If there are no Issues, the following ID can replace the simple English description of the modified content

    • New function: feat/1234. If there are no Issues, the following id can replace the simple English description of the modified content

    • Miscellaneous: chore/xxx, such as modifying some packaged configuration items and ci/cd scripts, which have nothing to do with the actual function code.

  7. Carry out function development, bug repair, etc.

  8. Don't rush to submit after development. General open source projects need to carry out unit test and coverage test on the functions we develop. For example, after the development of antd design / Pro component, we also need to carry out the following steps (each open source project needs different requirements, which is only for reference):

    1. If a new function is developed or the modified module is the core function, it is basically necessary to write unit test cases to ensure that the unit test covers all possible situations of the developed function as much as possible

      The following figure shows the unit test cases added after developing an amount component ProFormMoney

    2. To update the snapshot, the general web component library will compare the snapshot of some test cases in the project (in fact, compile the code in the test case into html and save it, and compare it with the later changed html). In antd design / Pro component, run the following command to update the snapshot:

      yarn test:update
      
    3. Run coverage test to check the coverage of our code. Usually, an open source project has its own coverage indicators, such as branch coverage of unit test reaching more than 95%, method coverage reaching more than 80%, etc.

    4. Detect subcontracting dependencies. If there are multiple subcontracts in a NodeJs project, such as the following subcontracts in antd design / Pro component:

      • card
      • descriptions
      • field
      • form
      • layout
      • list
      • provider
      • skeleton
      • table
      • utils

      The dependencies of each subcontract may be different. Sometimes when developing, you may not pay attention to installing the dependencies, and install the dependencies of the subcontract into the complete project dependencies at the outermost layer. This may cause others to report an error if they can't find the dependencies when using only one subcontract. Generally, NodeJs project will have a script to detect subcontracting dependencies, which is used to detect whether the dependencies introduced by each subcontracting are in the subcontracting package JSON.

      # Sample script for detecting subcontracting dependencies
      /* eslint-disable no-param-reassign */
      const parser = require('@babel/parser');
      const traverse = require('@babel/traverse');
      const t = require('babel-types');
      const { winPath } = require('umi-utils');
      const glob = require('glob');
      const fs = require('fs');
      const ora = require('ora');
      const { join, posix } = require('path');
      
      const spinner = ora();
      
      const peerDependencies = ['antd', 'react'];
      
      /**
       * Replace formatMessage in file
       *
       * @param {any} ast
       */
      const checkDepsByAst = (ast, filePath) => {
        return new Promise((resolve) => {
          traverse.default(ast, {
            enter(path) {
              if (path.isImportDeclaration()) {
                const importPath = path.node.source.value;
      
                if (!importPath) return;
      
                if (importPath.includes('/src')) {
                  resolve({
                    success: false,
                    message: 'import Cannot contain **/src/**',
                  });
                  return;
                }
      
                if (importPath.startsWith('.')) {
                  const importFile = join(__dirname, '..', filePath, '..', importPath);
                  if (importFile.split('.').length > 1) {
                    if (fs.existsSync(`${importFile}`)) return;
                    resolve({
                      success: false,
                      message: `${importFile} Path error, please check case or path error,
                    });
                    return;
                  }
                  if (
                    !fs.existsSync(`${importFile}.ts`) &&
                    !fs.existsSync(`${importFile}.tsx`) &&
                    !fs.existsSync(`${importFile}/index.tsx`) &&
                    !fs.existsSync(`${importFile}/index.ts`) &&
                    !fs.existsSync(`${importFile}.d.ts`)
                  ) {
                    resolve({
                      success: false,
                      message: `${importFile} Path error, please check case or path error,
                    });
                    return;
                  }
                }
                if (!importPath.startsWith('.') && path.node.importKind !== 'type') {
                  const packagePath = winPath(filePath.split(posix.sep).splice(0, 2).join(posix.sep));
                  try {
                    // Check whether the package is in
                    require.resolve(importPath, {
                      paths: [join(__dirname, '..', packagePath)],
                    });
                    if (!importPath.startsWith('antd') && !importPath.startsWith('react')) {
                      const packageName = importPath.split(posix.sep)[0];
                      const packageJson = require(join(__dirname, '..', packagePath, 'package.json'));
                      if (!JSON.stringify(packageJson.dependencies).includes(packageName)) {
                        resolve({
                          success: false,
                          message: `${packagePath} The ${packageName} dependency of is not in ${join(
                            __dirname,
                            '..',
                            packagePath,
                            'package.json',
                          )} In the statement,
                        });
                        return;
                      }
                    }
                  } catch (error) {
                    resolve({
                      success: false,
                      message: `${importPath} Dependency is not installed, please check the case or path error,
                    });
                  }
                }
              }
            },
          });
          resolve({
            success: true,
          });
          return;
        });
      };
      
      const forEachFile = (code, filePath) => {
        const ast = parser.parse(code, {
          sourceType: 'module',
          plugins: ['jsx', 'typescript', 'dynamicImport', 'classProperties', 'decorators-legacy'],
        });
        return checkDepsByAst(ast, filePath);
      };
      
      const globList = (patternList, options) => {
        let fileList = [];
        patternList.forEach((pattern) => {
          fileList = [...fileList, ...glob.sync(pattern, options)];
        });
      
        return fileList;
      };
      const checkDeps = ({ cwd }) => {
        console.log(cwd);
        // Find all ts under the project
        spinner.start('🕵️‍  find all code files');
        const tsFiles = globList(['packages/**/src/**/*.tsx', 'packages/**/src/**/*.tsx'], {
          cwd,
          ignore: [
            '**/*.d.ts',
            '**/demos/**',
            '**/dist/**',
            '**/public/**',
            '**/locales/**',
            '**/node_modules/**',
          ],
        });
        spinner.succeed();
      
        const getFileContent = (path) => fs.readFileSync(winPath(path), 'utf-8');
      
        spinner.start('🕵️  check deps');
      
        tsFiles.forEach(async (path) => {
          const source = getFileContent(join(cwd, path));
          if (source.includes('import')) {
            const result = await forEachFile(source, path);
            if (result.success === false) {
              console.log(`😂 ${path} Errors found: \ n ${result.message} `);
              process.exitCode(1);
            }
          }
        });
        spinner.succeed();
      };
      
      /** Check all root files */
      checkDeps({
        cwd: join(__dirname, '..'),
      });
      
      
    5. Format code. Some projects do not automatically complete the formatting code when they are submitted, which leads to the inconsistency between the submitted code style and the main style. Therefore, let's finally manually run the code format command to format according to the project format specification.

      yarn prettier
      
  9. Code submission. After code development and the above inspection, even if our development work is over, the next step is to submit the code, which should also follow certain specifications:

    • Fix bug:

      • First submission: if it is the first submission to fix the current bug and the bug is recorded on Issues, the following format should be used:

        # among#1234 represents the issues with id 1234. After submitting, you can associate your issues and display your repair records in the bug 'issues' raised by the user
        git commit -am "fix: #1234 fixed xxx problem“
        # Fix and close issues
        git commit -am "fix: close #1234 fixed xxx problem“
        
      • bug not submitted for the first time or without issues: if not submitted for the first time, follow the following format:

        git commit -am "fix: Fixed xxx problem"
        
    • New features

      • First submission

        # Among them#1234 represents issues with id 1234
        git commit -am "feat: #1234 added xxx function“
        # Add new features and turn off issues
        git commit -am "feat: close #1234 added xxx function“
        
      • Requirements not submitted for the first time or without issues

        git commit -am "feat: Added xxx function"
        
    • Modify miscellaneous

      • First submission

        git commit -am "chore: #1234 modified xxx configuration“
        
      • Problems or requirements not submitted for the first time or without issues

        git commit -am "chore: Modified xxx to configure"
        
  10. After the code is submitted, we directly push it to the warehouse we fork ed down

  11. Select the branch of development to mention the Pull Request. The specifications are as follows:

    • title:
      • Modify bug: fix (module name): description, such as fix(field,form): fix the bug in the query form
      • New feature: feat (module name): description, for example: feat(table): add a draggable sorting table
    • Content: list the key points of the detailed rules for modification
  12. After initiating the application, github ci will automatically perform basic checks on the branch code submitted to PR, such as unit test and coverage test. Only after passing the check will it go to the manual review stage. If any one of the processes is wrong, it needs to be modified as required and resubmitted before continuing.

  13. Manual review phase. At this node, a Maintainer will review whether the modified content is risky and needs to be merged into the trunk. During this period, details may be communicated many times through comments or emails.

  14. After the manual review is passed, there will be a Maintainer operation to merge your PR requests into the trunk. So far, the complete PR process has been completed

epilogue

Here, we have completed a complete open source project development process. Is it much clearer than before and know how to start? Find an open source project you like and contribute to the open source community together.

Topics: Front-end data structure