Skip to content

Commit 1d4b0b9

Browse files
authored
Merge pull request #12 from laminas/feature/#11-add-default-branch-switching
#11 - create+switch default branch on release
2 parents 0fc020d + 20ac681 commit 1d4b0b9

19 files changed

+973
-110
lines changed

.github/workflows/automatic-release.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,13 @@ jobs:
3535
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
3636
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
3737
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
38+
39+
- name: "Create and/or Switch to new Release Branch"
40+
uses: "./"
41+
with:
42+
command-name: "laminas:automatic-releases:switch-default-branch-to-next-minor"
43+
env:
44+
"GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }}
45+
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
46+
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
47+
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ to your project or organisation:
2525
* `GIT_AUTHOR_EMAIL` - email address of the author of your releases: can be an email address of a bot account.
2626
* `SIGNING_SECRET_KEY` - a **password-less** private GPG key in ASCII format, to be used for signing your releases:
2727
please use a dedicated GPG subkey for this purpose. Unsigned releases are not supported, and won't be supported.
28+
* `ORGANIZATION_ADMIN_TOKEN` - if you use the file from [`examples/.github/workflows/release-on-milestone-closed.yml`](examples/.github/workflows/release-on-milestone-closed.yml),
29+
then you have to provide a `ORGANIZATION_ADMIN_TOKEN`, which is a github token with administrative rights over
30+
your organisation (issued by a user that has administrative rights over your project).
31+
This is required for the `laminas:automatic-releases:switch-default-branch-to-next-minor`
32+
command, because [changing default branch of a repository currently requires administrative token rights](https://developer.github.com/v3/repos/#update-a-repository).
33+
You can generate a token from your [personal access tokens page](https://github.com/settings/tokens/new).
2834

2935
## Usage
3036

@@ -41,6 +47,8 @@ this action will perform all following steps (or stop with an error):
4147
5. create a tag named `x.y.z` on the selected branch, with the generated changelog
4248
6. publish a release named `x.y.z`, with the generated tag and changelog
4349
7. create (if applicable), a pull request from the selected branch to the next release branch
50+
8. create (if necessary) a "next minor" release branch `x.y+1.z`
51+
9. switch default repository branch to newest release branch
4452

4553
Please read the [`feature/`](./feature) specification for more detailed scenarios on how the tool is supposed
4654
to operate.

action.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ description: 'Automates automatic releases for semver-compliant repositories'
66

77
inputs:
88
command-name:
9-
description: 'Command to execute: one of "laminas:automatic-releases:release" or "laminas:automatic-releases:create-merge-up-pull-request"'
9+
description: |
10+
Command to execute: one of
11+
* `laminas:automatic-releases:release`
12+
* `laminas:automatic-releases:create-merge-up-pull-request`
13+
* `laminas:automatic-releases:switch-default-branch-to-next-minor`
1014
required: true
1115

1216
runs:

bin/console.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Http\Discovery\Psr17FactoryDiscovery;
1111
use Laminas\AutomaticReleases\Application\Command\CreateMergeUpPullRequest;
1212
use Laminas\AutomaticReleases\Application\Command\ReleaseCommand;
13+
use Laminas\AutomaticReleases\Application\Command\SwitchDefaultBranchToNextMinor;
1314
use Laminas\AutomaticReleases\Environment\EnvironmentVariables;
1415
use Laminas\AutomaticReleases\Git\CreateTagViaConsole;
1516
use Laminas\AutomaticReleases\Git\FetchAndSetCurrentUserByReplacingCurrentOriginRemote;
@@ -19,6 +20,7 @@
1920
use Laminas\AutomaticReleases\Github\Api\GraphQL\RunGraphQLQuery;
2021
use Laminas\AutomaticReleases\Github\Api\V3\CreatePullRequestThroughApiCall;
2122
use Laminas\AutomaticReleases\Github\Api\V3\CreateReleaseThroughApiCall;
23+
use Laminas\AutomaticReleases\Github\Api\V3\SetDefaultBranchThroughApiCall;
2224
use Laminas\AutomaticReleases\Github\CreateReleaseTextThroughChangelog;
2325
use Laminas\AutomaticReleases\Github\Event\Factory\LoadCurrentGithubEventFromGithubActionPath;
2426
use Laminas\AutomaticReleases\Github\JwageGenerateChangelog;
@@ -93,6 +95,18 @@ static function (int $errorCode, string $message = '', string $file = '', int $l
9395
$githubToken
9496
)
9597
),
98+
new SwitchDefaultBranchToNextMinor(
99+
$variables,
100+
$loadEvent,
101+
$fetch,
102+
$getCandidateBranches,
103+
$push,
104+
new SetDefaultBranchThroughApiCall(
105+
$makeRequests,
106+
$httpClient,
107+
$githubToken
108+
)
109+
),
96110
]);
97111

98112
$application->run();

examples/.github/workflows/release-on-milestone-closed.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
uses: "actions/checkout@v2"
1818

1919
- name: "Release"
20-
uses: "laminas/automatic-releases@v1"
20+
uses: "laminas/automatic-releases@v1.0.0"
2121
with:
2222
command-name: "laminas:automatic-releases:release"
2323
env:
@@ -27,11 +27,21 @@ jobs:
2727
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
2828

2929
- name: "Create Merge-Up Pull Request"
30-
uses: "laminas/automatic-releases@v1"
30+
uses: "laminas/automatic-releases@v1.0.0"
3131
with:
3232
command-name: "laminas:automatic-releases:create-merge-up-pull-request"
3333
env:
3434
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
3535
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
3636
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
3737
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
38+
39+
- name: "Create and/or Switch to new Release Branch"
40+
uses: "laminas/[email protected]"
41+
with:
42+
command-name: "laminas:automatic-releases:switch-default-branch-to-next-minor"
43+
env:
44+
"GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }}
45+
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
46+
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
47+
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}

feature/automated-releases.feature

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ Feature: Automated releases
33

44
Scenario: If no major release branch exists, the tool should not create a new major release
55
Given following existing branches:
6-
| name |
7-
| 1.0.x |
6+
| name |
7+
| 1.0.x |
8+
| master |
9+
| develop |
810
And following open milestones:
911
| name |
1012
| 2.0.0 |
@@ -13,8 +15,10 @@ Feature: Automated releases
1315

1416
Scenario: If no major release branch exists, the tool should not create a new minor release
1517
Given following existing branches:
16-
| name |
17-
| 1.0.x |
18+
| name |
19+
| 1.0.x |
20+
| master |
21+
| develop |
1822
And following open milestones:
1923
| name |
2024
| 1.1.0 |
@@ -23,39 +27,57 @@ Feature: Automated releases
2327

2428
Scenario: If a major release branch exists, the tool creates a major release from there
2529
Given following existing branches:
26-
| name |
27-
| 1.0.x |
28-
| master |
30+
| name |
31+
| 1.0.x |
32+
| 2.0.x |
33+
| master |
34+
| develop |
2935
And following open milestones:
3036
| name |
3137
| 2.0.0 |
3238
When I close milestone "2.0.0"
33-
Then tag "2.0.0" should have been created on branch "master"
34-
And branch "2.0.x" should have been created from "master"
39+
Then tag "2.0.0" should have been created on branch "2.0.x"
3540

36-
Scenario: If a major release branch exists, the tool creates a new minor release from there
41+
Scenario: If a new major release branch exists, the tool does not create a new minor release
3742
Given following existing branches:
38-
| name |
39-
| 1.0.x |
40-
| master |
43+
| name |
44+
| 1.0.x |
45+
| 2.0.x |
46+
| master |
47+
| develop |
4148
And following open milestones:
4249
| name |
4350
| 1.1.0 |
4451
When I close milestone "1.1.0"
45-
Then tag "1.1.0" should have been created on branch "master"
46-
And branch "1.1.x" should have been created from "master"
52+
Then the tool should have halted with an error
4753

48-
Scenario: If a minor release branch exists, the tool creates a new minor release from there
54+
Scenario: If a minor release branch exists, when closing the minor release milestone,
55+
the tool tags the minor release from the branch, and creates a pull request
56+
against the next newer minor release branch.
4957
Given following existing branches:
5058
| name |
5159
| 1.1.x |
60+
| 1.2.x |
5261
| master |
5362
And following open milestones:
5463
| name |
5564
| 1.1.0 |
5665
When I close milestone "1.1.0"
5766
Then tag "1.1.0" should have been created on branch "1.1.x"
58-
And a new pull request from branch "1.1.x" to "master" should have been created
67+
And a new pull request from branch "1.1.x" to "1.2.x" should have been created
68+
69+
Scenario: If no newer release branch exists, the tool will not create any pull requests
70+
Given following existing branches:
71+
| name |
72+
| 1.1.x |
73+
| master |
74+
| develop |
75+
And following open milestones:
76+
| name |
77+
| 1.1.0 |
78+
When I close milestone "1.1.0"
79+
Then tag "1.1.0" should have been created on branch "1.1.x"
80+
And no new pull request should have been created
5981

6082
Scenario: If a minor release branch exists, the tool creates a new patch release from there
6183
Given following existing branches:
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
@manually-tested
2+
Feature: Default branch switching
3+
4+
Scenario: A new minor branch is created and set as default branch on release
5+
Given following existing branches:
6+
| branch |
7+
| 1.0.x |
8+
| 1.1.x |
9+
| 1.2.x |
10+
And following open milestones:
11+
| name |
12+
| 1.2.0 |
13+
And the default branch is "1.0.x"
14+
When I close milestone "1.2.0"
15+
Then these should be the existing branches:
16+
| branch |
17+
| 1.0.x |
18+
| 1.1.x |
19+
| 1.2.x |
20+
| 1.3.x |
21+
And the default branch should be "1.3.x"
22+
23+
Scenario: The latest pre-existing minor release branch is set as default branch on a successful release
24+
Given following existing branches:
25+
| branch |
26+
| 1.0.x |
27+
| 1.1.x |
28+
| 1.2.x |
29+
| 1.3.x |
30+
And following open milestones:
31+
| name |
32+
| 1.2.0 |
33+
And the default branch is "1.0.x"
34+
When I close milestone "1.2.0"
35+
Then these should be the existing branches:
36+
| branch |
37+
| 1.0.x |
38+
| 1.1.x |
39+
| 1.2.x |
40+
| 1.3.x |
41+
And the default branch should be "1.3.x"
42+
43+
Scenario: A pre-existing branch of a greater major release is set as default branch on release
44+
Given following existing branches:
45+
| branch |
46+
| 1.0.x |
47+
| 1.1.x |
48+
| 1.2.x |
49+
| 2.0.x |
50+
| 2.1.x |
51+
And following open milestones:
52+
| name |
53+
| 1.2.0 |
54+
And the default branch is "1.0.x"
55+
When I close milestone "1.2.0"
56+
Then these should be the existing branches:
57+
| branch |
58+
| 1.0.x |
59+
| 1.1.x |
60+
| 1.2.x |
61+
| 2.0.x |
62+
| 2.1.x |
63+
And the default branch should be "2.1.x"
64+
65+
Scenario: Branch is not switched when no minor release branch exists
66+
Given following existing branches:
67+
| branch |
68+
| foo |
69+
| bar |
70+
| master |
71+
| develop |
72+
And following open milestones:
73+
| name |
74+
| 1.2.0 |
75+
And the default branch is "develop"
76+
When I close milestone "1.2.0"
77+
Then these should be the existing branches:
78+
| branch |
79+
| foo |
80+
| bar |
81+
| master |
82+
| develop |
83+
And the default branch should be "develop"
84+

infection.json.dist

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
"mutators": {
1515
"@default": true
1616
},
17-
"minMsi": 59,
18-
"minCoveredMsi": 59
17+
"minMsi": 62,
18+
"minCoveredMsi": 62
1919
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Laminas\AutomaticReleases\Application\Command;
6+
7+
use Laminas\AutomaticReleases\Environment\Variables;
8+
use Laminas\AutomaticReleases\Git\Fetch;
9+
use Laminas\AutomaticReleases\Git\GetMergeTargetCandidateBranches;
10+
use Laminas\AutomaticReleases\Git\Push;
11+
use Laminas\AutomaticReleases\Github\Api\V3\SetDefaultBranch;
12+
use Laminas\AutomaticReleases\Github\Event\Factory\LoadCurrentGithubEvent;
13+
use Symfony\Component\Console\Command\Command;
14+
use Symfony\Component\Console\Input\InputInterface;
15+
use Symfony\Component\Console\Output\OutputInterface;
16+
use Webmozart\Assert\Assert;
17+
18+
final class SwitchDefaultBranchToNextMinor extends Command
19+
{
20+
private Variables $variables;
21+
private LoadCurrentGithubEvent $loadGithubEvent;
22+
private Fetch $fetch;
23+
private GetMergeTargetCandidateBranches $getMergeCandidates;
24+
private Push $push;
25+
private SetDefaultBranch $switchDefaultBranch;
26+
27+
public function __construct(
28+
Variables $variables,
29+
LoadCurrentGithubEvent $loadGithubEvent,
30+
Fetch $fetch,
31+
GetMergeTargetCandidateBranches $getMergeCandidates,
32+
Push $push,
33+
SetDefaultBranch $switchDefaultBranch
34+
) {
35+
parent::__construct('laminas:automatic-releases:switch-default-branch-to-next-minor');
36+
37+
$this->variables = $variables;
38+
$this->loadGithubEvent = $loadGithubEvent;
39+
$this->fetch = $fetch;
40+
$this->getMergeCandidates = $getMergeCandidates;
41+
$this->push = $push;
42+
$this->switchDefaultBranch = $switchDefaultBranch;
43+
}
44+
45+
public function execute(InputInterface $input, OutputInterface $output): int
46+
{
47+
$event = $this->loadGithubEvent->__invoke();
48+
$repositoryPath = $this->variables->githubWorkspacePath();
49+
50+
Assert::directory($repositoryPath . '/.git');
51+
52+
$this->fetch->__invoke(
53+
$event->repository()
54+
->uriWithTokenAuthentication($this->variables->githubToken()),
55+
$repositoryPath
56+
);
57+
58+
$mergeCandidates = $this->getMergeCandidates->__invoke($repositoryPath);
59+
$releaseVersion = $event->version();
60+
$newestBranch = $mergeCandidates->newestReleaseBranch();
61+
62+
if ($newestBranch === null) {
63+
$output->writeln('No stable branches found: cannot switch default branch');
64+
65+
return 0;
66+
}
67+
68+
$nextDefaultBranch = $mergeCandidates->newestFutureReleaseBranchAfter($releaseVersion);
69+
70+
if (! $mergeCandidates->contains($nextDefaultBranch)) {
71+
$this->push->__invoke(
72+
$repositoryPath,
73+
$newestBranch->name(),
74+
$nextDefaultBranch->name()
75+
);
76+
}
77+
78+
$this->switchDefaultBranch->__invoke($event->repository(), $nextDefaultBranch);
79+
80+
return 0;
81+
}
82+
}

0 commit comments

Comments
 (0)