Class: PlanMyStuff::TestingProject

Inherits:
BaseProject show all
Defined in:
lib/plan_my_stuff/testing_project.rb

Overview

A GitHub Projects V2 project used to track manual verification of features. Identified by kind: “testing” in its readme metadata. Sibling of Project - both inherit shared machinery from BaseProject.

BaseProject.find / BaseProject.list dispatch to TestingProject automatically when the metadata kind matches; TestingProject.find raises APIError if the requested project is not a testing project. TestingProject.create! bootstraps testing-specific custom fields after creating the underlying GH project.

Constant Summary collapse

BOOTSTRAP_FIELDS =

Default GH Project custom field definitions bootstrapped on creation. Fields already present on the project are skipped.

“Test Status” is intentionally a separate field from GitHub’s built-in “Status” (which BaseProject and Pipeline hardcode). Using a parallel field lets the QA sign-off flow own its own options (Passed/Failed) without colliding with the board’s default Status column — a testing project pointed at a pipeline-tracked repo won’t overwrite either.

[
  { name: 'Test Status', data_type: 'SINGLE_SELECT', options: ['Todo', 'In Progress', 'Passed', 'Failed'] },
  { name: 'Testers', data_type: 'TEXT' },
  { name: 'Watchers', data_type: 'TEXT' },
  { name: 'Pass Mode', data_type: 'SINGLE_SELECT', options: %w[all any] },
  { name: 'Due Date', data_type: 'DATE' },
  { name: 'Deadline Miss Reason', data_type: 'TEXT' },
  { name: 'Result Notes', data_type: 'TEXT' },
  { name: 'Passed By', data_type: 'TEXT' },
  { name: 'Failed By', data_type: 'TEXT' },
  { name: 'Passed At', data_type: 'TEXT' },
].freeze

Constants inherited from BaseProject

BaseProject::ITEMS_PER_PAGE, BaseProject::MAX_AUTO_PAGINATE_ITEMS

Instance Attribute Summary

Attributes inherited from ApplicationRecord

#github_response

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BaseProject

clone!, #closed, #description, #fields, #has_next_page, #id, #items, #metadata, #next_cursor, #number, #pms_project?, #raw_readme, #readme, #reload, resolve_default_project_number, #save!, #statuses, #title, update!, #update!, #updated_at, #url

Methods inherited from ApplicationRecord

#destroyed?, #initialize, #new_record?, #persisted?, read_field

Constructor Details

This class inherits a constructor from PlanMyStuff::ApplicationRecord

Class Method Details

.create!(title:, user: nil, visibility: 'internal', custom_fields: {}, readme: '', description: nil, subject_urls: [], due_date: nil, deadline_miss_reason: nil) ⇒ PlanMyStuff::TestingProject

Creates a new testing project in the configured organization. Writes TestingProjectMetadata to the project readme and bootstraps any missing custom fields defined in BOOTSTRAP_FIELDS.

Parameters:

  • title (String)
  • user (Object, Integer, nil) (defaults to: nil)
  • visibility (String) (defaults to: 'internal')

    “public” or “internal”

  • custom_fields (Hash) (defaults to: {})

    app-defined metadata field values

  • readme (String) (defaults to: '')

    user-visible readme content

  • description (String, nil) (defaults to: nil)

    project short description

  • subject_urls (Array<String>) (defaults to: [])

    PR/issue URLs covered

  • due_date (Date, nil) (defaults to: nil)

    project-level deadline

  • deadline_miss_reason (String, nil) (defaults to: nil)

Returns:



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/plan_my_stuff/testing_project.rb', line 56

def create!(
  title:,
  user: nil,
  visibility: 'internal',
  custom_fields: {},
  readme: '',
  description: nil,
  subject_urls: [],
  due_date: nil,
  deadline_miss_reason: nil
)
  org = PlanMyStuff.configuration.organization

   = PlanMyStuff::TestingProjectMetadata.build(
    user: user,
    visibility: visibility,
    custom_fields: custom_fields,
    subject_urls: subject_urls,
    due_date: due_date,
    deadline_miss_reason: deadline_miss_reason,
  )
  .validate_custom_fields!

  template_number = PlanMyStuff.configuration.testing_template_project_number

  if template_number.present?
    create_from_template!(
      title: title,
      description: description,
      readme: readme,
      project_metadata: ,
      template_number: template_number,
    )
  else
    create_with_bootstrap!(
      title: title,
      description: description,
      readme: readme,
      project_metadata: ,
      org: org,
    )
  end
end

.find(number, paginate: :auto, cursor: nil) ⇒ PlanMyStuff::TestingProject

Finds a testing project by number. Raises if the project exists but is not a testing project.

Parameters:

  • number (Integer)
  • paginate (Symbol) (defaults to: :auto)

    :auto (default) or :cursor

  • cursor (String, nil) (defaults to: nil)

Returns:

Raises:

  • (ArgumentError)

    if the project is not a testing project



111
112
113
114
115
116
117
118
119
# File 'lib/plan_my_stuff/testing_project.rb', line 111

def find(number, paginate: :auto, cursor: nil)
  project = super

  unless project.is_a?(self)
    raise(ArgumentError, "Project ##{number} is not a testing project; use PlanMyStuff::Project.find")
  end

  project
end

.listArray<PlanMyStuff::TestingProject>

Lists all testing projects in the configured organization.

Returns:



125
126
127
# File 'lib/plan_my_stuff/testing_project.rb', line 125

def list
  super.select { |p| p.is_a?(self) }
end

Instance Method Details

#status_fieldHash

Returns the Test Status single-select field definition.

Returns:

  • (Hash)

    with :id and :options keys

Raises:



253
254
255
256
257
258
259
# File 'lib/plan_my_stuff/testing_project.rb', line 253

def status_field
  field = fields.find { |f| f[:name] == 'Test Status' && f[:options] }

  raise(APIError, "No 'Test Status' field found on project ##{number}") unless field

  field
end