Skip to content

Commit 5d81a6f

Browse files
greg-1-andersonRyan Aslett
authored andcommitted
Merged in one-tag-at-a-time (pull request #1)
Process one tag at a time.
2 parents e6aae03 + 3271eff commit 5d81a6f

File tree

5 files changed

+124
-57
lines changed

5 files changed

+124
-57
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
# Ignore the configuration file
22
subtree-split.config
3+
config.yml
4+
config_secrets.yml
35

4-
# Ignore the upstream repository
6+
# Ignore the upstream repository caches
57
upstream
68
upstream-current
9+
upstream-split-source
710

811
# Composer
912
vendor

config.yml renamed to config.yml.dist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Copy this file to `config.yml` and customize to suit.
2+
13
# This is the upstream project that we plan to split
24
project_to_split: drupal
35
# Github User

config_secrets.yml.dist

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copy this file to `config_secrets.yml` and customize to suit.
2+
3+
github_api_token: 12345...
4+
packagist_api_token: 12345...

src/AppConfig.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ protected function configure() {
1717

1818
$this->beginCommand('split')
1919
->addArgument('branch', Argument::REQUIRED)
20-
->addArgument('config', Argument::REQUIRED)
20+
->addArgument('config', Argument::OPTIONAL)
2121
->setHandler(new SplitCommand());
2222
}
2323

src/SplitCommand.php

Lines changed: 113 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,29 @@ class SplitCommand {
2929
public function handle(Args $args, IO $io) {
3030
$yaml = new Yaml();
3131

32-
$configfile = $args->getArgument('config');
32+
$configfile = $this->getConfigFilePath($args);
33+
3334
$config_secrets = str_replace(".yml", "_secrets.yml", $configfile);
3435
if ($content = file_get_contents($configfile)) {
3536
$config = $yaml->parse($content);
3637
}
3738
if ($content = file_get_contents($config_secrets)) {
3839
$config = array_merge($config, $yaml->parse($content));
3940
}
41+
4042
$this->github_username = $config['github_username'];
4143
$this->github_orgname = $config['github_orgname'];
4244
$this->github_teamid = $config['github_teamid'];
4345
$this->project = $config['project_to_split'];
4446

47+
$this->alterPath();
48+
4549
$this->upstream = "https://git.drupalcode.org/project/{$this->project}.git";
4650

4751

48-
$packagist_api_client = new GuzzleClient(['base_uri' => 'https://packagist.org/api/']);
4952
$directory = 'upstream-current';
5053

5154
$github_apikey = $config['github_api_token'];
52-
$packagist_apitoken = $config['packagist_api_token'];
5355

5456
// Update/checkout local repository.
5557
$this->updateRepository($directory, $args->getArgument('branch'));
@@ -59,6 +61,10 @@ public function handle(Args $args, IO $io) {
5961
// That contains a composer.json is a split candidate.
6062
//
6163
$subtrees = $this->getSubtrees($directory);
64+
65+
// Make sure all 'core-' subtrees are ordered first.
66+
uksort($subtrees, [$this, 'comparePackageNames']);
67+
6268
// For each subtree,
6369
// 1. determine if a github repo exists for it
6470
// 2. if not, create a github repo
@@ -75,68 +81,90 @@ public function handle(Args $args, IO $io) {
7581
$paginator = new ResultPager($client);
7682
$parameters = array($this->github_orgname);
7783
$repositories = $paginator->fetchAll($userApi, 'repositories', $parameters);
84+
$reponames = [];
7885
foreach ($repositories as $repo) {
7986
$reponames[] = $repo['name'];
8087
}
81-
$packagist_client = new PackagistClient();
8288
foreach ($subtrees as $subtree_name => $subtree_data) {
89+
$io->writeLine("-----------------------------------------------------");
8390
$io->writeLine("Processing ${subtree_name}");
8491
if (!in_array($subtree_name, $reponames)) {
8592
$io->writeLine("Creating ${subtree_name}");
8693
$client->api('repo')
8794
->create($subtree_name, $subtree_data['description'], "http://drupal.org/project/{$this->project}", TRUE, $this->github_orgname, FALSE, FALSE, TRUE, $this->github_teamid, FALSE);
8895
}
89-
// Update branch.
90-
$this->splitBranch($directory, $args->getArgument('branch'), $github_apikey, $subtree_data['path'], $subtree_name);
91-
// Update tags.
92-
exec('git ls-remote --tags ' . $this->upstream, $upstream_tags);
93-
exec("git ls-remote --tags https://{$this->github_username}:{$github_apikey}@github.com/{$this->github_orgname}/{$subtree_name}.git", $downstream_tags);
94-
95-
$upstream_tags = Utility::filterValidTags($upstream_tags, $args->getArgument('branch'));
96-
$downstream_tags = Utility::filterValidTags($downstream_tags, $args->getArgument('branch'));
97-
98-
// Tags which are not in the downstream repo.
99-
$tags = array_diff($upstream_tags, $downstream_tags);
100-
$walkdata = [
101-
'directory' => $directory,
102-
'name' => $subtree_name,
103-
'path' => $subtree_data['path'],
104-
'key' => $github_apikey,
105-
];
106-
array_walk($tags, function ($tag) use ($walkdata,$github_apikey) {
107-
$this->splitTag($walkdata['directory'], $tag, $walkdata['key'], $walkdata['path'], $walkdata['name']);
108-
});
109-
110-
// Check if package exists:
111-
$packagename = 'drupal/' . $subtree_name;
112-
$body = '{"repository":{"url":"[email protected]:' . $this->github_orgname . '/' . $subtree_name . '.git"}}';
113-
try {
114-
$packagist_client->get($packagename);
115-
$endpoint = 'update-package';
116-
}
117-
catch (Exception $e) {
118-
// Package doesnt exist at packagist: needs to be created.
119-
$endpoint = 'create-package';
120-
}
121-
122-
try {
123-
$packagist_api_client->request('POST', $endpoint, [
124-
'body' => $body,
125-
'headers' => ['Content-Type' => 'application/json'],
126-
'query' => [
127-
'username' => "$this->github_username",
128-
'apiToken' => $packagist_apitoken,
129-
],
130-
]);
96+
$ref = $args->getArgument('branch');
97+
if (preg_match('#\.x$#', $ref)) {
98+
$io->writeLine("Update branch $ref");
99+
// Update branch.
100+
$this->splitBranch($directory, $ref, $github_apikey, $subtree_data['path'], $subtree_name);
131101
}
132-
catch (GuzzleException $e) {
133-
// There. handled.
102+
else {
103+
$io->writeLine("Update tag $ref");
104+
// Update tag.
105+
$this->splitTag($directory, $ref, $github_apikey, $subtree_data['path'], $subtree_name);
134106
}
135107

108+
$this->updatePackagist($config, $subtree_name);
136109
}
137110
passthru("rm -rf {$directory}");
138111
}
139112

113+
protected function updatePackagist($config, $subtree_name) {
114+
if (!isset($config['packagist_api_token'])) {
115+
return;
116+
}
117+
118+
$packagist_client = new PackagistClient();
119+
$packagist_apitoken = $config['packagist_api_token'];
120+
121+
// Check if package exists:
122+
$packagename = 'drupal/' . $subtree_name;
123+
$body = '{"repository":{"url":"[email protected]:' . $this->github_orgname . '/' . $subtree_name . '.git"}}';
124+
try {
125+
$packagist_client->get($packagename);
126+
$endpoint = 'update-package';
127+
}
128+
catch (Exception $e) {
129+
// Package doesnt exist at packagist: needs to be created.
130+
$endpoint = 'create-package';
131+
}
132+
133+
$packagist_api_client = new GuzzleClient(['base_uri' => 'https://packagist.org/api/']);
134+
135+
try {
136+
$packagist_api_client->request('POST', $endpoint, [
137+
'body' => $body,
138+
'headers' => ['Content-Type' => 'application/json'],
139+
'query' => [
140+
'username' => "$this->github_username",
141+
'apiToken' => $packagist_apitoken,
142+
],
143+
]);
144+
}
145+
catch (GuzzleException $e) {
146+
// There. handled.
147+
}
148+
}
149+
150+
protected function getConfigFilePath($args) {
151+
return $args->getArgument('config')
152+
?? $this->checkFileExists('config.yml')
153+
?? 'config.yml.dist';
154+
}
155+
156+
protected function checkFileExists($path) {
157+
return file_exists($path) ? $path : NULL;
158+
}
159+
160+
protected function alterPath() {
161+
// We run whatever splitsh-lite we can find in the $PATH. Add the current
162+
// directory to the end of the path so that we will always find the one
163+
// at the project root if there isn't one already in the path.
164+
$path = getenv('PATH');
165+
putenv("PATH=$path:.");
166+
}
167+
140168
protected function updateRepository($directory, $branch) {
141169
if (!file_exists($directory)) {
142170
passthru("git clone {$this->upstream} {$directory}");
@@ -146,15 +174,19 @@ protected function updateRepository($directory, $branch) {
146174

147175
protected function splitBranch($directory, $ref, $token, $prefix = 'core', $name = 'core') {
148176
passthru("cd {$directory} && git checkout --force {$ref} && git reset --hard origin/{$ref}");
149-
passthru("./splitsh-lite --progress --prefix={$prefix}/ --origin=origin/{$ref} --path={$directory} --target=HEAD");
177+
passthru("splitsh-lite --progress --prefix={$prefix}/ --origin=origin/{$ref} --path={$directory} --target=HEAD");
150178
passthru("cd {$directory} && git push https://{$this->github_username}:{$token}@github.com/{$this->github_orgname}/{$name}.git HEAD:{$ref}");
151179
}
152180

153181
protected function splitTag($directory, $ref, $token, $prefix = 'core', $name = 'core') {
154-
passthru("cd {$directory} && git fetch --tags");
155-
passthru("./splitsh-lite --progress --prefix={$prefix}/ --origin=tags/{$ref} --path={$directory} --target=tags/{$ref}");
156-
passthru("cd {$directory} && git push --delete https://{$this->github_username}:{$token}@github.com/{$this->github_orgname}/{$name}.git {$ref}");
157-
passthru("cd {$directory} && git push https://{$this->github_username}:{$token}@github.com/{$this->github_orgname}/{$name}.git {$ref}");
182+
$split_directory = 'upstream-split-source';
183+
passthru("git clone $directory $split_directory");
184+
passthru("cd {$split_directory} && git fetch --tags");
185+
passthru("splitsh-lite --progress --prefix={$prefix}/ --origin=tags/{$ref} --path={$split_directory} --target=tags/{$ref}");
186+
passthru("cd {$split_directory} && git push --delete https://{$this->github_username}:{$token}@github.com/{$this->github_orgname}/{$name}.git {$ref}");
187+
passthru("cd {$split_directory} && git push https://{$this->github_username}:{$token}@github.com/{$this->github_orgname}/{$name}.git {$ref}");
188+
passthru("cd {$split_directory} && git tag --delete $ref");
189+
passthru("rm -rf {$split_directory}");
158190
}
159191

160192
/**
@@ -174,10 +206,36 @@ protected function getSubtrees($directory) {
174206
if ($file->getRelativePath() == "") {
175207
continue;
176208
};
177-
$subtree_projectname = str_replace("drupal/", "", json_decode($file->getContents())->name);
178-
$subtrees[$subtree_projectname] = ['path' => $file->getRelativePath(), 'description' => json_decode($file->getContents())->description];
209+
$json = json_decode($file->getContents());
210+
$subtree_projectname = str_replace("drupal/", "", $json->name);
211+
$subtrees[$subtree_projectname] = ['path' => $file->getRelativePath(), 'description' => $json->description];
179212
}
180213
return $subtrees;
181214
}
182215

216+
protected function comparePackageNames($a, $b) {
217+
return strcasecmp($this->packageNameForComparison($a), $this->packageNameForComparison($b));
218+
}
219+
220+
/**
221+
* Prepends two spaces for 'core-' and one for 'core' itself.
222+
*
223+
* @param string $name
224+
* Package name to compare.
225+
*
226+
* @return string
227+
* Prefix to add before comparing.
228+
*/
229+
protected function packageNameForComparison($name) {
230+
$name = trim($name);
231+
$space = ' ';
232+
if (substr($name, 0, 5) == 'core-') {
233+
return "$space$space$name";
234+
}
235+
if (substr($name, 0, 4) == 'core') {
236+
return "$space$name";
237+
}
238+
return $name;
239+
}
240+
183241
}

0 commit comments

Comments
 (0)