uffizzi_core 0.3.2 → 0.3.5
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 +4 -4
- data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments_controller.rb +15 -17
- data/app/jobs/uffizzi_core/config_file/apply_job.rb +2 -2
- data/app/lib/uffizzi_core/concerns/models/activity_item.rb +0 -8
- data/app/lib/uffizzi_core/concerns/models/deployment.rb +5 -0
- data/app/repositories/uffizzi_core/activity_item_repo.rb +4 -0
- data/app/repositories/uffizzi_core/compose_file_repo.rb +0 -3
- data/app/repositories/uffizzi_core/config_file_repo.rb +0 -22
- data/app/repositories/uffizzi_core/container_repo.rb +0 -5
- data/app/repositories/uffizzi_core/credential_repo.rb +0 -8
- data/app/repositories/uffizzi_core/deployment_repo.rb +0 -11
- data/app/repositories/uffizzi_core/membership_repo.rb +0 -1
- data/app/repositories/uffizzi_core/repo_repo.rb +0 -1
- data/app/repositories/uffizzi_core/template_repo.rb +0 -87
- data/app/serializers/uffizzi_core/api/cli/v1/project_serializer/deployment_serializer.rb +0 -4
- data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer.rb +0 -4
- data/app/services/uffizzi_core/compose_file_service.rb +11 -0
- data/app/services/uffizzi_core/controller_service.rb +1 -1
- data/app/services/uffizzi_core/deployment_service.rb +9 -9
- data/app/services/uffizzi_core/docker_hub_service.rb +6 -6
- data/db/migrate/20220704135629_add_disabled_at_to_deployments.rb +16 -0
- data/lib/uffizzi_core/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b888a8d1591e641bb45316b744f8c7b71352104761401b3388590edb75a1cfee
|
4
|
+
data.tar.gz: efec514c14a589b68da1bb42fe28e7bbdf7569ab6bfc1b4ea22ba8b2b4f14b88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30dc824b604d9c770645a86853f96dd251826d1ddb0e4429b14697fc16a56e891854eac9ac20eeaea12f6aae76f9921ebb2e203517281585a6326eba93483b30
|
7
|
+
data.tar.gz: c732982588d01d53a65cbb090acfd244b5b8c6c5dcf272ad80a3bc37e02797dcf2d5d06df252ffbc2b5e982ff1a165d1b44ba527d95fc38c411103eee41d265e
|
@@ -70,17 +70,22 @@ class UffizziCore::Api::Cli::V1::Projects::DeploymentsController < UffizziCore::
|
|
70
70
|
# @response [object<errors: object<title: string>>] 404 Not found
|
71
71
|
# @response 401 Not authorized
|
72
72
|
def update
|
73
|
-
compose_file, errors =
|
73
|
+
compose_file, errors = UffizziCore::ComposeFileService.create_temporary_compose(
|
74
|
+
resource_project,
|
75
|
+
current_user,
|
76
|
+
compose_file_params,
|
77
|
+
dependencies_params[:dependencies],
|
78
|
+
)
|
74
79
|
return render_invalid_file if compose_file.invalid_file?
|
75
80
|
return render_errors(errors) if errors.present?
|
76
81
|
|
77
82
|
errors = check_credentials(compose_file)
|
78
83
|
return render_errors(errors) if errors.present?
|
79
84
|
|
80
|
-
|
81
|
-
|
85
|
+
deployment = UffizziCore::Deployment.find(params[:id])
|
86
|
+
updated_deployment = UffizziCore::DeploymentService.update_from_compose(compose_file, resource_project, current_user, deployment)
|
82
87
|
|
83
|
-
respond_with
|
88
|
+
respond_with updated_deployment
|
84
89
|
end
|
85
90
|
|
86
91
|
# @path [POST] /api/cli/v1/projects/{project_slug}/deployments/{id}/deploy_containers
|
@@ -126,7 +131,12 @@ class UffizziCore::Api::Cli::V1::Projects::DeploymentsController < UffizziCore::
|
|
126
131
|
def find_or_create_compose_file
|
127
132
|
existing_compose_file = resource_project.compose_file
|
128
133
|
if compose_file_params.present?
|
129
|
-
|
134
|
+
UffizziCore::ComposeFileService.create_temporary_compose(
|
135
|
+
resource_project,
|
136
|
+
current_user,
|
137
|
+
compose_file_params,
|
138
|
+
dependencies_params[:dependencies],
|
139
|
+
)
|
130
140
|
else
|
131
141
|
raise ActiveRecord::RecordNotFound if existing_compose_file.blank?
|
132
142
|
|
@@ -135,18 +145,6 @@ class UffizziCore::Api::Cli::V1::Projects::DeploymentsController < UffizziCore::
|
|
135
145
|
end
|
136
146
|
end
|
137
147
|
|
138
|
-
def create_temporary_compose_file
|
139
|
-
create_params = {
|
140
|
-
project: resource_project,
|
141
|
-
user: current_user,
|
142
|
-
compose_file_params: compose_file_params,
|
143
|
-
dependencies: dependencies_params[:dependencies] || [],
|
144
|
-
}
|
145
|
-
|
146
|
-
kind = UffizziCore::ComposeFile.kind.temporary
|
147
|
-
UffizziCore::ComposeFileService.create(create_params, kind)
|
148
|
-
end
|
149
|
-
|
150
148
|
def check_credentials(compose_file)
|
151
149
|
credentials = resource_project.account.credentials
|
152
150
|
check_credentials_form = UffizziCore::Api::Cli::V1::ComposeFile::CheckCredentialsForm.new
|
@@ -5,7 +5,7 @@ class UffizziCore::ConfigFile::ApplyJob < UffizziCore::ApplicationJob
|
|
5
5
|
|
6
6
|
sidekiq_retry_in do |count, exception|
|
7
7
|
case exception
|
8
|
-
when UffizziCore::
|
8
|
+
when UffizziCore::DeploymentNotFoundError
|
9
9
|
Rails.logger.info("DEPLOYMENT_PROCESS ApplyJob retry deployment_id=#{exception.deployment_id} count=#{count}")
|
10
10
|
Settings.controller.resource_create_retry_time
|
11
11
|
end
|
@@ -22,7 +22,7 @@ class UffizziCore::ConfigFile::ApplyJob < UffizziCore::ApplicationJob
|
|
22
22
|
end
|
23
23
|
|
24
24
|
unless UffizziCore::ControllerService.deployment_exists?(deployment)
|
25
|
-
raise UffizziCore::
|
25
|
+
raise UffizziCore::DeploymentNotFoundError,
|
26
26
|
deployment_id
|
27
27
|
end
|
28
28
|
|
@@ -14,14 +14,6 @@ module UffizziCore::Concerns::Models::ActivityItem
|
|
14
14
|
|
15
15
|
has_many :events, dependent: :destroy
|
16
16
|
|
17
|
-
scope :docker, -> {
|
18
|
-
where(type: UffizziCore::ActivityItem::Docker.name)
|
19
|
-
}
|
20
|
-
|
21
|
-
scope :github, -> {
|
22
|
-
where(type: UffizziCore::ActivityItem::Github.name)
|
23
|
-
}
|
24
|
-
|
25
17
|
def docker?
|
26
18
|
type == UffizziCore::ActivityItem::Docker.name
|
27
19
|
end
|
@@ -57,6 +57,7 @@ module UffizziCore::Concerns::Models::Deployment
|
|
57
57
|
|
58
58
|
def after_disable
|
59
59
|
clean
|
60
|
+
update!(disabled_at: Time.now)
|
60
61
|
end
|
61
62
|
|
62
63
|
def after_fail
|
@@ -67,5 +68,9 @@ module UffizziCore::Concerns::Models::Deployment
|
|
67
68
|
active_containers.each(&:disable!)
|
68
69
|
UffizziCore::Deployment::DeleteJob.perform_async(id)
|
69
70
|
end
|
71
|
+
|
72
|
+
def preview_url
|
73
|
+
"#{subdomain}.#{Settings.app.managed_dns_zone}"
|
74
|
+
end
|
70
75
|
end
|
71
76
|
end
|
@@ -14,27 +14,5 @@ module UffizziCore::ConfigFileRepo
|
|
14
14
|
scope :by_source, ->(source) {
|
15
15
|
where(source: source)
|
16
16
|
}
|
17
|
-
|
18
|
-
scope :only_used_config_files, -> {
|
19
|
-
select(:id)
|
20
|
-
.where("(id = ANY(ARRAY(select distinct(
|
21
|
-
jsonb_array_elements(
|
22
|
-
(
|
23
|
-
jsonb_array_elements(
|
24
|
-
jsonb_extract_path_text(
|
25
|
-
payload::jsonb, 'containers_attributes'
|
26
|
-
)::jsonb
|
27
|
-
) ->> 'container_config_files_attributes'
|
28
|
-
)::jsonb
|
29
|
-
) ->> 'config_file_id'
|
30
|
-
) as ids from templates)::int[]))")
|
31
|
-
.or(
|
32
|
-
UffizziCore::ConfigFile.where(
|
33
|
-
id: UffizziCore::ContainerConfigFile.where(
|
34
|
-
container_id: UffizziCore::Container.active.select(:id),
|
35
|
-
).select(:config_file_id),
|
36
|
-
),
|
37
|
-
)
|
38
|
-
}
|
39
17
|
end
|
40
18
|
end
|
@@ -6,7 +6,6 @@ module UffizziCore::ContainerRepo
|
|
6
6
|
included do
|
7
7
|
include UffizziCore::BasicOrderRepo
|
8
8
|
|
9
|
-
scope :with_github_repo, -> { includes(:repo).where(repo: { type: UffizziCore::Repo::Github.name }) }
|
10
9
|
scope :with_amazon_repo, -> { includes(:repo).where(repo: { type: UffizziCore::Repo::Amazon.name }) }
|
11
10
|
scope :with_docker_hub_repo, -> { includes(:repo).where(repo: { type: UffizziCore::Repo::DockerHub.name }) }
|
12
11
|
|
@@ -14,10 +13,6 @@ module UffizziCore::ContainerRepo
|
|
14
13
|
where(public: true)
|
15
14
|
}
|
16
15
|
|
17
|
-
scope :with_enabled_continuously_deploy, -> {
|
18
|
-
where(continuously_deploy: UffizziCore::Container::STATE_ENABLED)
|
19
|
-
}
|
20
|
-
|
21
16
|
scope :by_repo_type, ->(type) {
|
22
17
|
includes(:repo).where(repo: { type: type })
|
23
18
|
}
|
@@ -5,19 +5,11 @@ module UffizziCore::CredentialRepo
|
|
5
5
|
|
6
6
|
included do
|
7
7
|
scope :by_type, ->(type) { where(type: type) }
|
8
|
-
|
9
8
|
scope :docker_hub, -> { by_type(UffizziCore::Credential::DockerHub.name) }
|
10
|
-
|
11
|
-
scope :github, -> { by_type(UffizziCore::Credential::Github.name) }
|
12
|
-
|
13
9
|
scope :azure, -> { by_type(UffizziCore::Credential::Azure.name) }
|
14
|
-
|
15
10
|
scope :google, -> { by_type(UffizziCore::Credential::Google.name) }
|
16
|
-
|
17
11
|
scope :amazon, -> { by_type(UffizziCore::Credential::Amazon.name) }
|
18
|
-
|
19
12
|
scope :github_container_registry, -> { by_type(UffizziCore::Credential::GithubContainerRegistry.name) }
|
20
|
-
|
21
13
|
scope :deployable, -> {
|
22
14
|
by_type([
|
23
15
|
UffizziCore::Credential::DockerHub.name,
|
@@ -7,18 +7,7 @@ module UffizziCore::DeploymentRepo
|
|
7
7
|
scope :with_name, ->(name) {
|
8
8
|
where(name: name)
|
9
9
|
}
|
10
|
-
scope :by_config_file, ->(config_file) {
|
11
|
-
container_config_files = UffizziCore::ContainerConfigFile.where(config_file: config_file)
|
12
|
-
containers = UffizziCore::Container.where(id: container_config_files.select(:container_id))
|
13
|
-
where(id: containers.select(:deployment_id))
|
14
|
-
}
|
15
10
|
scope :with_amazon_repos, -> { includes(containers: [:repo]).where(containers: { repos: { type: UffizziCore::Repo::Amazon.name } }) }
|
16
|
-
scope :by_templates, ->(templates) {
|
17
|
-
where(template: templates).where.not(templates: nil)
|
18
|
-
}
|
19
|
-
scope :with_containers, ->(source, image, tag) {
|
20
|
-
includes(containers: :repo).where(containers: { image: image, tag: tag, repos: { type: source } })
|
21
|
-
}
|
22
11
|
scope :existed, -> { where(state: [:active, :failed]) }
|
23
12
|
end
|
24
13
|
end
|
@@ -4,92 +4,5 @@ module UffizziCore::TemplateRepo
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
scope :by_docker_containers_with_deploy_preview_when_image_tag_is_created, ->(source, image, tag) {
|
8
|
-
general_query = {
|
9
|
-
containers_attributes: [
|
10
|
-
{
|
11
|
-
image: image,
|
12
|
-
repo_attributes: {
|
13
|
-
type: source,
|
14
|
-
deploy_preview_when_image_tag_is_created: true,
|
15
|
-
},
|
16
|
-
},
|
17
|
-
],
|
18
|
-
}
|
19
|
-
|
20
|
-
excluding_query = {
|
21
|
-
containers_attributes: [
|
22
|
-
{
|
23
|
-
image: image,
|
24
|
-
tag: tag,
|
25
|
-
repo_attributes: {
|
26
|
-
type: source,
|
27
|
-
deploy_preview_when_image_tag_is_created: true,
|
28
|
-
},
|
29
|
-
},
|
30
|
-
],
|
31
|
-
}
|
32
|
-
|
33
|
-
where('templates.payload @> ?', general_query.to_json).where.not('templates.payload @> ?', excluding_query.to_json)
|
34
|
-
}
|
35
|
-
|
36
|
-
scope :by_docker_containers_with_delete_preview_when_image_tag_is_updated, ->(source, image, tag) {
|
37
|
-
general_query = {
|
38
|
-
containers_attributes: [
|
39
|
-
{
|
40
|
-
image: image,
|
41
|
-
tag: tag,
|
42
|
-
repo_attributes: {
|
43
|
-
type: source,
|
44
|
-
delete_preview_when_image_tag_is_updated: true,
|
45
|
-
},
|
46
|
-
},
|
47
|
-
],
|
48
|
-
}
|
49
|
-
|
50
|
-
where('templates.payload @> ?', general_query.to_json)
|
51
|
-
}
|
52
|
-
|
53
|
-
scope :by_github_containers_with_deploy_preview_when_pull_request_is_opened, ->(repository_id, branch) {
|
54
|
-
query = {
|
55
|
-
containers_attributes: [
|
56
|
-
{
|
57
|
-
repo_attributes: {
|
58
|
-
type: UffizziCore::Repo::Github.name,
|
59
|
-
repository_id: repository_id,
|
60
|
-
branch: branch,
|
61
|
-
deploy_preview_when_pull_request_is_opened: true,
|
62
|
-
},
|
63
|
-
},
|
64
|
-
],
|
65
|
-
}
|
66
|
-
|
67
|
-
where('templates.payload @> ?', query.to_json)
|
68
|
-
}
|
69
|
-
|
70
|
-
scope :by_github_containers_with_delete_preview_when_pull_request_is_closed, ->(repository_id, branch) {
|
71
|
-
query = {
|
72
|
-
containers_attributes: [
|
73
|
-
{
|
74
|
-
repo_attributes: {
|
75
|
-
type: UffizziCore::Repo::Github.name,
|
76
|
-
repository_id: repository_id,
|
77
|
-
branch: branch,
|
78
|
-
delete_preview_when_pull_request_is_closed: true,
|
79
|
-
},
|
80
|
-
},
|
81
|
-
],
|
82
|
-
}
|
83
|
-
|
84
|
-
where('templates.payload @> ?', query.to_json)
|
85
|
-
}
|
86
|
-
|
87
|
-
scope :by_compose_file_kind, ->(kind) {
|
88
|
-
left_joins(:compose_file).where(compose_files: { kind: kind })
|
89
|
-
}
|
90
|
-
|
91
|
-
scope :without_compose, -> {
|
92
|
-
left_joins(:compose_file).where(compose_files: { id: nil })
|
93
|
-
}
|
94
7
|
end
|
95
8
|
end
|
@@ -30,10 +30,6 @@ class UffizziCore::Api::Cli::V1::Projects::DeploymentSerializer < UffizziCore::B
|
|
30
30
|
object.containers.active
|
31
31
|
end
|
32
32
|
|
33
|
-
def preview_url
|
34
|
-
UffizziCore::DeploymentService.build_preview_url(object)
|
35
|
-
end
|
36
|
-
|
37
33
|
def tag
|
38
34
|
object.ingress_container&.tag
|
39
35
|
end
|
@@ -87,6 +87,17 @@ class UffizziCore::ComposeFileService
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
+
def create_temporary_compose(resource_project, current_user, compose_file_params, dependencies)
|
91
|
+
create_params = {
|
92
|
+
project: resource_project,
|
93
|
+
user: current_user,
|
94
|
+
compose_file_params: compose_file_params,
|
95
|
+
dependencies: dependencies || [],
|
96
|
+
}
|
97
|
+
kind = UffizziCore::ComposeFile.kind.temporary
|
98
|
+
UffizziCore::ComposeFileService.create(create_params, kind)
|
99
|
+
end
|
100
|
+
|
90
101
|
private
|
91
102
|
|
92
103
|
def process_compose_file(compose_file_form, params)
|
@@ -52,7 +52,7 @@ class UffizziCore::ControllerService
|
|
52
52
|
body = {
|
53
53
|
containers: containers,
|
54
54
|
credentials: credentials,
|
55
|
-
deployment_url:
|
55
|
+
deployment_url: deployment.preview_url,
|
56
56
|
}
|
57
57
|
|
58
58
|
if password_protection_module.present?
|
@@ -29,23 +29,21 @@ class UffizziCore::DeploymentService
|
|
29
29
|
deployment_form
|
30
30
|
end
|
31
31
|
|
32
|
-
def update_from_compose(compose_file, project, user,
|
32
|
+
def update_from_compose(compose_file, project, user, deployment)
|
33
33
|
deployment_attributes = ActionController::Parameters.new(compose_file.template.payload)
|
34
34
|
|
35
35
|
deployment_form = UffizziCore::Api::Cli::V1::Deployment::UpdateForm.new(deployment_attributes)
|
36
36
|
deployment_form.assign_dependences!(project, user)
|
37
37
|
deployment_form.compose_file = compose_file
|
38
38
|
|
39
|
-
|
40
|
-
deployment = UffizziCore::Deployment.find(deployment_id)
|
39
|
+
ActiveRecord::Base.transaction do
|
41
40
|
deployment.containers.destroy_all
|
42
|
-
deployment.compose_file.destroy if deployment.compose_file.kind.temporary?
|
43
|
-
deployment.update!(containers: deployment_form.containers, compose_file_id: compose_file.id)
|
41
|
+
deployment.compose_file.destroy! if deployment.compose_file.kind.temporary?
|
44
42
|
|
45
|
-
|
43
|
+
deployment.update!(containers: deployment_form.containers, compose_file_id: compose_file.id)
|
46
44
|
end
|
47
45
|
|
48
|
-
|
46
|
+
deployment
|
49
47
|
end
|
50
48
|
|
51
49
|
def deploy_containers(deployment, repeated = false)
|
@@ -62,7 +60,7 @@ class UffizziCore::DeploymentService
|
|
62
60
|
Rails.logger.info("DEPLOYMENT_PROCESS deployment_id=#{deployment.id} start deploying into controller")
|
63
61
|
|
64
62
|
containers = deployment.active_containers
|
65
|
-
containers = add_default_deployment_variables!(containers)
|
63
|
+
containers = add_default_deployment_variables!(containers, deployment)
|
66
64
|
|
67
65
|
UffizziCore::ControllerService.deploy_containers(deployment, containers)
|
68
66
|
else
|
@@ -284,13 +282,15 @@ class UffizziCore::DeploymentService
|
|
284
282
|
Digest::SHA256.hexdigest("#{container.id}:#{container.image}")[0, 10]
|
285
283
|
end
|
286
284
|
|
287
|
-
def add_default_deployment_variables!(containers)
|
285
|
+
def add_default_deployment_variables!(containers, deployment)
|
288
286
|
containers.each do |container|
|
289
287
|
envs = []
|
290
288
|
if container.port.present? && !UffizziCore::ContainerService.defines_env?(container, 'PORT')
|
291
289
|
envs.push('name' => 'PORT', 'value' => container.target_port.to_s)
|
292
290
|
end
|
293
291
|
|
292
|
+
envs.push('name' => 'UFFIZZI_URL', 'value' => "https://#{deployment.preview_url}")
|
293
|
+
|
294
294
|
container.variables = [] if container.variables.nil?
|
295
295
|
|
296
296
|
container.variables.push(*envs)
|
@@ -49,13 +49,13 @@ class UffizziCore::DockerHubService
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def user_client(credential)
|
52
|
-
if @client.
|
53
|
-
@client = UffizziCore::DockerHubClient.new(credential)
|
52
|
+
return @client if @client&.credential&.username == credential.username
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
54
|
+
@client = UffizziCore::DockerHubClient.new(credential)
|
55
|
+
|
56
|
+
unless @client.authentificated?
|
57
|
+
Rails.logger.warn("broken credentials, DockerHubService credential_id=#{credential.id}")
|
58
|
+
credential.unauthorize! unless credential.unauthorized?
|
59
59
|
end
|
60
60
|
|
61
61
|
@client
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddDisabledAtToDeployments < ActiveRecord::Migration[6.1]
|
4
|
+
def up
|
5
|
+
change_table :uffizzi_core_deployments do |t|
|
6
|
+
t.datetime :disabled_at
|
7
|
+
end
|
8
|
+
UffizziCore::Deployment.disabled.update_all('disabled_at = updated_at')
|
9
|
+
end
|
10
|
+
|
11
|
+
def down
|
12
|
+
change_table :uffizzi_core_deployments do |t|
|
13
|
+
t.remove :disabled_at
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/uffizzi_core/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uffizzi_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Thurman
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-07-
|
12
|
+
date: 2022-07-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aasm
|
@@ -957,6 +957,7 @@ files:
|
|
957
957
|
- db/migrate/20220419074956_add_health_check_to_containers.rb
|
958
958
|
- db/migrate/20220422151523_add_volumes_to_uffizzi_core_containers.rb
|
959
959
|
- db/migrate/20220525113412_rename_name_to_uffizzi_containers.rb
|
960
|
+
- db/migrate/20220704135629_add_disabled_at_to_deployments.rb
|
960
961
|
- db/seeds.rb
|
961
962
|
- lib/tasks/uffizzi_core_tasks.rake
|
962
963
|
- lib/uffizzi_core.rb
|