InfoGrab DocsInfoGrab Docs

Import/Export 개발 문서

요약

새로 추가되는 관계(relation)는 버그 및 성능 이슈 도입 위험을 줄이기 위해 기능 플래그 뒤에 배치해야 합니다. Import/Export 기능에 대한 일반 개발 가이드라인과 팁입니다. 이 문서는 원래 YouTube에서 제공되는 Import/Export 201 프레젠테이션을 기반으로 작성되었습니다.

새로 추가되는 관계(relation)는 버그 및 성능 이슈 도입 위험을 줄이기 위해 기능 플래그 뒤에 배치해야 합니다.

Import/Export 기능에 대한 일반 개발 가이드라인과 팁입니다.

이 문서는 원래 YouTube에서 제공되는 Import/Export 201 프레젠테이션을 기반으로 작성되었습니다.

더 많은 맥락을 위해 YouTube의 Import/Export 개발 심층 분석을 시청할 수 있습니다.

Import/Export 개발 문서#

보안#

Import/Export 기능은 지속적으로 업데이트(새로운 내보내기 항목 추가)되고 있습니다. 그러나 코드는 오랫동안 리팩토링되지 않았습니다. 동적인 특성으로 인해 보안 우려 사항의 수가 증가하지 않도록 코드 감사를 수행해야 합니다. GitLab 팀원은 이 비공개 이슈에서 자세한 정보를 확인할 수 있습니다: https://gitlab.com/gitlab-org/gitlab/-/issues/20720.

코드 내 보안#

다음 클래스들 중 일부는 Import/Export에 보안 레이어를 제공합니다.

AttributeCleaner는 금지된 키를 제거합니다:

# AttributeCleaner
# Removes all `_ids` and other prohibited keys
    class AttributeCleaner
      ALLOWED_REFERENCES = RelationFactory::PROJECT_REFERENCES + RelationFactory::USER_REFERENCES + ['group_id']

      def clean
        @relation_hash.reject do |key, _value|
          prohibited_key?(key) || !@relation_class.attribute_method?(key) || excluded_key?(key)
        end.except('id')
      end

      ...

AttributeConfigurationSpec은 새 칼럼 추가를 확인하고 검증합니다:

# AttributeConfigurationSpec
<<-MSG
  It looks like #{relation_class}, which is exported using the project Import/Export, has new attributes:

  Please add the attribute(s) to SAFE_MODEL_ATTRIBUTES if they can be exported.

  Please denylist the attribute(s) in IMPORT_EXPORT_CONFIG by adding it to its corresponding
  model in the +excluded_attributes+ section.

  SAFE_MODEL_ATTRIBUTES: #{File.expand_path(safe_attributes_file)}
  IMPORT_EXPORT_CONFIG: #{Gitlab::ImportExport.config_file}
MSG

ModelConfigurationSpec은 새 모델 추가를 확인하고 검증합니다:

# ModelConfigurationSpec
<<-MSG
  New model(s) <#{new_models.join(',')}> have been added, related to #{parent_model_name}, which is exported by
  the Import/Export feature.

  If you think this model should be included in the export, please add it to `#{Gitlab::ImportExport.config_file}`.

  Definitely add it to `#{File.expand_path(ce_models_yml)}`
  to signal that you've handled this error and to prevent it from showing up in the future.
MSG

ExportFileSpec은 암호화되거나 민감한 칼럼을 탐지합니다:

# ExportFileSpec
<<-MSG
  Found a new sensitive word <#{key_found}>, which is part of the hash #{parent.inspect}
  If you think this information shouldn't get exported, please exclude the model or attribute in
  IMPORT_EXPORT_CONFIG.

  Otherwise, please add the exception to +safe_list+ in CURRENT_SPEC using #{sensitive_word} as the
  key and the correspondent hash or model as the value.

  Also, if the attribute is a generated unique token, please add it to RelationFactory::TOKEN_RESET_MODELS
  if it needs to be reset (to prevent duplicate column problems while importing to the same instance).

  IMPORT_EXPORT_CONFIG: #{Gitlab::ImportExport.config_file}
  CURRENT_SPEC: #{__FILE__}
MSG

버전 관리#

Import/Export는 단일 GitLab 릴리스 중에도 상수 변경이 잦기 때문에 엄격한 SemVer를 사용하지 않습니다. 하지만 호환성을 깨는 변경이 있을 때는 버전 업데이트가 필요합니다.

# ImportExport
module Gitlab
  module ImportExport
    extend self

    # For every version update, the history in import_export.md has to be kept up to date.
    VERSION = '0.2.4'

호환성#

프로젝트를 가져오거나 내보낼 때 호환성을 확인하세요.

버전을 올려야 하는 경우#

모델/칼럼 이름을 변경하거나 JSON 구조 또는 아카이브 파일의 파일 구조에 대한 형식 수정을 수행하는 경우 버전을 올려야 합니다.

다음의 경우에는 버전을 올릴 필요가 없습니다:

  • 새 칼럼 또는 모델 추가

  • 칼럼 또는 모델 제거(DB 제약 조건이 없는 경우)

  • 새로운 항목 내보내기(예: 새로운 유형의 업로드)

버전을 올릴 때마다 통합 스펙이 실패하며, 다음 명령으로 수정할 수 있습니다:

bundle exec rake gitlab:import_export:bump_version

코드 빠른 살펴보기#

Import/Export 설정 (import_export.yml)#

주요 설정 파일 import_export.yml은 내보내거나 가져올 수 있는 모델을 정의합니다.

프로젝트 import/export에 포함할 모델 관계:

project_tree:
  - labels:
    - :priorities
  - milestones:
    - events:
      - :push_event_payload
  - issues:
    - events:
    # ...

지정된 모델에 대해 다음 속성만 포함:

included_attributes:
  user:
    - :id
    - :public_email
  # ...

지정된 모델에 대해 다음 속성은 포함하지 않음:

excluded_attributes:
  project:
    - :name
    - :path
    - ...

내보내기 시 호출할 추가 메서드:

# Methods
methods:
  labels:
    - :type
  label:
    - :type

모델 관계의 내보내기 순서 커스터마이즈:

# Specify a custom export reordering for a given relationship
# For example for issues we use a custom export reordering by relative_position, so that on import, we can reset the
# relative position value, but still keep the issues order to the order in which issues were in the exported project.
# By default the ordering of relations is done by PK.
# column - specify the column by which to reorder, by default it is relation's PK
# direction - specify the ordering direction :asc or :desc, default :asc
# nulls_position - specify where would null values be positioned. Because custom ordering column can contain nulls we
#                  need to also specify where would the nulls be placed. It can be :nulls_last or :nulls_first, defaults
#                  to :nulls_last

export_reorders:
  project:
    issues:
      column: :relative_position
      direction: :asc
      nulls_position: :nulls_last

조건부 내보내기#

연관된 리소스가 프로젝트 외부에서 온 경우, 프로젝트 또는 그룹을 내보내는 사용자가 이러한 연관에 접근할 수 있는지 검증해야 할 수 있습니다. include_if_exportable은 리소스에 대한 연관의 배열을 받습니다. 내보내기 시, 연관된 리소스를 내보내기에 포함할 수 있는지 검증하기 위해 리소스의 exportable_association? 메서드가 연관 이름과 사용자를 인수로 호출됩니다.

예시:

include_if_exportable:
  project:
    issues:
      - epic_issue

이 정의는:

  • 이슈의 exportable_association?(:epic_issue, current_user: current_user) 메서드를 호출합니다.

  • 메서드가 true를 반환하면, 해당 이슈의 epic_issue 연관을 이슈에 포함합니다.

Import#

import job 상태는 none에서 여러 상태를 거쳐 finished 또는 failed로 이동합니다:

import_status: none -> scheduled -> started -> finished/failed

상태가 started인 동안 Importer 코드는 import에 필요한 각 단계를 처리합니다.

# ImportExport::Importer
module Gitlab
  module ImportExport
    class Importer
      def execute
        if import_file && check_version! && restorers.all?(&:restore) && overwrite_project
          project
        else
          raise Projects::ImportService::Error.new(@shared.errors.join(', '))
        end
      rescue => e
        raise Projects::ImportService::Error.new(e.message)
      ensure
        remove_import_file
      end

      def restorers
        [repo_restorer, wiki_restorer, project_tree, avatar_restorer,
         uploads_restorer, lfs_restorer, statistics_restorer]
      end

내보내기 서비스는 Importer와 유사하지만, 데이터를 저장하는 대신 복원합니다.

Export#

# ImportExport::ExportService
module Projects
  module ImportExport
    class ExportService < BaseService

      def save_all!
        if save_services
          Gitlab::ImportExport::Saver.save(project: project, shared: @shared, user: user)
          notify_success
        else
          cleanup_and_notify_error!
        end
      end

      def save_services
        [version_saver, avatar_saver, project_tree_saver, uploads_saver, repo_saver,
           wiki_repo_saver, lfs_saver].all?(&:save)
      end

테스트 픽스처#

Import/Export 스펙에서 사용되는 픽스처는 spec/fixtures/lib/gitlab/import_export에 있습니다. 프로젝트와 그룹 픽스처가 모두 있습니다.

각 픽스처에는 두 가지 버전이 있습니다:

  • 모든 객체가 포함된 사람이 읽을 수 있는 단일 JSON 파일로, project.json 또는 group.json이라고 합니다.

  • ndjson 형식의 파일 트리를 포함하는 tree라는 폴더. 반드시 필요하지 않은 한 이 폴더 아래의 파일을 수동으로 편집하지 마세요.

사람이 읽을 수 있는 JSON 파일에서 NDJSON 트리를 생성하는 도구는 gitlab-org/cloud-connector-team/team-tools 프로젝트에 있습니다.

프로젝트#

NDJSON 트리를 생성하려면 legacy-project-json-to-ndjson.sh를 사용하세요.

NDJSON 트리의 구조는 다음과 같습니다:

tree
├── project
│   ├── auto_devops.ndjson
│   ├── boards.ndjson
│   ├── ci_cd_settings.ndjson
│   ├── ci_pipelines.ndjson
│   ├── container_expiration_policy.ndjson
│   ├── custom_attributes.ndjson
│   ├── error_tracking_setting.ndjson
│   ├── external_pull_requests.ndjson
│   ├── issues.ndjson
│   ├── labels.ndjson
│   ├── merge_requests.ndjson
│   ├── milestones.ndjson
│   ├── pipeline_schedules.ndjson
│   ├── project_badges.ndjson
│   ├── project_feature.ndjson
│   ├── project_members.ndjson
│   ├── protected_branches.ndjson
│   ├── protected_tags.ndjson
│   ├── releases.ndjson
│   ├── services.ndjson
│   ├── snippets.ndjson
│   └── triggers.ndjson
└── project.json

그룹#

NDJSON 트리를 생성하려면 legacy-group-json-to-ndjson.rb를 사용하세요.

NDJSON 트리의 구조는 다음과 같습니다:

tree
└── groups
    ├── 4351
    │   ├── badges.ndjson
    │   ├── boards.ndjson
    │   ├── epics.ndjson
    │   ├── labels.ndjson
    │   ├── members.ndjson
    │   └── milestones.ndjson
    ├── 4352
    │   ├── badges.ndjson
    │   ├── boards.ndjson
    │   ├── epics.ndjson
    │   ├── labels.ndjson
    │   ├── members.ndjson
    │   └── milestones.ndjson
    ├── _all.ndjson
    ├── 4351.json
    └── 4352.json

이 픽스처를 업데이트할 때는 테스트가 두 형식 모두에 적용되므로 json 파일과 tree 폴더를 모두 업데이트해야 합니다.

Import/Export 개발 문서

GitLab v19.1
원문 보기
요약

새로 추가되는 관계(relation)는 버그 및 성능 이슈 도입 위험을 줄이기 위해 기능 플래그 뒤에 배치해야 합니다. Import/Export 기능에 대한 일반 개발 가이드라인과 팁입니다. 이 문서는 원래 YouTube에서 제공되는 Import/Export 201 프레젠테이션을 기반으로 작성되었습니다.

새로 추가되는 관계(relation)는 버그 및 성능 이슈 도입 위험을 줄이기 위해 기능 플래그 뒤에 배치해야 합니다.

Import/Export 기능에 대한 일반 개발 가이드라인과 팁입니다.

이 문서는 원래 YouTube에서 제공되는 Import/Export 201 프레젠테이션을 기반으로 작성되었습니다.

더 많은 맥락을 위해 YouTube의 Import/Export 개발 심층 분석을 시청할 수 있습니다.

Import/Export 개발 문서#

보안#

Import/Export 기능은 지속적으로 업데이트(새로운 내보내기 항목 추가)되고 있습니다. 그러나 코드는 오랫동안 리팩토링되지 않았습니다. 동적인 특성으로 인해 보안 우려 사항의 수가 증가하지 않도록 코드 감사를 수행해야 합니다. GitLab 팀원은 이 비공개 이슈에서 자세한 정보를 확인할 수 있습니다: https://gitlab.com/gitlab-org/gitlab/-/issues/20720.

코드 내 보안#

다음 클래스들 중 일부는 Import/Export에 보안 레이어를 제공합니다.

AttributeCleaner는 금지된 키를 제거합니다:

# AttributeCleaner
# Removes all `_ids` and other prohibited keys
    class AttributeCleaner
      ALLOWED_REFERENCES = RelationFactory::PROJECT_REFERENCES + RelationFactory::USER_REFERENCES + ['group_id']

      def clean
        @relation_hash.reject do |key, _value|
          prohibited_key?(key) || !@relation_class.attribute_method?(key) || excluded_key?(key)
        end.except('id')
      end

      ...

AttributeConfigurationSpec은 새 칼럼 추가를 확인하고 검증합니다:

# AttributeConfigurationSpec
<<-MSG
  It looks like #{relation_class}, which is exported using the project Import/Export, has new attributes:

  Please add the attribute(s) to SAFE_MODEL_ATTRIBUTES if they can be exported.

  Please denylist the attribute(s) in IMPORT_EXPORT_CONFIG by adding it to its corresponding
  model in the +excluded_attributes+ section.

  SAFE_MODEL_ATTRIBUTES: #{File.expand_path(safe_attributes_file)}
  IMPORT_EXPORT_CONFIG: #{Gitlab::ImportExport.config_file}
MSG

ModelConfigurationSpec은 새 모델 추가를 확인하고 검증합니다:

# ModelConfigurationSpec
<<-MSG
  New model(s) <#{new_models.join(',')}> have been added, related to #{parent_model_name}, which is exported by
  the Import/Export feature.

  If you think this model should be included in the export, please add it to `#{Gitlab::ImportExport.config_file}`.

  Definitely add it to `#{File.expand_path(ce_models_yml)}`
  to signal that you've handled this error and to prevent it from showing up in the future.
MSG

ExportFileSpec은 암호화되거나 민감한 칼럼을 탐지합니다:

# ExportFileSpec
<<-MSG
  Found a new sensitive word <#{key_found}>, which is part of the hash #{parent.inspect}
  If you think this information shouldn't get exported, please exclude the model or attribute in
  IMPORT_EXPORT_CONFIG.

  Otherwise, please add the exception to +safe_list+ in CURRENT_SPEC using #{sensitive_word} as the
  key and the correspondent hash or model as the value.

  Also, if the attribute is a generated unique token, please add it to RelationFactory::TOKEN_RESET_MODELS
  if it needs to be reset (to prevent duplicate column problems while importing to the same instance).

  IMPORT_EXPORT_CONFIG: #{Gitlab::ImportExport.config_file}
  CURRENT_SPEC: #{__FILE__}
MSG

버전 관리#

Import/Export는 단일 GitLab 릴리스 중에도 상수 변경이 잦기 때문에 엄격한 SemVer를 사용하지 않습니다. 하지만 호환성을 깨는 변경이 있을 때는 버전 업데이트가 필요합니다.

# ImportExport
module Gitlab
  module ImportExport
    extend self

    # For every version update, the history in import_export.md has to be kept up to date.
    VERSION = '0.2.4'

호환성#

프로젝트를 가져오거나 내보낼 때 호환성을 확인하세요.

버전을 올려야 하는 경우#

모델/칼럼 이름을 변경하거나 JSON 구조 또는 아카이브 파일의 파일 구조에 대한 형식 수정을 수행하는 경우 버전을 올려야 합니다.

다음의 경우에는 버전을 올릴 필요가 없습니다:

  • 새 칼럼 또는 모델 추가

  • 칼럼 또는 모델 제거(DB 제약 조건이 없는 경우)

  • 새로운 항목 내보내기(예: 새로운 유형의 업로드)

버전을 올릴 때마다 통합 스펙이 실패하며, 다음 명령으로 수정할 수 있습니다:

bundle exec rake gitlab:import_export:bump_version

코드 빠른 살펴보기#

Import/Export 설정 (import_export.yml)#

주요 설정 파일 import_export.yml은 내보내거나 가져올 수 있는 모델을 정의합니다.

프로젝트 import/export에 포함할 모델 관계:

project_tree:
  - labels:
    - :priorities
  - milestones:
    - events:
      - :push_event_payload
  - issues:
    - events:
    # ...

지정된 모델에 대해 다음 속성만 포함:

included_attributes:
  user:
    - :id
    - :public_email
  # ...

지정된 모델에 대해 다음 속성은 포함하지 않음:

excluded_attributes:
  project:
    - :name
    - :path
    - ...

내보내기 시 호출할 추가 메서드:

# Methods
methods:
  labels:
    - :type
  label:
    - :type

모델 관계의 내보내기 순서 커스터마이즈:

# Specify a custom export reordering for a given relationship
# For example for issues we use a custom export reordering by relative_position, so that on import, we can reset the
# relative position value, but still keep the issues order to the order in which issues were in the exported project.
# By default the ordering of relations is done by PK.
# column - specify the column by which to reorder, by default it is relation's PK
# direction - specify the ordering direction :asc or :desc, default :asc
# nulls_position - specify where would null values be positioned. Because custom ordering column can contain nulls we
#                  need to also specify where would the nulls be placed. It can be :nulls_last or :nulls_first, defaults
#                  to :nulls_last

export_reorders:
  project:
    issues:
      column: :relative_position
      direction: :asc
      nulls_position: :nulls_last

조건부 내보내기#

연관된 리소스가 프로젝트 외부에서 온 경우, 프로젝트 또는 그룹을 내보내는 사용자가 이러한 연관에 접근할 수 있는지 검증해야 할 수 있습니다. include_if_exportable은 리소스에 대한 연관의 배열을 받습니다. 내보내기 시, 연관된 리소스를 내보내기에 포함할 수 있는지 검증하기 위해 리소스의 exportable_association? 메서드가 연관 이름과 사용자를 인수로 호출됩니다.

예시:

include_if_exportable:
  project:
    issues:
      - epic_issue

이 정의는:

  • 이슈의 exportable_association?(:epic_issue, current_user: current_user) 메서드를 호출합니다.

  • 메서드가 true를 반환하면, 해당 이슈의 epic_issue 연관을 이슈에 포함합니다.

Import#

import job 상태는 none에서 여러 상태를 거쳐 finished 또는 failed로 이동합니다:

import_status: none -> scheduled -> started -> finished/failed

상태가 started인 동안 Importer 코드는 import에 필요한 각 단계를 처리합니다.

# ImportExport::Importer
module Gitlab
  module ImportExport
    class Importer
      def execute
        if import_file && check_version! && restorers.all?(&:restore) && overwrite_project
          project
        else
          raise Projects::ImportService::Error.new(@shared.errors.join(', '))
        end
      rescue => e
        raise Projects::ImportService::Error.new(e.message)
      ensure
        remove_import_file
      end

      def restorers
        [repo_restorer, wiki_restorer, project_tree, avatar_restorer,
         uploads_restorer, lfs_restorer, statistics_restorer]
      end

내보내기 서비스는 Importer와 유사하지만, 데이터를 저장하는 대신 복원합니다.

Export#

# ImportExport::ExportService
module Projects
  module ImportExport
    class ExportService < BaseService

      def save_all!
        if save_services
          Gitlab::ImportExport::Saver.save(project: project, shared: @shared, user: user)
          notify_success
        else
          cleanup_and_notify_error!
        end
      end

      def save_services
        [version_saver, avatar_saver, project_tree_saver, uploads_saver, repo_saver,
           wiki_repo_saver, lfs_saver].all?(&:save)
      end

테스트 픽스처#

Import/Export 스펙에서 사용되는 픽스처는 spec/fixtures/lib/gitlab/import_export에 있습니다. 프로젝트와 그룹 픽스처가 모두 있습니다.

각 픽스처에는 두 가지 버전이 있습니다:

  • 모든 객체가 포함된 사람이 읽을 수 있는 단일 JSON 파일로, project.json 또는 group.json이라고 합니다.

  • ndjson 형식의 파일 트리를 포함하는 tree라는 폴더. 반드시 필요하지 않은 한 이 폴더 아래의 파일을 수동으로 편집하지 마세요.

사람이 읽을 수 있는 JSON 파일에서 NDJSON 트리를 생성하는 도구는 gitlab-org/cloud-connector-team/team-tools 프로젝트에 있습니다.

프로젝트#

NDJSON 트리를 생성하려면 legacy-project-json-to-ndjson.sh를 사용하세요.

NDJSON 트리의 구조는 다음과 같습니다:

tree
├── project
│   ├── auto_devops.ndjson
│   ├── boards.ndjson
│   ├── ci_cd_settings.ndjson
│   ├── ci_pipelines.ndjson
│   ├── container_expiration_policy.ndjson
│   ├── custom_attributes.ndjson
│   ├── error_tracking_setting.ndjson
│   ├── external_pull_requests.ndjson
│   ├── issues.ndjson
│   ├── labels.ndjson
│   ├── merge_requests.ndjson
│   ├── milestones.ndjson
│   ├── pipeline_schedules.ndjson
│   ├── project_badges.ndjson
│   ├── project_feature.ndjson
│   ├── project_members.ndjson
│   ├── protected_branches.ndjson
│   ├── protected_tags.ndjson
│   ├── releases.ndjson
│   ├── services.ndjson
│   ├── snippets.ndjson
│   └── triggers.ndjson
└── project.json

그룹#

NDJSON 트리를 생성하려면 legacy-group-json-to-ndjson.rb를 사용하세요.

NDJSON 트리의 구조는 다음과 같습니다:

tree
└── groups
    ├── 4351
    │   ├── badges.ndjson
    │   ├── boards.ndjson
    │   ├── epics.ndjson
    │   ├── labels.ndjson
    │   ├── members.ndjson
    │   └── milestones.ndjson
    ├── 4352
    │   ├── badges.ndjson
    │   ├── boards.ndjson
    │   ├── epics.ndjson
    │   ├── labels.ndjson
    │   ├── members.ndjson
    │   └── milestones.ndjson
    ├── _all.ndjson
    ├── 4351.json
    └── 4352.json

이 픽스처를 업데이트할 때는 테스트가 두 형식 모두에 적용되므로 json 파일과 tree 폴더를 모두 업데이트해야 합니다.