Skip to content
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

Implement Sync Beta Group Commands #147

Closed
wants to merge 21 commits into from
Closed

Conversation

DechengMa
Copy link
Contributor

@DechengMa DechengMa commented May 18, 2020

Implement basic sync beta group command.

  • Delete local group files -> request to remove groups in server
  • Create local group files -> request create groups in server
  • After create -> pull back and sync local
  • Edit local group files -> update server groups
  • Wrap up and restructure codes
  • Apply new file system on it
  • Refactor file structure and remove duplicate data

📝 Summary of Changes

Changes proposed in this pull request:

  • Add let id: String? field to Beta Group model. I know we don't want to do this but it's a must coz two groups can have the same name.
  • Add var testers: [String] to Beta Group for storing tester emails
  • Make BetaGroup extend to Equatable, Hashable for comparing in Set, to SyncResultRenderable for rendering dry run and sync result, to FileNameGettable for generating a beatified filename (a String extension was made for snakeCased filename).
  • Create SyncResultRenderer for printing sync and dry run result
  • Create enum SyncStrategy for both rendering result and handle the update.
  • Create protocol ResourceFolderManagerand BetaGroupFolderManager, for managing folders and group files.
  • Tweak ListBetaTestersOperation and create UpdateBetaGroupOperation. Create service function pullBetaGroups, updateBetaGroup, deleteBetaGroup.
  • Implement SyncBetaGroupsCommand which contains PullBetaGroupsCommand and PushBetaGroupsCommand.

⚠️ Items of Note

  • When edit file to change group, only particular field are editable: for a beta group, only name, public link, link limit, link enabled can be changed (according to API), and if others are changed, when push it will have no effect. So this means the user must have some instructions.

🧐🗒 Reviewer Notes

💁 Example

Usage:

asc testflight betagroup sync pull [--output-path <output-path>]
asc testflight betagroup sync push [--input-path <input-path>] [--dry-run]

--output-path and --input-path is a folder path.

CLI will go through all the files in that folder and find file with a suffix of yml and read it as a beta group file.

Sample Output:

TODO

Sample file structure

TODO

🔨 How To Test

asc testflight betagroup sync pull

asc testflight betagroup sync push --dry-run

asc testflight betagroup sync push

How to

Note: Please run pull first to get server groups and testers before run push

Create a new group via sync:

  1. Create a file, name it whatever you like in folder ./config/betagroups(or the input folder path), suffix must be yml
  2. Put some basic group info in it, eg
app:
  bundleId: com.example.foo // MUST HAVE
groupName: testgroup // MUST HAVE, MUST UNIQUE (please don't create group with the same name in same app)
publicLinkEnabled: false
publicLinkLimit: 5
publicLinkLimitEnabled: false
  1. Run command asc testflight betagroup sync push

Delete a group

  1. Delete the group file in folder
  2. Run command asc testflight betagroup sync push

Update a group

  1. Directly edit the group file in the config folder
    fields that support editing: (edit other fields will not work)
groupName
publicLinkEnabled
publicLinkLimit
publicLinkLimitEnabled
  1. Run command asc testflight betagroup sync push

@DechengMa DechengMa added the enhancement New feature or request label May 18, 2020
@DechengMa DechengMa self-assigned this May 18, 2020
@DechengMa DechengMa changed the title Testflight/Sync/ Implement PullBetaGroupsCommand Implement Sync Beta Group Commands May 19, 2020
@DechengMa DechengMa force-pushed the testflight/sync-betagroup branch from 8e881e4 to e822f13 Compare May 20, 2020 08:06
@DechengMa DechengMa marked this pull request as ready for review May 20, 2020 23:54
Copy link
Contributor

@adamjcampbell adamjcampbell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some preliminary suggestions and thoughts
Looking pretty good! This may go through some designing though

Sources/AppStoreConnectCLI/Helpers/String+Helpers.swift Outdated Show resolved Hide resolved
Sources/AppStoreConnectCLI/Model/App.swift Outdated Show resolved Hide resolved
@@ -5,7 +5,8 @@ import Combine
import Foundation
import SwiftyTextTable

struct BetaGroup: TableInfoProvider, ResultRenderable, Equatable {
struct BetaGroup: TableInfoProvider, ResultRenderable {
let id: String?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same goes for BetaGroup

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An optional id is for creating a beta group. When creating a new group we don't have the id yet. we can basically create a file with just minimal information (eg. group name, link enabled, etc) and push back

@@ -14,6 +15,7 @@ struct BetaGroup: TableInfoProvider, ResultRenderable, Equatable {
let publicLinkLimit: Int?
let publicLinkLimitEnabled: Bool?
let creationDate: String?
var testers: String? // CSV file path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where things can get interesting.. Having variables that will populated when pulled from disk but not populated when retrieved from the network

Comment on lines 70 to 94
static func == (lhs: BetaGroup, rhs: BetaGroup) -> Bool {
return lhs.id == rhs.id &&
lhs.groupName == rhs.groupName &&
lhs.publicLinkEnabled == rhs.publicLinkEnabled &&
lhs.publicLinkLimit == rhs.publicLinkLimit &&
lhs.publicLinkLimitEnabled == rhs.publicLinkLimitEnabled
}

func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(groupName)
hasher.combine(publicLinkEnabled)
hasher.combine(publicLinkLimit)
hasher.combine(publicLinkLimitEnabled)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could potentially only use the id for matching.. do we ever foresee having duplicates?

Did you have to override the default implementations because of the testers file path? There may also be a different solution here 🤔

Copy link
Contributor Author

@DechengMa DechengMa May 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very true. for now, this is only for comparing the BetaGroup object difference, not for testers. when doing something like Set(localGroups).subtracting(serverGroups) I can get the difference and update the server by local

Sources/AppStoreConnectCLI/Model/BetaGroup.swift Outdated Show resolved Hide resolved
@DechengMa DechengMa force-pushed the testflight/sync-betagroup branch from e822f13 to 986827a Compare May 22, 2020 01:31
@DechengMa DechengMa requested a review from adamjcampbell May 25, 2020 23:38
@DechengMa DechengMa marked this pull request as draft June 11, 2020 07:44
@DechengMa DechengMa force-pushed the testflight/sync-betagroup branch from 986827a to fe92a6c Compare June 12, 2020 04:23
@DechengMa DechengMa marked this pull request as ready for review June 12, 2020 04:38
@DechengMa DechengMa dismissed adamjcampbell’s stale review June 19, 2020 03:25

Changes were made upon request

@orj
Copy link
Member

orj commented Jun 22, 2020

@DechengMa sorry I've not reviewed this. I'd like to try building a workflow based on this work to test it out.

@DechengMa
Copy link
Contributor Author

@DechengMa sorry I've not reviewed this. I'd like to try building a workflow based on this work to test it out.

Sure no problem. Please PM directly if there's anything that I can do to help. And I'll be around for fixing any bugs / unexpected behaviours in the first place.


extension BetaGroup: FileProvider {
var fileName: String {
"\(app.bundleId ?? "")_\(groupName).yml"
Copy link
Member

@orj orj Jun 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be normalising the filename a bit better here. groupName could be an unsafe filename. We should turn all non alpha numeric characters into underscores.

extension String {
  func filenameSafe() -> String {
    let unsafeFilenameCharacters = CharacterSet(charactersIn: " *?:/\\.")
    return str.components(separatedBy: unsafeFilenameCharacters).joined(separator: "_")
  }
}

I'm working with an app that has a beta group named "a/h_Security" so this code creates a subdirectory named "bundleId_a" with a file in it called "h_Security.yml"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an account that has a lot of groups it would be better to nest them in subdirectories. The app.bundleId could be a subdirectory rather than a prefix.

Also, surely the app.bundleId will be non-nil? When will it ever be nil?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually thinking about he normalised/safe filename some more I think when group names are translated to file/path names they should be really cleaned up:

Eg: A group name like d_App Team (Learn & Adopt) should be translated to d-app-team-learn-adopt. The problem with that however is that removing characters might mean there could be clashes. We might have to come up with some resolution strategy in that case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm trying to suggest here is that the filenames should be names that a developer might choose if they were authoring them themselves.

Copy link
Member

@orj orj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good work @DechengMa but I think we need to refine it a bit.

The current pulled structure is very flat and includes redundant data. I think we should change the structure so it is like this:

  • config/betagroups/
    • com.example.appid/
      • safe-group-name/
        • betagroup.yml
        • betatesters.csv

@orj
Copy link
Member

orj commented Jun 24, 2020

Something else I'd like us to clean up here is the duplication of information. When we pull down the details of the beta group the app element is repeated in each betagroup file. This isn't ideal. It would be better if it was not repeated.

@DechengMa DechengMa force-pushed the testflight/sync-betagroup branch from 46aa03a to 0e381c0 Compare July 1, 2020 00:10
@DechengMa DechengMa marked this pull request as draft July 2, 2020 04:23
@DechengMa DechengMa closed this Jul 10, 2020
@DechengMa
Copy link
Contributor Author

a new redesigned sync command will be implemented in #203

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants