code_ownership 1.34.2 → 1.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: e34134e28ee70e58344ea6d3f90be157bbdd6945888eee07d73abf3db3ed873b
         | 
| 4 | 
            +
              data.tar.gz: 1875f6d3131505551c163aa03413edefa86c6f279d2c3189d9663a74a9603758
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: de217fe525521395f2b6ad647257aecd69c9e8f8895fa0d466051cf4d365c3fce2dcf08ea9c9bfbeeef0c75116f3188d6f350c72becb965f7f3d49a992a0b6fa
         | 
| 7 | 
            +
              data.tar.gz: abf92fcca79c8311cfa9d82fabcb0b129fdd076c9cb7a3db31c0db983dabf1e6cb5810b501e38cdab9fbf028dc3a43ed6105928469015b6bf30a33e774b5a6b6
         | 
    
        data/README.md
    CHANGED
    
    | @@ -73,6 +73,12 @@ js_package_paths: | |
| 73 73 |  | 
| 74 74 | 
             
            This defaults `**/`, which makes it look for `package.json` files across your application.
         | 
| 75 75 |  | 
| 76 | 
            +
            > [!NOTE]
         | 
| 77 | 
            +
            > Javscript package ownership does not respect `unowned_globs`. If you wish to disable usage of this feature you can set `js_package_paths` to an empty list.
         | 
| 78 | 
            +
            ```yml
         | 
| 79 | 
            +
            js_package_paths: []
         | 
| 80 | 
            +
            ```
         | 
| 81 | 
            +
             | 
| 76 82 | 
             
            ### Custom Ownership
         | 
| 77 83 | 
             
            To enable custom ownership, you can inject your own custom classes into `code_ownership`.
         | 
| 78 84 | 
             
            To do this, first create a class that adheres to the `CodeOwnership::Mapper` and/or `CodeOwnership::Validator` interface.
         | 
| @@ -155,7 +161,7 @@ unowned_globs: | |
| 155 161 | 
             
              - app/services/some_file2.rb
         | 
| 156 162 | 
             
              - frontend/javascripts/**/__generated__/**/*
         | 
| 157 163 | 
             
            ```
         | 
| 158 | 
            -
            You can call the validation function with the Ruby API | 
| 164 | 
            +
            You can call the validation function with the Ruby API
         | 
| 159 165 | 
             
            ```ruby
         | 
| 160 166 | 
             
            CodeOwnership.validate!
         | 
| 161 167 | 
             
            ```
         | 
| @@ -11,6 +11,7 @@ module CodeOwnership | |
| 11 11 | 
             
                const :unbuilt_gems_path, T.nilable(String)
         | 
| 12 12 | 
             
                const :skip_codeowners_validation, T::Boolean
         | 
| 13 13 | 
             
                const :raw_hash, T::Hash[T.untyped, T.untyped]
         | 
| 14 | 
            +
                const :require_github_teams, T::Boolean
         | 
| 14 15 |  | 
| 15 16 | 
             
                sig { returns(Configuration) }
         | 
| 16 17 | 
             
                def self.fetch
         | 
| @@ -27,7 +28,8 @@ module CodeOwnership | |
| 27 28 | 
             
                    unowned_globs: config_hash.fetch('unowned_globs', []),
         | 
| 28 29 | 
             
                    js_package_paths: js_package_paths(config_hash),
         | 
| 29 30 | 
             
                    skip_codeowners_validation: config_hash.fetch('skip_codeowners_validation', false),
         | 
| 30 | 
            -
                    raw_hash: config_hash
         | 
| 31 | 
            +
                    raw_hash: config_hash,
         | 
| 32 | 
            +
                    require_github_teams: config_hash.fetch('require_github_teams', false)
         | 
| 31 33 | 
             
                  )
         | 
| 32 34 | 
             
                end
         | 
| 33 35 |  | 
| @@ -10,6 +10,8 @@ module CodeOwnership | |
| 10 10 | 
             
                    include Mapper
         | 
| 11 11 |  | 
| 12 12 | 
             
                    CODEOWNERS_DIRECTORY_FILE_NAME = '.codeowner'
         | 
| 13 | 
            +
                    RELATIVE_ROOT = Pathname('.').freeze
         | 
| 14 | 
            +
                    ABSOLUTE_ROOT = Pathname('/').freeze
         | 
| 13 15 |  | 
| 14 16 | 
             
                    @@directory_cache = T.let({}, T::Hash[String, T.nilable(CodeTeams::Team)]) # rubocop:disable Style/ClassVars
         | 
| 15 17 |  | 
| @@ -74,36 +76,46 @@ module CodeOwnership | |
| 74 76 | 
             
                      )
         | 
| 75 77 | 
             
                    end
         | 
| 76 78 |  | 
| 77 | 
            -
                    #  | 
| 79 | 
            +
                    # Takes a file and finds the relevant `.codeowner` file by walking up the directory
         | 
| 78 80 | 
             
                    # structure. Example, given `a/b/c.rb`, this looks for `a/b/.codeowner`, `a/.codeowner`,
         | 
| 79 81 | 
             
                    # and `.codeowner` in that order, stopping at the first file to actually exist.
         | 
| 80 | 
            -
                    #  | 
| 82 | 
            +
                    # If the parovided file is a directory, it will look for `.codeowner` in that directory and then upwards.
         | 
| 83 | 
            +
                    # We do additional caching so that we don't have to check for file existence every time.
         | 
| 81 84 | 
             
                    sig { params(file: String).returns(T.nilable(CodeTeams::Team)) }
         | 
| 82 85 | 
             
                    def map_file_to_relevant_owner(file)
         | 
| 83 86 | 
             
                      file_path = Pathname.new(file)
         | 
| 84 | 
            -
                       | 
| 87 | 
            +
                      team = T.let(nil, T.nilable(CodeTeams::Team))
         | 
| 85 88 |  | 
| 86 | 
            -
                       | 
| 87 | 
            -
                         | 
| 88 | 
            -
             | 
| 89 | 
            +
                      if File.directory?(file)
         | 
| 90 | 
            +
                        team = get_team_from_codeowners_file_within_directory(file_path)
         | 
| 91 | 
            +
                      end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                      while team.nil? && file_path != RELATIVE_ROOT && file_path != ABSOLUTE_ROOT
         | 
| 94 | 
            +
                        file_path = file_path.parent
         | 
| 95 | 
            +
                        team = get_team_from_codeowners_file_within_directory(file_path)
         | 
| 96 | 
            +
                      end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                      team
         | 
| 99 | 
            +
                    end
         | 
| 89 100 |  | 
| 90 | 
            -
             | 
| 101 | 
            +
                    sig { params(directory: Pathname).returns(T.nilable(CodeTeams::Team)) }
         | 
| 102 | 
            +
                    def get_team_from_codeowners_file_within_directory(directory)
         | 
| 103 | 
            +
                      potential_codeowners_file = directory.join(CODEOWNERS_DIRECTORY_FILE_NAME)
         | 
| 91 104 |  | 
| 92 | 
            -
             | 
| 93 | 
            -
                        if @@directory_cache.key?(potential_codeowners_file_name)
         | 
| 94 | 
            -
                          team = @@directory_cache[potential_codeowners_file_name]
         | 
| 95 | 
            -
                        elsif potential_codeowners_file.exist?
         | 
| 96 | 
            -
                          team = owner_for_codeowners_file(potential_codeowners_file)
         | 
| 105 | 
            +
                      potential_codeowners_file_name = potential_codeowners_file.to_s
         | 
| 97 106 |  | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 107 | 
            +
                      team = nil
         | 
| 108 | 
            +
                      if @@directory_cache.key?(potential_codeowners_file_name)
         | 
| 109 | 
            +
                        team = @@directory_cache[potential_codeowners_file_name]
         | 
| 110 | 
            +
                      elsif potential_codeowners_file.exist?
         | 
| 111 | 
            +
                        team = owner_for_codeowners_file(potential_codeowners_file)
         | 
| 102 112 |  | 
| 103 | 
            -
                         | 
| 113 | 
            +
                        @@directory_cache[potential_codeowners_file_name] = team
         | 
| 114 | 
            +
                      else
         | 
| 115 | 
            +
                        @@directory_cache[potential_codeowners_file_name] = nil
         | 
| 104 116 | 
             
                      end
         | 
| 105 117 |  | 
| 106 | 
            -
                       | 
| 118 | 
            +
                      return team
         | 
| 107 119 | 
             
                    end
         | 
| 108 120 | 
             
                  end
         | 
| 109 121 | 
             
                end
         | 
| @@ -21,7 +21,7 @@ module CodeOwnership | |
| 21 21 |  | 
| 22 22 | 
             
                    sig { override.params(teams: T::Array[CodeTeams::Team]).returns(T::Array[String]) }
         | 
| 23 23 | 
             
                    def self.validation_errors(teams)
         | 
| 24 | 
            -
                      all_github_teams = teams.flat_map { |team| self.for(team).github.team }
         | 
| 24 | 
            +
                      all_github_teams = teams.flat_map { |team| self.for(team).github.team }.compact
         | 
| 25 25 |  | 
| 26 26 | 
             
                      teams_used_more_than_once = all_github_teams.tally.select do |_team, count|
         | 
| 27 27 | 
             
                        count > 1
         | 
| @@ -29,6 +29,18 @@ module CodeOwnership | |
| 29 29 |  | 
| 30 30 | 
             
                      errors = T.let([], T::Array[String])
         | 
| 31 31 |  | 
| 32 | 
            +
                      if require_github_teams?
         | 
| 33 | 
            +
                        missing_github_teams = teams.select { |team| self.for(team).github.team.nil? }
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                        if missing_github_teams.any?
         | 
| 36 | 
            +
                          errors << <<~ERROR
         | 
| 37 | 
            +
                            The following teams are missing `github.team` entries:
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                            #{missing_github_teams.map(&:config_yml).join("\n")}
         | 
| 40 | 
            +
                          ERROR
         | 
| 41 | 
            +
                        end
         | 
| 42 | 
            +
                      end
         | 
| 43 | 
            +
             | 
| 32 44 | 
             
                      if teams_used_more_than_once.any?
         | 
| 33 45 | 
             
                        errors << <<~ERROR
         | 
| 34 46 | 
             
                          The following teams are specified multiple times:
         | 
| @@ -40,6 +52,11 @@ module CodeOwnership | |
| 40 52 |  | 
| 41 53 | 
             
                      errors
         | 
| 42 54 | 
             
                    end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    sig { returns(T::Boolean) }
         | 
| 57 | 
            +
                    def self.require_github_teams?
         | 
| 58 | 
            +
                      CodeOwnership.configuration.require_github_teams
         | 
| 59 | 
            +
                    end
         | 
| 43 60 | 
             
                  end
         | 
| 44 61 | 
             
                end
         | 
| 45 62 | 
             
              end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: code_ownership
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.36.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Gusto Engineers
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023- | 
| 11 | 
            +
            date: 2023-12-01 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: code_teams
         |