Hello Community,
Managing production deployments can be challenging when multiple teams and tools are involved. Our IT team relied on Excel sheets to track approved JIRA items for weekly bug fixes and monthly enhancements. This manual process was time-consuming and error-prone.
To simplify this, I developed an application using SAP RAP that automates the collection and management of JIRA items for deployment.
I built an application leveraging RAP draft functionality to manage deployment data efficiently.
Key Features:
I plan to enhance the application with:
Database Table
1. ZRELEASE_ITEMS - For main object
@EndUserText.label : 'Release Items'
@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zrelease_items {
key client : abap.clnt not null;
key id : abap.char(10) not null;
key defect : zdefectid not null;
description : abap.char(300);
projecttype : zproject_typ;
region : zregio;
releasetype : zreltype;
changetype : zchange_typ;
releasedate : abap.dats;
ffidused : abap.char(50);
jiraurl : abap.char(500);
createdon : abap.dats;
createdby : abp_creation_user;
isdeployed : abap_boolean;
}2. ZRELATTACH - For attachment
@EndUserText.label : 'Release Items Attachments'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zrelattach {
key client : abap.clnt not null;
key zrelid : abap.char(10) not null;
key zdefect : zdefectid not null;
key zid : uuid not null;
attachment : zrawstr;
mimetype : abap.char(128);
filename : abap.char(255);
crtby : abp_creation_user;
crton : abp_creation_date;
}ZREL_CHANGELOG - For Change History
@EndUserText.label : 'release item scenario: log changes to release entity'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zrel_changelog {
key client : abap.clnt not null;
key change_id : abap.raw(16) not null;
id : abap.char(10) not null;
changing_operation : abap.char(10);
changed_field_name : abap.char(32);
changed_from : abap.char(255);
changed_value : abap.char(255);
created_at : timestampl;
changed_by : abp_creation_user;
}
CDS - Basic View(Header)
@AbapCatalog.viewEnhancementCategory: [ #NONE ]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Basic View For Release Items'
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@ObjectModel.usageType: { serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED }
define root view entity ZI_RELEASE
as select from zrelease_items
composition [0..*] of ZI_ATTACH as _Attach
association [1] to ZI_PROJECT_FV as _ProjectText on $projection.Projecttype = _ProjectText.ProjType
association [1] to ZI_REGION_FV as _RegionText on $projection.Region = _RegionText.Staging
association [1] to ZI_RELTYP_FV as _ReleaseText on $projection.ReleaseType = _ReleaseText.RelType
association [1] to ZI_CHANGE_FV as _ChangeText on $projection.ChangeType = _ChangeText.ChangeTyp
association [0..*] to ZC_CHANGELOG as _ChangeLog on $projection.Id = _ChangeLog.Id
{
key id as Id,
key defect as Defect,
description as Description,
@ObjectModel.text.association: '_ProjectText'
projecttype as Projecttype,
@ObjectModel.text.association: '_RegionText'
region as Region,
@ObjectModel.text.association: '_ReleaseText'
releasetype as ReleaseType,
@ObjectModel.text.association: '_ChangeText'
changetype as ChangeType,
releasedate as ReleaseDate,
ffidused as FFID,
jiraurl as JiraUrl,
createdon as CreatedOn,
createdby as CreatedBy,
isdeployed as IsDeployed,
_Attach,
_ProjectText,
_RegionText,
_ReleaseText,
_ChangeText,
_ChangeLog
}CDS - Projection(Header)
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Consumption View For Release Item'
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@Search.searchable: true
@ObjectModel.semanticKey: [ 'Id','Defect' ]
define root view entity ZC_RELEASE provider contract transactional_query as projection on ZI_RELEASE
{
key Id,
@ObjectModel.sort.enabled: true
key Defect,
Description,
@ObjectModel.text.element: [ 'ProjectText' ]
Projecttype,
_ProjectText.Description as ProjectText,
@ObjectModel.text.element: [ 'RegionText' ]
Region,
_RegionText.Description as RegionText,
@ObjectModel.text.element: [ 'ReleaseText' ]
ReleaseType,
_ReleaseText.Description as ReleaseText,
@ObjectModel.text.element: [ 'ChangeText' ]
ChangeType,
_ChangeText.Description as ChangeText,
ReleaseDate,
FFID,
JiraUrl,
CreatedOn,
@Semantics.user.createdBy: true
CreatedBy,
IsDeployed,
_Attach : redirected to composition child ZC_ATTACH,
_ProjectText,
_RegionText,
_ReleaseText,
_ChangeText,
_ChangeLog
}CDS - Basic(Attachment)
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Basic View For Attachment'
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZI_ATTACH as select from zrelattach
association to parent ZI_RELEASE as _RELEASE on $projection.Zrelid = _RELEASE.Id and
$projection.Zdefect = _RELEASE.Defect
{
key zrelattach.zrelid as Zrelid,
key zrelattach.zdefect as Zdefect,
key zrelattach.zid as Zid,
zrelattach.attachment as Attachment,
zrelattach.mimetype as Mimetype,
zrelattach.filename as Filename,
zrelattach.crtby as Crtby,
zrelattach.crton as Crton,
_RELEASE
}CDS - Projection(Attachment)
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Consumption View For Attachment'
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define view entity ZC_ATTACH as projection on ZI_ATTACH
{
key Zrelid,
key Zdefect,
key Zid,
@Semantics.largeObject:{
fileName: 'Filename',
mimeType: 'Mimetype',
contentDispositionPreference: #INLINE
}
Attachment,
@Semantics.mimeType: true
Mimetype,
Filename,
@Semantics.user.createdBy: true
Crtby,
Crton,
/* Associations */
_RELEASE : redirected to parent ZC_RELEASE
}CDS - Basic view(Change History)
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Basic View For Change Log'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZI_CHANGELOG as select from zrel_changelog
{
key change_id as ChangeId,
id as Id,
changing_operation as ChangingOperation,
changed_field_name as ChangedFieldName,
changed_from as ChangedFrom,
changed_value as ChangedValue,
created_at as CreatedAt,
changed_by as ChangedBy
}CDS - Metadata extension(Header)
@Metadata.layer: #CORE
@Search.searchable: true
annotate view ZC_RELEASE with
{
@EndUserText.label: 'ID'
.defaultSearchElement: true
.fuzzinessThreshold: 0.7
.facet: [ //{ id: 'HeaderInfo', label: 'Header Info', type: #COLLECTION, targetQualifier: 'Header' },
{ id: 'GeneralInfo',
label: 'General',
targetQualifier: 'General',
type: #IDENTIFICATION_REFERENCE,
purpose: #STANDARD,
position: 10
//parentId: 'HeaderInfo'
},
{ id: 'Attach',
label: 'Attachments',
targetQualifier: 'Attach',
type: #LINEITEM_REFERENCE,
targetElement: '_Attach',
//parentId: 'HeaderInfo',
position: 20 },
{
id: 'ChangeLog',
label: 'Changes',
targetQualifier: 'ChangeLog',
type: #LINEITEM_REFERENCE,
targetElement: '_ChangeLog',
position: 30
} ]
.identification: [ { position: 10, qualifier: 'General' } ]
.lineItem: [ { position: 10, label: 'Mark As Deployed',type: #FOR_ACTION , dataAction: 'MrkDep' } ]
.selectionField: [ { position: 10 } ]
Id;
.defaultSearchElement: true
.fuzzinessThreshold: 0.7
.identification: [ { position: 20, qualifier: 'General' } ]
.lineItem: [ { position: 20, label: 'Defect' } ]
.selectionField: [ { position: 20 } ]
Defect;
@EndUserText.label: 'Description'
.defaultSearchElement: true
.fuzzinessThreshold: 0.7
.identification: [ { position: 30, qualifier: 'General' } ]
.lineItem: [ { position: 30, label: 'Description' } ]
Description;
@Consumption.valueHelpDefinition: [ { entity: { element: 'Staging', name: 'ZI_REGION_FV' } } ]
@Consumption.filter.selectionType: #SINGLE
@EndUserText.label: 'Region'
.identification: [ { position: 40, qualifier: 'General' } ]
.lineItem: [ { position: 40, label: 'Region' } ]
.selectionField: [ { position: 30 } ]
.textArrangement: #TEXT_ONLY
Region;
@Consumption.valueHelpDefinition: [ { entity: { element: 'ProjType', name: 'ZI_PROJECT_FV' } } ]
.textArrangement: #TEXT_ONLY
@Consumption.filter.selectionType: #SINGLE
.identification: [ { position: 50, qualifier: 'General' } ]
.lineItem: [ { position: 50, label: 'Project Type' } ]
.selectionField: [ { position: 40 } ]
Projecttype;
@Consumption.valueHelpDefinition: [ { entity: { element: 'RelType', name: 'ZI_RELTYP_FV' } } ]
@Consumption.filter.selectionType: #SINGLE
.textArrangement: #TEXT_ONLY
.identification: [ { position: 60, qualifier: 'General' } ]
.lineItem: [ { position: 60, label: 'Release Type' } ]
.selectionField: [ { position: 50 } ]
ReleaseType;
@Consumption.valueHelpDefinition: [ { entity: { element: 'ChangeTyp', name: 'ZI_CHANGE_FV' } } ]
@Consumption.filter.selectionType: #SINGLE
.textArrangement: #TEXT_ONLY
.identification: [ { position: 70, qualifier: 'General' } ]
.lineItem: [ { position: 70, label: 'Change Type' } ]
.selectionField: [ { position: 60 } ]
ChangeType;
@EndUserText.label: 'FF ID'
.identification: [ { position: 80, qualifier: 'General' } ]
.lineItem: [ { position: 100, label: 'FF ID' } ]
FFID;
@EndUserText.label: 'JIRA Link'
.identification: [ { position: 100, qualifier: 'General' } ]
JiraUrl;
@EndUserText.label: 'Release Date'
.identification: [ { position: 90, qualifier: 'General' } ]
.lineItem: [ { position: 100, label: 'Release Date' } ]
.selectionField: [ { position: 70 } ]
@Consumption.filter.selectionType: #SINGLE
ReleaseDate;
@EndUserText.label: 'Created On'
.identification: [ { position: 110, qualifier: 'General' } ]
.selectionField: [ { position: 80 } ]
@Consumption.filter.selectionType: #SINGLE
CreatedOn;
@EndUserText.label: 'Created By'
.identification: [{ position: 120, qualifier: 'General' }]
.selectionField: [ { position: 90 } ]
CreatedBy;
@EndUserText.label: 'IsDeployed'
.identification: [{ position: 130, qualifier: 'General' }]
.lineItem: [{ position: 130, label: 'IsDeployed',emphasized: true }]
.selectionField: [ { position: 100 } ]
IsDeployed;
}CDS - Metadata extension(Attachment)
@Metadata.layer: #CORE
annotate entity ZC_ATTACH
with
{
.hidden: true
Zrelid;
.hidden: true
Zdefect;
.hidden: true
Zid;
.textArrangement: #TEXT_FIRST
.lineItem: [{ position: 10,label: 'Attachment' ,qualifier: 'Attach'}]
.identification: [{position: 10}]
Attachment;
.hidden: true
Mimetype;
.textArrangement: #TEXT_FIRST
.lineItem: [{ position: 20,label: 'Description' , qualifier: 'Attach'}]
.identification: [{position: 20}]
Filename;
.lineItem: [{ position: 30,label: 'CreatedBy' ,qualifier: 'Attach'}]
.identification: [{position: 30}]
Crtby;
.lineItem: [{ position: 40,label: 'CreatedOn' ,qualifier: 'Attach'}]
.identification: [{position: 40}]
Crton;
/* Associations */
//_RELEASE;
}CDS - Metadata Extension(Change History)
@Metadata.layer: #CORE
annotate entity ZC_CHANGELOG
with
{
.hidden: true
ChangeId;
.hidden: true
Id;
.lineItem: [{ position: 10,label: 'Operation',qualifier: 'ChangeLog' }]
ChangingOperation;
.lineItem: [{ position: 20,label: 'Field' , qualifier: 'ChangeLog'}]
ChangedFieldName;
.lineItem: [{ position: 30,label: 'Old Value' , qualifier: 'ChangeLog'}]
ChangedFrom;
.lineItem: [{ position: 40,label: 'New Value' ,qualifier: 'ChangeLog'}]
ChangedValue;
.hidden: true
CreatedAt;
.lineItem: [{ position: 60,label: 'Change By' ,qualifier: 'ChangeLog'}]
ChangedBy;
}Service Definition
@EndUserText.label: 'Service definition for release item'
define service ZSD_RELEASE {
expose ZC_RELEASE;
expose ZC_ATTACH;
expose ZC_CHANGELOG;
}Service Binding
Number Range
Behavior Definition
managed implementation in class zbp_i_release unique;
strict ( 2 );
with draft;
define behavior for ZI_RELEASE //alias <alias_name>
persistent table zrelease_items
draft table ZDRAFT_RELEASE
lock master
authorization master ( instance,global )
late numbering
etag master CreatedOn
{
create ( authorization : global );
update(features : instance);
delete(features : instance);
field ( readonly ) Id;
field ( readonly : update) Defect;
field ( mandatory : create ) Defect; // ChangeType,Description,Region,Projecttype,ffid,ReleaseDate,ReleaseType;
field ( features : instance ) ChangeType,Description,Region,Projecttype,ffid,ReleaseDate,ReleaseType,IsDeployed;
association _Attach {create;with draft;}
action ( features : instance ) MrkDep;
draft action Edit;
draft action Resume;
draft action Activate optimized;
draft action Discard;
draft determine action Prepare
{
validation ValidateDD;
}
validation ValidateDD on save {create;update;}
side effects
{
field Defect affects field JiraUrl;
}
determination BuildURL on modify { field Defect; }
mapping for zrelease_items {
Id = id;
Defect = defect;
ffid = ffidused;
ChangeType = changetype;
Description = description;
JiraUrl = jiraurl;
Projecttype = projecttype;
Region = region;
ReleaseDate = releasedate;
ReleaseType = releasetype;
CreatedOn = createdon;
CreatedBy = createdby;
IsDeployed = isdeployed;
}
}
define behavior for ZI_ATTACH
implementation in class zimpl_attach unique
persistent table zrelattach
draft table zdraft_attach
lock dependent by _RELEASE
authorization dependent by _RELEASE
late numbering
etag dependent by _RELEASE
{
update;
delete;
field ( readonly:update ) Zdefect,Zrelid,Zid;
association _RELEASE {with draft;}
mapping for zrelattach{
Zrelid = zrelid;
Zdefect = zdefect;
Zid = zid;
Filename = filename;
Attachment = attachment;
Crtby = crtby;
Crton = crton;
Mimetype = mimetype;
}
}Behavior Implementation
1. Number Assignment
LOOP AT mapped-zi_release REFERENCE INTO DATA(map).
IF map->Id IS NOT INITIAL.
CONTINUE.
ENDIF.
TRY.
cl_numberrange_runtime=>number_get( EXPORTING object = 'ZRELEASEID'
nr_range_nr = '01'
IMPORTING number = DATA(lv_id) ).
CATCH cx_nr_object_not_found.
CATCH cx_number_ranges.
ENDTRY.
map->Id = |{ lv_id ALPHA = OUT }|.
map->Defect = map->%tmp-Defect.
ENDLOOP.2. URL generation,
READ ENTITIES OF zi_release IN LOCAL MODE
ENTITY zi_release ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_results).
LOOP AT lt_results ASSIGNING FIELD-SYMBOL(<ls_result>).
IF <ls_result>-JiraUrl IS INITIAL.
<ls_result>-JiraUrl = |https://Jira.company.com/browse/{ <ls_result>-Defect }|.
ENDIF.
IF <ls_result>-CreatedOn IS INITIAL.
<ls_result>-CreatedOn = cl_abap_context_info=>get_system_date( ).
ENDIF.
IF <ls_result>-CreatedBy IS INITIAL.
TRY.
<ls_result>-CreatedBy = cl_abap_context_info=>get_user_technical_name( ).
CATCH cx_abap_context_info_error.
ENDTRY.
ENDIF.
ENDLOOP.
MODIFY ENTITIES OF zi_release IN LOCAL MODE
ENTITY zi_release
UPDATE FIELDS ( JiraUrl CreatedOn CreatedBy )
WITH CORRESPONDING #( lt_results ).
ENDMETHOD.
assignment of created on/created by
Video Snip
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 34 | |
| 25 | |
| 17 | |
| 16 | |
| 16 | |
| 15 | |
| 13 | |
| 13 | |
| 13 | |
| 12 |