Commit 95805515 authored by Kerri Miller's avatar Kerri Miller

Merge branch '10io-fix-graphql-container-repository-tag-size-type' into 'master'

Fix the graphQL type for container repository tags

See merge request gitlab-org/gitlab!50419
parents b1f29131 c2c3804d
...@@ -63,7 +63,9 @@ export default { ...@@ -63,7 +63,9 @@ export default {
}, },
computed: { computed: {
formattedSize() { formattedSize() {
return this.tag.totalSize ? numberToHumanSize(this.tag.totalSize) : NOT_AVAILABLE_SIZE; return this.tag.totalSize
? numberToHumanSize(Number(this.tag.totalSize))
: NOT_AVAILABLE_SIZE;
}, },
layers() { layers() {
return this.tag.layers ? n__('%d layer', '%d layers', this.tag.layers) : ''; return this.tag.layers ? n__('%d layer', '%d layers', this.tag.layers) : '';
......
...@@ -14,7 +14,7 @@ module Types ...@@ -14,7 +14,7 @@ module Types
field :digest, GraphQL::STRING_TYPE, null: true, description: 'Digest of the tag.' field :digest, GraphQL::STRING_TYPE, null: true, description: 'Digest of the tag.'
field :revision, GraphQL::STRING_TYPE, null: true, description: 'Revision of the tag.' field :revision, GraphQL::STRING_TYPE, null: true, description: 'Revision of the tag.'
field :short_revision, GraphQL::STRING_TYPE, null: true, description: 'Short revision of the tag.' field :short_revision, GraphQL::STRING_TYPE, null: true, description: 'Short revision of the tag.'
field :total_size, GraphQL::INT_TYPE, null: true, description: 'The size of the tag.' field :total_size, GraphQL::Types::BigInt, null: true, description: 'The size of the tag.'
field :created_at, Types::TimeType, null: true, description: 'Timestamp when the tag was created.' field :created_at, Types::TimeType, null: true, description: 'Timestamp when the tag was created.'
field :can_delete, GraphQL::BOOLEAN_TYPE, null: false, description: 'Can the current user delete this tag.' field :can_delete, GraphQL::BOOLEAN_TYPE, null: false, description: 'Can the current user delete this tag.'
......
---
title: Fix the graphQL type for container repository tags
merge_request: 50419
author:
type: fixed
...@@ -1149,6 +1149,12 @@ type BaseService implements Service { ...@@ -1149,6 +1149,12 @@ type BaseService implements Service {
type: String type: String
} }
"""
Represents non-fractional signed whole numeric values. Since the value may
exceed the size of a 32-bit integer, it's encoded as a string.
"""
scalar BigInt
type Blob implements Entry { type Blob implements Entry {
""" """
Flat path of the entry Flat path of the entry
...@@ -4075,7 +4081,7 @@ type ContainerRepositoryTag { ...@@ -4075,7 +4081,7 @@ type ContainerRepositoryTag {
""" """
The size of the tag. The size of the tag.
""" """
totalSize: Int totalSize: BigInt
} }
""" """
......
...@@ -3009,6 +3009,16 @@ ...@@ -3009,6 +3009,16 @@
"enumValues": null, "enumValues": null,
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "SCALAR",
"name": "BigInt",
"description": "Represents non-fractional signed whole numeric values. Since the value may exceed the size of a 32-bit integer, it's encoded as a string.",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{ {
"kind": "OBJECT", "kind": "OBJECT",
"name": "Blob", "name": "Blob",
...@@ -11105,7 +11115,7 @@ ...@@ -11105,7 +11115,7 @@
], ],
"type": { "type": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "Int", "name": "BigInt",
"ofType": null "ofType": null
}, },
"isDeprecated": false, "isDeprecated": false,
...@@ -640,7 +640,7 @@ A tag from a container repository. ...@@ -640,7 +640,7 @@ A tag from a container repository.
| `path` | String! | Path of the tag. | | `path` | String! | Path of the tag. |
| `revision` | String | Revision of the tag. | | `revision` | String | Revision of the tag. |
| `shortRevision` | String | Short revision of the tag. | | `shortRevision` | String | Short revision of the tag. |
| `totalSize` | Int | The size of the tag. | | `totalSize` | BigInt | The size of the tag. |
### CreateAlertIssuePayload ### CreateAlertIssuePayload
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
"type": "string" "type": "string"
}, },
"totalSize": { "totalSize": {
"type": "integer" "type": "string"
}, },
"createdAt": { "createdAt": {
"type": "string" "type": "string"
......
...@@ -172,25 +172,31 @@ describe('tags list row', () => { ...@@ -172,25 +172,31 @@ describe('tags list row', () => {
}); });
it('contains the totalSize and layers', () => { it('contains the totalSize and layers', () => {
mountComponent({ ...defaultProps, tag: { ...tag, totalSize: 1024, layers: 10 } }); mountComponent({ ...defaultProps, tag: { ...tag, totalSize: '1024', layers: 10 } });
expect(findSize().text()).toMatchInterpolatedText('1.00 KiB · 10 layers'); expect(findSize().text()).toMatchInterpolatedText('1.00 KiB · 10 layers');
}); });
it('when totalSize is giantic', () => {
mountComponent({ ...defaultProps, tag: { ...tag, totalSize: '1099511627776', layers: 2 } });
expect(findSize().text()).toMatchInterpolatedText('1024.00 GiB · 2 layers');
});
it('when totalSize is missing', () => { it('when totalSize is missing', () => {
mountComponent({ ...defaultProps, tag: { ...tag, totalSize: 0, layers: 10 } }); mountComponent({ ...defaultProps, tag: { ...tag, totalSize: '0', layers: 10 } });
expect(findSize().text()).toMatchInterpolatedText(`${NOT_AVAILABLE_SIZE} · 10 layers`); expect(findSize().text()).toMatchInterpolatedText(`${NOT_AVAILABLE_SIZE} · 10 layers`);
}); });
it('when layers are missing', () => { it('when layers are missing', () => {
mountComponent({ ...defaultProps, tag: { ...tag, totalSize: 1024 } }); mountComponent({ ...defaultProps, tag: { ...tag, totalSize: '1024' } });
expect(findSize().text()).toMatchInterpolatedText('1.00 KiB'); expect(findSize().text()).toMatchInterpolatedText('1.00 KiB');
}); });
it('when there is 1 layer', () => { it('when there is 1 layer', () => {
mountComponent({ ...defaultProps, tag: { ...tag, totalSize: 0, layers: 1 } }); mountComponent({ ...defaultProps, tag: { ...tag, totalSize: '0', layers: 1 } });
expect(findSize().text()).toMatchInterpolatedText(`${NOT_AVAILABLE_SIZE} · 1 layer`); expect(findSize().text()).toMatchInterpolatedText(`${NOT_AVAILABLE_SIZE} · 1 layer`);
}); });
......
...@@ -140,7 +140,7 @@ export const tagsMock = [ ...@@ -140,7 +140,7 @@ export const tagsMock = [
revision: 'c2613843ab33aabf847965442b13a8b55a56ae28837ce182627c0716eb08c02b', revision: 'c2613843ab33aabf847965442b13a8b55a56ae28837ce182627c0716eb08c02b',
shortRevision: 'c2613843a', shortRevision: 'c2613843a',
createdAt: '2020-11-03T13:29:38+00:00', createdAt: '2020-11-03T13:29:38+00:00',
totalSize: 105, totalSize: '1099511627776',
canDelete: true, canDelete: true,
__typename: 'ContainerRepositoryTag', __typename: 'ContainerRepositoryTag',
}, },
...@@ -152,7 +152,7 @@ export const tagsMock = [ ...@@ -152,7 +152,7 @@ export const tagsMock = [
revision: 'df44e7228f0f255c73e35b6f0699624a615f42746e3e8e2e4b3804a6d6fc3292', revision: 'df44e7228f0f255c73e35b6f0699624a615f42746e3e8e2e4b3804a6d6fc3292',
shortRevision: 'df44e7228', shortRevision: 'df44e7228',
createdAt: '2020-11-03T13:29:32+00:00', createdAt: '2020-11-03T13:29:32+00:00',
totalSize: 104, totalSize: '536870912000',
canDelete: true, canDelete: true,
__typename: 'ContainerRepositoryTag', __typename: 'ContainerRepositoryTag',
}, },
......
...@@ -19,7 +19,7 @@ RSpec.describe 'container repository details' do ...@@ -19,7 +19,7 @@ RSpec.describe 'container repository details' do
let(:user) { project.owner } let(:user) { project.owner }
let(:variables) { {} } let(:variables) { {} }
let(:tags) { %w(latest tag1 tag2 tag3 tag4 tag5) } let(:tags) { %w[latest tag1 tag2 tag3 tag4 tag5] }
let(:container_repository_global_id) { container_repository.to_global_id.to_s } let(:container_repository_global_id) { container_repository.to_global_id.to_s }
let(:container_repository_details_response) { graphql_data.dig('containerRepository') } let(:container_repository_details_response) { graphql_data.dig('containerRepository') }
...@@ -77,6 +77,37 @@ RSpec.describe 'container repository details' do ...@@ -77,6 +77,37 @@ RSpec.describe 'container repository details' do
end end
end end
context 'with a giant size tag' do
let(:tags) { %w[latest] }
let(:giant_size) { 1.terabyte }
let(:tag_sizes_response) { graphql_data_at('containerRepository', 'tags', 'nodes', 'totalSize') }
let(:fields) do
<<~GQL
tags {
nodes {
totalSize
}
}
GQL
end
let(:query) do
graphql_query_for(
'containerRepository',
{ id: container_repository_global_id },
fields
)
end
it 'returns the expected value as a string' do
stub_next_container_registry_tags_call(:total_size, giant_size)
subject
expect(tag_sizes_response.first).to eq(giant_size.to_s)
end
end
context 'limiting the number of tags' do context 'limiting the number of tags' do
let(:limit) { 2 } let(:limit) { 2 }
let(:tags_response) { container_repository_details_response.dig('tags', 'edges') } let(:tags_response) { container_repository_details_response.dig('tags', 'edges') }
...@@ -107,7 +138,7 @@ RSpec.describe 'container repository details' do ...@@ -107,7 +138,7 @@ RSpec.describe 'container repository details' do
end end
end end
context 'with tags without a manifest' do context 'with tags with a manifest containing nil fields' do
let(:tags_response) { container_repository_details_response.dig('tags', 'nodes') } let(:tags_response) { container_repository_details_response.dig('tags', 'nodes') }
let(:errors) { container_repository_details_response.dig('errors') } let(:errors) { container_repository_details_response.dig('errors') }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment