Skip to content

Added tempalted profile support #191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions autocodesign/autocodesign.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ type DevPortalClient interface {

FindProfile(name string, profileType appstoreconnect.ProfileType) (Profile, error)
DeleteProfile(id string) error
CreateProfile(name string, profileType appstoreconnect.ProfileType, bundleID appstoreconnect.BundleID, certificateIDs []string, deviceIDs []string) (Profile, error)
CreateProfile(name string, profileType appstoreconnect.ProfileType, bundleID appstoreconnect.BundleID, certificateIDs []string, deviceIDs []string, templateName string) (Profile, error)

FindBundleID(bundleIDIdentifier string) (*appstoreconnect.BundleID, error)
CheckBundleIDEntitlements(bundleID appstoreconnect.BundleID, appEntitlements Entitlements) error
Expand Down Expand Up @@ -131,6 +131,7 @@ type CodesignAssetsOpts struct {
BitriseTestDevices []devportalservice.TestDevice
MinProfileValidityDays int
FallbackToLocalAssetsOnAPIFailure bool
ProfileTemplateName map[DistributionType]string
VerboseLog bool
}

Expand Down Expand Up @@ -206,7 +207,7 @@ func (m codesignAssetManager) EnsureCodesignAssets(appLayout AppLayout, opts Cod
printMissingCodeSignAssets(missingAppLayout)

// Ensure Profiles
newCodesignAssets, err := ensureProfiles(m.devPortalClient, distrType, certsByType, *missingAppLayout, devPortalDeviceIDs, opts.MinProfileValidityDays)
newCodesignAssets, err := ensureProfiles(m.devPortalClient, distrType, certsByType, *missingAppLayout, devPortalDeviceIDs, opts.MinProfileValidityDays, opts.ProfileTemplateName)
if err != nil {
switch {
case errors.As(err, &ErrAppClipAppID{}):
Expand Down Expand Up @@ -238,3 +239,18 @@ func (m codesignAssetManager) EnsureCodesignAssets(appLayout AppLayout, opts Cod

return codesignAssetsByDistributionType, nil
}

// ListProfileAttachedEntitlements ...
func (layout AppLayout) ListProfileAttachedEntitlements() map[string][]string {
bundleIDToTemplatedEntitlements := make(map[string][]string)

for bundleID, entitlements := range layout.EntitlementsByArchivableTargetBundleID {
for entitlementKey, value := range entitlements {
if (Entitlement{entitlementKey: value}).IsProfileAttached() {
bundleIDToTemplatedEntitlements[bundleID] = append(bundleIDToTemplatedEntitlements[bundleID], entitlementKey)
}
}
}

return bundleIDToTemplatedEntitlements
}
71 changes: 68 additions & 3 deletions autocodesign/autocodesign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func Test_codesignAssetManager_EnsureCodesignAssets(t *testing.T) {
})
devportalWithNoAppID.On("CreateBundleID", "io.test", "Bitrise io test").Return(createdAppID, nil).
On("SyncBundleID", *createdAppID, mock.Anything).Return(nil).
On("CreateProfile", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
On("CreateProfile", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "").
Return(newMockProfile(profileArgs{}), nil)

appIDAndProfileFoundAppLayout := AppLayout{
Expand Down Expand Up @@ -398,11 +398,11 @@ func Test_GivenProfileExpired_WhenProfilesInconsistent_ThenItRetries(t *testing.
// FindProfile
client.On("DeleteProfile", expiredProfile.ID()).Return(nil).Once()
client.On("CheckBundleIDEntitlements", mock.Anything, mock.Anything).Return(nil).Once()
client.On("CreateProfile", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, ProfilesInconsistentError{}).Once()
client.On("CreateProfile", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "").Return(nil, ProfilesInconsistentError{}).Once()
// FindProfile
client.On("DeleteProfile", expiredProfile.ID()).Return(nil).Once()
client.On("CheckBundleIDEntitlements", mock.Anything, mock.Anything).Return(nil).Once()
client.On("CreateProfile", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(validProfile, nil).Once()
client.On("CreateProfile", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "").Return(validProfile, nil).Once()

assetWriter := newDefaultMockAssetWriter()
appLayout := AppLayout{
Expand Down Expand Up @@ -552,3 +552,68 @@ func newClientWithAppIDWithoutAppleSignIn(cert certificateutil.CertificateInfoMo

return client
}

func TestAppLayout_ListProfileAttachedEntitlements(t *testing.T) {
tests := []struct {
name string
entitlementsByBundleID map[string]Entitlements
want map[string][]string
}{
{
name: "no entitlements",
entitlementsByBundleID: map[string]Entitlements{
"com.bundleid": map[string]interface{}{},
},
want: map[string][]string{},
},
{
name: "all entitlements supported",
entitlementsByBundleID: map[string]Entitlements{
"com.bundleid": map[string]interface{}{
"aps-environment": true,
},
},
want: map[string][]string{},
},
{
name: "contains unsupported entitlement",
entitlementsByBundleID: map[string]Entitlements{
"com.bundleid": map[string]interface{}{
"com.entitlement-ignored": true,
"com.apple.developer.contacts.notes": true,
},
},
want: map[string][]string{
"com.bundleid": {"com.apple.developer.contacts.notes"},
},
},
{
name: "contains unsupported entitlement, multiple bundle IDs",
entitlementsByBundleID: map[string]Entitlements{
"com.bundleid": map[string]interface{}{
"aps-environment": true,
"com.apple.developer.carplay-maps": true,
},
"com.bundleid2": map[string]interface{}{
"com.entitlement-ignored": true,
"com.apple.developer.contacts.notes": true,
},
},
want: map[string][]string{
"com.bundleid": {"com.apple.developer.carplay-maps"},
"com.bundleid2": {"com.apple.developer.contacts.notes"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
app := AppLayout{
EntitlementsByArchivableTargetBundleID: tt.entitlementsByBundleID,
}

got := app.ListProfileAttachedEntitlements()

require.Equal(t, tt.want, got)
})
}
}
12 changes: 7 additions & 5 deletions autocodesign/devportalclient/appstoreconnect/profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,9 @@ func (s ProvisioningService) ListProfiles(opt *ListProfilesOptions) (*ProfilesRe

// ProfileCreateRequestDataAttributes ...
type ProfileCreateRequestDataAttributes struct {
Name string `json:"name"`
ProfileType ProfileType `json:"profileType"`
Name string `json:"name"`
ProfileType ProfileType `json:"profileType"`
TemplateType string `json:"templateName,omitempty"`
}

// ProfileCreateRequestDataRelationshipData ...
Expand Down Expand Up @@ -201,7 +202,7 @@ type ProfileCreateRequest struct {
}

// NewProfileCreateRequest returns a ProfileCreateRequest structure
func NewProfileCreateRequest(profileType ProfileType, name, bundleIDID string, certificateIDs []string, deviceIDs []string) ProfileCreateRequest {
func NewProfileCreateRequest(profileType ProfileType, name, bundleIDID string, certificateIDs []string, deviceIDs []string, templateName string) ProfileCreateRequest {
bundleIDData := ProfileCreateRequestDataRelationshipData{
ID: bundleIDID,
Type: "bundleIds",
Expand Down Expand Up @@ -233,8 +234,9 @@ func NewProfileCreateRequest(profileType ProfileType, name, bundleIDID string, c

data := ProfileCreateRequestData{
Attributes: ProfileCreateRequestDataAttributes{
Name: name,
ProfileType: profileType,
Name: name,
ProfileType: profileType,
TemplateType: templateName,
},
Relationships: relationships,
Type: "profiles",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ func (c *ProfileClient) DeleteProfile(id string) error {
}

// CreateProfile ...
func (c *ProfileClient) CreateProfile(name string, profileType appstoreconnect.ProfileType, bundleID appstoreconnect.BundleID, certificateIDs []string, deviceIDs []string) (autocodesign.Profile, error) {
profile, err := c.createProfile(name, profileType, bundleID, certificateIDs, deviceIDs)
func (c *ProfileClient) CreateProfile(name string, profileType appstoreconnect.ProfileType, bundleID appstoreconnect.BundleID, certificateIDs []string, deviceIDs []string, templateName string) (autocodesign.Profile, error) {
profile, err := c.createProfile(name, profileType, bundleID, certificateIDs, deviceIDs, templateName)
if err != nil {
// Expired profiles are not listed via profiles endpoint,
// so we can not catch if the profile already exist but expired, before we attempt to create one with the managed profile name.
Expand All @@ -171,7 +171,7 @@ func (c *ProfileClient) CreateProfile(name string, profileType appstoreconnect.P
return nil, fmt.Errorf("expired profile cleanup failed: %s", err)
}

profile, err = c.createProfile(name, profileType, bundleID, certificateIDs, deviceIDs)
profile, err = c.createProfile(name, profileType, bundleID, certificateIDs, deviceIDs, templateName)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -218,7 +218,7 @@ func (c *ProfileClient) deleteExpiredProfile(bundleID *appstoreconnect.BundleID,
return c.DeleteProfile(profile.ID)
}

func (c *ProfileClient) createProfile(name string, profileType appstoreconnect.ProfileType, bundleID appstoreconnect.BundleID, certificateIDs []string, deviceIDs []string) (autocodesign.Profile, error) {
func (c *ProfileClient) createProfile(name string, profileType appstoreconnect.ProfileType, bundleID appstoreconnect.BundleID, certificateIDs []string, deviceIDs []string, templateName string) (autocodesign.Profile, error) {
// Create new Bitrise profile on App Store Connect
r, err := c.client.Provisioning.CreateProfile(
appstoreconnect.NewProfileCreateRequest(
Expand All @@ -227,6 +227,7 @@ func (c *ProfileClient) createProfile(name string, profileType appstoreconnect.P
bundleID.ID,
certificateIDs,
deviceIDs,
templateName,
),
)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func TestEnsureProfile_ExpiredProfile(t *testing.T) {
},
}

profile, err := profileClient.CreateProfile("Bitrise iOS development - (io.bitrise.testapp)", appstoreconnect.IOSAppDevelopment, bundleID, []string{}, []string{})
profile, err := profileClient.CreateProfile("Bitrise iOS development - (io.bitrise.testapp)", appstoreconnect.IOSAppDevelopment, bundleID, []string{}, []string{}, "")

// Assert
require.NoError(t, err)
Expand Down
6 changes: 5 additions & 1 deletion autocodesign/devportalclient/spaceship/profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,11 @@ func (c *ProfileClient) DeleteProfile(id string) error {
}

// CreateProfile ...
func (c *ProfileClient) CreateProfile(name string, profileType appstoreconnect.ProfileType, bundleID appstoreconnect.BundleID, certificateIDs []string, deviceIDs []string) (autocodesign.Profile, error) {
func (c *ProfileClient) CreateProfile(name string, profileType appstoreconnect.ProfileType, bundleID appstoreconnect.BundleID, certificateIDs []string, deviceIDs []string, templateName string) (autocodesign.Profile, error) {
if templateName != "" {
return nil, fmt.Errorf("profile template name not supported with spaceship client")
}

log.Debugf("Creating provisioning profile with name: %s", name)

cmd, err := c.client.createRequestCommand("create_profile",
Expand Down
63 changes: 31 additions & 32 deletions autocodesign/mock_DevPortalClient.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading