Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
c3822edb
Unverified
Commit
c3822edb
authored
Jun 22, 2021
by
Christopher Fujino
Committed by
GitHub
Jun 22, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Conductor add next (#84354)
parent
567586b4
Changes
23
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
1322 additions
and
371 deletions
+1322
-371
README.md
dev/conductor/README.md
+50
-2
conductor.dart
dev/conductor/bin/conductor.dart
+4
-0
codesign.dart
dev/conductor/lib/codesign.dart
+2
-3
globals.dart
dev/conductor/lib/globals.dart
+2
-0
next.dart
dev/conductor/lib/next.dart
+288
-0
compile_proto.sh
dev/conductor/lib/proto/compile_proto.sh
+1
-1
conductor_state.pb.dart
dev/conductor/lib/proto/conductor_state.pb.dart
+12
-11
conductor_state.pbenum.dart
dev/conductor/lib/proto/conductor_state.pbenum.dart
+9
-9
conductor_state.pbjson.dart
dev/conductor/lib/proto/conductor_state.pbjson.dart
+11
-11
conductor_state.proto
dev/conductor/lib/proto/conductor_state.proto
+12
-10
repository.dart
dev/conductor/lib/repository.dart
+112
-86
roll_dev.dart
dev/conductor/lib/roll_dev.dart
+14
-13
start.dart
dev/conductor/lib/start.dart
+42
-15
state.dart
dev/conductor/lib/state.dart
+43
-21
status.dart
dev/conductor/lib/status.dart
+2
-4
version.dart
dev/conductor/lib/version.dart
+59
-5
codesign_test.dart
dev/conductor/test/codesign_test.dart
+8
-14
common.dart
dev/conductor/test/common.dart
+14
-3
next_test.dart
dev/conductor/test/next_test.dart
+572
-0
roll_dev_integration_test.dart
dev/conductor/test/roll_dev_integration_test.dart
+0
-91
roll_dev_test.dart
dev/conductor/test/roll_dev_test.dart
+33
-55
start_test.dart
dev/conductor/test/start_test.dart
+19
-1
version_test.dart
dev/conductor/test/version_test.dart
+13
-16
No files found.
dev/conductor/README.md
View file @
c3822edb
...
...
@@ -29,8 +29,8 @@ Releases are initialized with the `start` sub-command, like:
conductor start \
--candidate-branch=flutter-2.2-candidate.10 \
--release-channel=beta \
--framework-mirror=git@github.com:
flutter-contributor
/flutter.git \
--engine-mirror=git@github.com:
flutter-contributor
/engine.git \
--framework-mirror=git@github.com:
username
/flutter.git \
--engine-mirror=git@github.com:
username
/engine.git \
--engine-cherrypicks=72114dafe28c8700f1d5d629c6ae9d34172ba395 \
--framework-cherrypicks=a3e66b396746f6581b2b7efd1b0d0f0074215128,d8d853436206e86f416236b930e97779b143a100 \
--dart-revision=4511eb2a779a612d9d6b2012123575013e0aef12
...
...
@@ -54,3 +54,51 @@ Upon successful completion of the release, the following command will remove the
persistent state file:
`conductor clean`
## Steps
Once the user has finished manual steps for each step, they proceed to the next
step with the command:
`conductor next`
### Apply Engine Cherrypicks
The tool will attempt to auto-apply all engine cherrypicks. However, any
cherrypicks that result in a merge conflict will be reverted and it is left to
the user to manually cherry-pick them (with the command
`git cherry-pick
$REVISION`
) and resolve the merge conflict in their checkout.
Once a PR is opened, the user must validate CI builds. If there are regressions
(or if the
`licenses_check`
fails, then
`//engine/ci/licenses_golden/licenses_third_party`
must be updated to match the
output of the failing test), then the user must fix these tests in their local
checkout and push their changes again.
### Codesign Engine Binaries
The user must validate post-submit CI builds for their merged engine PR have
passed. A link to the web dashboard is available via
`conductor status`
. Once
the post-submit CI builds have all passed, the user must codesign engine
binaries for the
**merged**
engine commit.
### Apply Framework Cherrypicks
The tool will attempt to auto-apply all framework cherrypicks. However, any
cherrypicks that result in a merge conflict will be reverted and it is left to
the user to manually cherry-pick them (with the command
`git cherry-pick
$REVISION`
) and resolve the merge conflict in their checkout.
### Publish Version
This step will add a version git tag to the final Framework commit and push it
to the upstream repository.
### Publish Channel
This step will update the upstream release branch.
### Verify Release
For the final step, the user must manually verify that packaging builds have
finished successfully.
dev/conductor/bin/conductor.dart
View file @
c3822edb
...
...
@@ -13,6 +13,7 @@ import 'package:conductor/candidates.dart';
import
'package:conductor/clean.dart'
;
import
'package:conductor/codesign.dart'
;
import
'package:conductor/globals.dart'
;
import
'package:conductor/next.dart'
;
import
'package:conductor/repository.dart'
;
import
'package:conductor/roll_dev.dart'
;
import
'package:conductor/start.dart'
;
...
...
@@ -74,6 +75,9 @@ Future<void> main(List<String> args) async {
checkouts:
checkouts
,
flutterRoot:
localFlutterRoot
,
),
NextCommand
(
checkouts:
checkouts
,
),
].
forEach
(
runner
.
addCommand
);
if
(!
assertsEnabled
())
{
...
...
dev/conductor/lib/codesign.dart
View file @
c3822edb
...
...
@@ -115,8 +115,7 @@ class CodesignCommand extends Command<void> {
revision
=
(
processManager
.
runSync
(
<
String
>[
'git'
,
'rev-parse'
,
'HEAD'
],
workingDirectory:
framework
.
checkoutDirectory
.
path
,
).
stdout
as
String
)
.
trim
();
).
stdout
as
String
).
trim
();
assert
(
revision
.
isNotEmpty
);
}
...
...
@@ -291,7 +290,7 @@ class CodesignCommand extends Command<void> {
if
(
wrongEntitlementBinaries
.
isNotEmpty
)
{
stdio
.
printError
(
'Found
${wrongEntitlementBinaries.length}
binaries with unexpected entitlements:'
);
wrongEntitlementBinaries
.
forEach
(
print
);
wrongEntitlementBinaries
.
forEach
(
stdio
.
printError
);
}
if
(
unexpectedBinaries
.
isNotEmpty
)
{
...
...
dev/conductor/lib/globals.dart
View file @
c3822edb
...
...
@@ -20,6 +20,8 @@ const List<String> kReleaseChannels = <String>[
const
String
kReleaseDocumentationUrl
=
'https://github.com/flutter/flutter/wiki/Flutter-Cherrypick-Process'
;
const
String
kLuciPackagingConsoleLink
=
'https://ci.chromium.org/p/flutter/g/packaging/console'
;
final
RegExp
releaseCandidateBranchRegex
=
RegExp
(
r'flutter-(\d+)\.(\d+)-candidate\.(\d+)'
,
);
...
...
dev/conductor/lib/next.dart
0 → 100644
View file @
c3822edb
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'package:args/command_runner.dart'
;
import
'package:file/file.dart'
show
File
;
import
'package:meta/meta.dart'
show
required
,
visibleForTesting
;
import
'./globals.dart'
;
import
'./proto/conductor_state.pb.dart'
as
pb
;
import
'./proto/conductor_state.pbenum.dart'
;
import
'./repository.dart'
;
import
'./state.dart'
;
import
'./stdio.dart'
;
const
String
kStateOption
=
'state-file'
;
const
String
kYesFlag
=
'yes'
;
const
String
kForceFlag
=
'force'
;
/// Command to proceed from one [pb.ReleasePhase] to the next.
class
NextCommand
extends
Command
<
void
>
{
NextCommand
({
@required
this
.
checkouts
,
})
{
final
String
defaultPath
=
defaultStateFilePath
(
checkouts
.
platform
);
argParser
.
addOption
(
kStateOption
,
defaultsTo:
defaultPath
,
help:
'Path to persistent state file. Defaults to
$defaultPath
'
,
);
argParser
.
addFlag
(
kYesFlag
,
help:
'Auto-accept any confirmation prompts.'
,
hide:
true
,
// primarily for integration testing
);
argParser
.
addFlag
(
kForceFlag
,
help:
'Force push when updating remote git branches.'
,
);
}
final
Checkouts
checkouts
;
@override
String
get
name
=>
'next'
;
@override
String
get
description
=>
'Proceed to the next release phase.'
;
@override
void
run
()
{
runNext
(
autoAccept:
argResults
[
kYesFlag
]
as
bool
,
checkouts:
checkouts
,
force:
argResults
[
kForceFlag
]
as
bool
,
stateFile:
checkouts
.
fileSystem
.
file
(
argResults
[
kStateOption
]),
);
}
}
@visibleForTesting
bool
prompt
(
String
message
,
Stdio
stdio
)
{
stdio
.
write
(
'
${message.trim()}
(y/n) '
);
final
String
response
=
stdio
.
readLineSync
().
trim
();
final
String
firstChar
=
response
[
0
].
toUpperCase
();
if
(
firstChar
==
'Y'
)
{
return
true
;
}
if
(
firstChar
==
'N'
)
{
return
false
;
}
throw
ConductorException
(
'Unknown user input (expected "y" or "n"):
$response
'
,
);
}
@visibleForTesting
void
runNext
(
{
@required
bool
autoAccept
,
@required
bool
force
,
@required
Checkouts
checkouts
,
@required
File
stateFile
,
})
{
final
Stdio
stdio
=
checkouts
.
stdio
;
const
List
<
CherrypickState
>
finishedStates
=
<
CherrypickState
>[
CherrypickState
.
COMPLETED
,
CherrypickState
.
ABANDONED
,
];
if
(!
stateFile
.
existsSync
())
{
throw
ConductorException
(
'No persistent state file found at
${stateFile.path}
.'
,
);
}
final
pb
.
ConductorState
state
=
readStateFromFile
(
stateFile
);
switch
(
state
.
currentPhase
)
{
case
pb
.
ReleasePhase
.
APPLY_ENGINE_CHERRYPICKS
:
final
List
<
pb
.
Cherrypick
>
unappliedCherrypicks
=
<
pb
.
Cherrypick
>[];
for
(
final
pb
.
Cherrypick
cherrypick
in
state
.
engine
.
cherrypicks
)
{
if
(!
finishedStates
.
contains
(
cherrypick
.
state
))
{
unappliedCherrypicks
.
add
(
cherrypick
);
}
}
if
(
state
.
engine
.
cherrypicks
.
isEmpty
)
{
stdio
.
printStatus
(
'This release has no engine cherrypicks.'
);
break
;
}
else
if
(
unappliedCherrypicks
.
isEmpty
)
{
stdio
.
printStatus
(
'All engine cherrypicks have been auto-applied by '
'the conductor.
\n
'
);
if
(
autoAccept
==
false
)
{
final
bool
response
=
prompt
(
'Are you ready to push your changes to the repository '
'
${state.engine.mirror.url}
?'
,
stdio
,
);
if
(!
response
)
{
stdio
.
printError
(
'Aborting command.'
);
writeStateToFile
(
stateFile
,
state
,
stdio
.
logs
);
return
;
}
}
}
else
{
stdio
.
printStatus
(
'There were
${unappliedCherrypicks.length}
cherrypicks that were not auto-applied.'
);
stdio
.
printStatus
(
'These must be applied manually in the directory '
'
${state.engine.checkoutPath}
before proceeding.
\n
'
);
if
(
autoAccept
==
false
)
{
final
bool
response
=
prompt
(
'Are you ready to push your engine branch to the repository '
'
${state.engine.mirror.url}
?'
,
stdio
,
);
if
(!
response
)
{
stdio
.
printError
(
'Aborting command.'
);
writeStateToFile
(
stateFile
,
state
,
stdio
.
logs
);
return
;
}
}
}
break
;
case
pb
.
ReleasePhase
.
CODESIGN_ENGINE_BINARIES
:
if
(
autoAccept
==
false
)
{
// TODO(fujino): actually test if binaries have been codesigned on macOS
final
bool
response
=
prompt
(
'Has CI passed for the engine PR and binaries been codesigned?'
,
stdio
,
);
if
(!
response
)
{
stdio
.
printError
(
'Aborting command.'
);
writeStateToFile
(
stateFile
,
state
,
stdio
.
logs
);
return
;
}
}
break
;
case
pb
.
ReleasePhase
.
APPLY_FRAMEWORK_CHERRYPICKS
:
final
List
<
pb
.
Cherrypick
>
unappliedCherrypicks
=
<
pb
.
Cherrypick
>[];
for
(
final
pb
.
Cherrypick
cherrypick
in
state
.
framework
.
cherrypicks
)
{
if
(!
finishedStates
.
contains
(
cherrypick
.
state
))
{
unappliedCherrypicks
.
add
(
cherrypick
);
}
}
if
(
state
.
framework
.
cherrypicks
.
isEmpty
)
{
stdio
.
printStatus
(
'This release has no framework cherrypicks.'
);
break
;
}
else
if
(
unappliedCherrypicks
.
isEmpty
)
{
stdio
.
printStatus
(
'All framework cherrypicks have been auto-applied by '
'the conductor.
\n
'
);
if
(
autoAccept
==
false
)
{
final
bool
response
=
prompt
(
'Are you ready to push your changes to the repository '
'
${state.framework.mirror.url}
?'
,
stdio
,
);
if
(!
response
)
{
stdio
.
printError
(
'Aborting command.'
);
writeStateToFile
(
stateFile
,
state
,
stdio
.
logs
);
return
;
}
}
}
else
{
stdio
.
printStatus
(
'There were
${unappliedCherrypicks.length}
cherrypicks that were not auto-applied.'
);
stdio
.
printStatus
(
'These must be applied manually in the directory '
'
${state.framework.checkoutPath}
before proceeding.
\n
'
);
if
(
autoAccept
==
false
)
{
final
bool
response
=
prompt
(
'Are you ready to push your framework branch to the repository '
'
${state.framework.mirror.url}
?'
,
stdio
,
);
if
(!
response
)
{
stdio
.
printError
(
'Aborting command.'
);
writeStateToFile
(
stateFile
,
state
,
stdio
.
logs
);
return
;
}
}
}
break
;
case
pb
.
ReleasePhase
.
PUBLISH_VERSION
:
stdio
.
printStatus
(
'Please ensure that you have merged your framework PR and that'
);
stdio
.
printStatus
(
'post-submit CI has finished successfully.
\n
'
);
final
Remote
upstream
=
Remote
(
name:
RemoteName
.
upstream
,
url:
state
.
framework
.
upstream
.
url
,
);
final
FrameworkRepository
framework
=
FrameworkRepository
(
checkouts
,
initialRef:
state
.
framework
.
candidateBranch
,
upstreamRemote:
upstream
,
previousCheckoutLocation:
state
.
framework
.
checkoutPath
,
);
final
String
headRevision
=
framework
.
reverseParse
(
'HEAD'
);
if
(
autoAccept
==
false
)
{
final
bool
response
=
prompt
(
'Has CI passed for the framework PR?'
,
stdio
,
);
if
(!
response
)
{
stdio
.
printError
(
'Aborting command.'
);
writeStateToFile
(
stateFile
,
state
,
stdio
.
logs
);
return
;
}
}
framework
.
tag
(
headRevision
,
state
.
releaseVersion
,
upstream
.
name
);
break
;
case
pb
.
ReleasePhase
.
PUBLISH_CHANNEL
:
final
Remote
upstream
=
Remote
(
name:
RemoteName
.
upstream
,
url:
state
.
framework
.
upstream
.
url
,
);
final
FrameworkRepository
framework
=
FrameworkRepository
(
checkouts
,
initialRef:
state
.
framework
.
candidateBranch
,
upstreamRemote:
upstream
,
previousCheckoutLocation:
state
.
framework
.
checkoutPath
,
);
final
String
headRevision
=
framework
.
reverseParse
(
'HEAD'
);
if
(
autoAccept
==
false
)
{
final
bool
response
=
prompt
(
'Are you ready to publish release
${state.releaseVersion}
to '
'channel
${state.releaseChannel}
at
${state.framework.upstream.url}
?'
,
stdio
,
);
if
(!
response
)
{
stdio
.
printError
(
'Aborting command.'
);
writeStateToFile
(
stateFile
,
state
,
stdio
.
logs
);
return
;
}
}
framework
.
updateChannel
(
headRevision
,
state
.
framework
.
upstream
.
url
,
state
.
releaseChannel
,
force:
force
,
);
break
;
case
pb
.
ReleasePhase
.
VERIFY_RELEASE
:
stdio
.
printStatus
(
'The current status of packaging builds can be seen at:
\n
'
'
\t
$kLuciPackagingConsoleLink
'
,
);
if
(
autoAccept
==
false
)
{
final
bool
response
=
prompt
(
'Have all packaging builds finished successfully?'
,
stdio
,
);
if
(!
response
)
{
stdio
.
printError
(
'Aborting command.'
);
writeStateToFile
(
stateFile
,
state
,
stdio
.
logs
);
return
;
}
}
break
;
case
pb
.
ReleasePhase
.
RELEASE_COMPLETED
:
throw
ConductorException
(
'This release is finished.'
);
break
;
}
final
ReleasePhase
nextPhase
=
getNextPhase
(
state
.
currentPhase
);
stdio
.
printStatus
(
'
\n
Updating phase from
${state.currentPhase}
to
$nextPhase
...
\n
'
);
state
.
currentPhase
=
nextPhase
;
stdio
.
printStatus
(
phaseInstructions
(
state
));
writeStateToFile
(
stateFile
,
state
,
stdio
.
logs
);
}
dev/conductor/lib/proto/compile_proto.sh
View file @
c3822edb
...
...
@@ -32,7 +32,7 @@ for SOURCE_FILE in $(ls "$DIR"/*.pb*.dart); do
"
$DARTFMT
"
--overwrite
--line-length
120
"
$SOURCE_FILE
"
# Create temp copy with the license header prepended
cp
license_header.txt
"
${
SOURCE_FILE
}
.tmp"
cp
"
$DIR
/license_header.txt"
"
${
SOURCE_FILE
}
.tmp"
# Add an extra newline required by analysis (analysis also prevents
# license_header.txt from having the trailing newline)
...
...
dev/conductor/lib/proto/conductor_state.pb.dart
View file @
c3822edb
...
...
@@ -378,12 +378,13 @@ class ConductorState extends $pb.GeneratedMessage {
protoName:
'lastUpdatedDate'
)
..
pPS
(
8
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_field_names'
)
?
''
:
'logs'
)
..
e
<
ReleasePhase
>(
9
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_field_names'
)
?
''
:
'
las
tPhase'
,
$pb
.
PbFieldType
.
OE
,
protoName:
'
las
tPhase'
,
defaultOrMaker:
ReleasePhase
.
INITIALIZE
,
9
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_field_names'
)
?
''
:
'
curren
tPhase'
,
$pb
.
PbFieldType
.
OE
,
protoName:
'
curren
tPhase'
,
defaultOrMaker:
ReleasePhase
.
APPLY_ENGINE_CHERRYPICKS
,
valueOf:
ReleasePhase
.
valueOf
,
enumValues:
ReleasePhase
.
values
)
..
aOS
(
10
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_field_names'
)
?
''
:
'conductorVersion'
)
..
aOS
(
10
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_field_names'
)
?
''
:
'conductorVersion'
,
protoName:
'conductorVersion'
)
..
hasRequiredFields
=
false
;
ConductorState
.
_
()
:
super
();
...
...
@@ -395,7 +396,7 @@ class ConductorState extends $pb.GeneratedMessage {
$fixnum
.
Int64
createdDate
,
$fixnum
.
Int64
lastUpdatedDate
,
$core
.
Iterable
<
$core
.
String
>
logs
,
ReleasePhase
las
tPhase
,
ReleasePhase
curren
tPhase
,
$core
.
String
conductorVersion
,
})
{
final
_result
=
create
();
...
...
@@ -420,8 +421,8 @@ class ConductorState extends $pb.GeneratedMessage {
if
(
logs
!=
null
)
{
_result
.
logs
.
addAll
(
logs
);
}
if
(
las
tPhase
!=
null
)
{
_result
.
lastPhase
=
las
tPhase
;
if
(
curren
tPhase
!=
null
)
{
_result
.
currentPhase
=
curren
tPhase
;
}
if
(
conductorVersion
!=
null
)
{
_result
.
conductorVersion
=
conductorVersion
;
...
...
@@ -531,16 +532,16 @@ class ConductorState extends $pb.GeneratedMessage {
$core
.
List
<
$core
.
String
>
get
logs
=>
$_getList
(
6
);
@
$pb
.
TagNumber
(
9
)
ReleasePhase
get
las
tPhase
=>
$_getN
(
7
);
ReleasePhase
get
curren
tPhase
=>
$_getN
(
7
);
@
$pb
.
TagNumber
(
9
)
set
las
tPhase
(
ReleasePhase
v
)
{
set
curren
tPhase
(
ReleasePhase
v
)
{
setField
(
9
,
v
);
}
@
$pb
.
TagNumber
(
9
)
$core
.
bool
has
Las
tPhase
()
=>
$_has
(
7
);
$core
.
bool
has
Curren
tPhase
()
=>
$_has
(
7
);
@
$pb
.
TagNumber
(
9
)
void
clear
Las
tPhase
()
=>
clearField
(
9
);
void
clear
Curren
tPhase
()
=>
clearField
(
9
);
@
$pb
.
TagNumber
(
10
)
$core
.
String
get
conductorVersion
=>
$_getSZ
(
8
);
...
...
dev/conductor/lib/proto/conductor_state.pbenum.dart
View file @
c3822edb
...
...
@@ -14,29 +14,29 @@ import 'dart:core' as $core;
import
'package:protobuf/protobuf.dart'
as
$pb
;
class
ReleasePhase
extends
$pb
.
ProtobufEnum
{
static
const
ReleasePhase
INITIALIZE
=
ReleasePhase
.
_
(
0
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'INITIALIZE'
);
static
const
ReleasePhase
APPLY_ENGINE_CHERRYPICKS
=
ReleasePhase
.
_
(
1
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'APPLY_ENGINE_CHERRYPICKS'
);
ReleasePhase
.
_
(
0
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'APPLY_ENGINE_CHERRYPICKS'
);
static
const
ReleasePhase
CODESIGN_ENGINE_BINARIES
=
ReleasePhase
.
_
(
2
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'CODESIGN_ENGINE_BINARIES'
);
ReleasePhase
.
_
(
1
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'CODESIGN_ENGINE_BINARIES'
);
static
const
ReleasePhase
APPLY_FRAMEWORK_CHERRYPICKS
=
ReleasePhase
.
_
(
3
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'APPLY_FRAMEWORK_CHERRYPICKS'
);
2
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'APPLY_FRAMEWORK_CHERRYPICKS'
);
static
const
ReleasePhase
PUBLISH_VERSION
=
ReleasePhase
.
_
(
4
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'PUBLISH_VERSION'
);
ReleasePhase
.
_
(
3
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'PUBLISH_VERSION'
);
static
const
ReleasePhase
PUBLISH_CHANNEL
=
ReleasePhase
.
_
(
5
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'PUBLISH_CHANNEL'
);
ReleasePhase
.
_
(
4
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'PUBLISH_CHANNEL'
);
static
const
ReleasePhase
VERIFY_RELEASE
=
ReleasePhase
.
_
(
6
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'VERIFY_RELEASE'
);
ReleasePhase
.
_
(
5
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'VERIFY_RELEASE'
);
static
const
ReleasePhase
RELEASE_COMPLETED
=
ReleasePhase
.
_
(
6
,
const
$core
.
bool
.
fromEnvironment
(
'protobuf.omit_enum_names'
)
?
''
:
'RELEASE_COMPLETED'
);
static
const
$core
.
List
<
ReleasePhase
>
values
=
<
ReleasePhase
>[
INITIALIZE
,
APPLY_ENGINE_CHERRYPICKS
,
CODESIGN_ENGINE_BINARIES
,
APPLY_FRAMEWORK_CHERRYPICKS
,
PUBLISH_VERSION
,
PUBLISH_CHANNEL
,
VERIFY_RELEASE
,
RELEASE_COMPLETED
,
];
static
final
$core
.
Map
<
$core
.
int
,
ReleasePhase
>
_byValue
=
$pb
.
ProtobufEnum
.
initByValue
(
values
);
...
...
dev/conductor/lib/proto/conductor_state.pbjson.dart
View file @
c3822edb
...
...
@@ -17,19 +17,19 @@ import 'dart:typed_data' as $typed_data;
const
ReleasePhase$json
=
const
{
'1'
:
'ReleasePhase'
,
'2'
:
const
[
const
{
'1'
:
'
INITIALIZE
'
,
'2'
:
0
},
const
{
'1'
:
'
APPLY_ENGINE_CHERRYPICK
S'
,
'2'
:
1
},
const
{
'1'
:
'
CODESIGN_ENGINE_BINARIE
S'
,
'2'
:
2
},
const
{
'1'
:
'
APPLY_FRAMEWORK_CHERRYPICKS
'
,
'2'
:
3
},
const
{
'1'
:
'PUBLISH_
VERSION
'
,
'2'
:
4
},
const
{
'1'
:
'
PUBLISH_CHANNEL
'
,
'2'
:
5
},
const
{
'1'
:
'
VERIFY_RELEASE
'
,
'2'
:
6
},
const
{
'1'
:
'
APPLY_ENGINE_CHERRYPICKS
'
,
'2'
:
0
},
const
{
'1'
:
'
CODESIGN_ENGINE_BINARIE
S'
,
'2'
:
1
},
const
{
'1'
:
'
APPLY_FRAMEWORK_CHERRYPICK
S'
,
'2'
:
2
},
const
{
'1'
:
'
PUBLISH_VERSION
'
,
'2'
:
3
},
const
{
'1'
:
'PUBLISH_
CHANNEL
'
,
'2'
:
4
},
const
{
'1'
:
'
VERIFY_RELEASE
'
,
'2'
:
5
},
const
{
'1'
:
'
RELEASE_COMPLETED
'
,
'2'
:
6
},
],
};
/// Descriptor for `ReleasePhase`. Decode as a `google.protobuf.EnumDescriptorProto`.
final
$typed_data
.
Uint8List
releasePhaseDescriptor
=
$convert
.
base64Decode
(
'CgxSZWxlYXNlUGhhc2US
DgoKSU5JVElBTElaRRAAEhwKGEFQUExZX0VOR0lORV9DSEVSUllQSUNLUxABEhwKGENPREVTSUdOX0VOR0lORV9CSU5BUklFUxACEh8KG0FQUExZX0ZSQU1FV09SS19DSEVSUllQSUNLUxADEhMKD1BVQkxJU0hfVkVSU0lPThAEEhMKD1BVQkxJU0hfQ0hBTk5FTBAFEhIKDlZFUklGWV9SRUxFQVNFEAY=
'
);
'CgxSZWxlYXNlUGhhc2US
HAoYQVBQTFlfRU5HSU5FX0NIRVJSWVBJQ0tTEAASHAoYQ09ERVNJR05fRU5HSU5FX0JJTkFSSUVTEAESHwobQVBQTFlfRlJBTUVXT1JLX0NIRVJSWVBJQ0tTEAISEwoPUFVCTElTSF9WRVJTSU9OEAMSEwoPUFVCTElTSF9DSEFOTkVMEAQSEgoOVkVSSUZZX1JFTEVBU0UQBRIVChFSRUxFQVNFX0NPTVBMRVRFRBAG
'
);
@
$core
.
Deprecated
(
'Use cherrypickStateDescriptor instead'
)
const
CherrypickState$json
=
const
{
'1'
:
'CherrypickState'
,
...
...
@@ -98,11 +98,11 @@ const ConductorState$json = const {
const
{
'1'
:
'createdDate'
,
'3'
:
6
,
'4'
:
1
,
'5'
:
3
,
'10'
:
'createdDate'
},
const
{
'1'
:
'lastUpdatedDate'
,
'3'
:
7
,
'4'
:
1
,
'5'
:
3
,
'10'
:
'lastUpdatedDate'
},
const
{
'1'
:
'logs'
,
'3'
:
8
,
'4'
:
3
,
'5'
:
9
,
'10'
:
'logs'
},
const
{
'1'
:
'
lastPhase'
,
'3'
:
9
,
'4'
:
1
,
'5'
:
14
,
'6'
:
'.conductor_state.ReleasePhase'
,
'10'
:
'las
tPhase'
},
const
{
'1'
:
'conductor
_v
ersion'
,
'3'
:
10
,
'4'
:
1
,
'5'
:
9
,
'10'
:
'conductorVersion'
},
const
{
'1'
:
'
currentPhase'
,
'3'
:
9
,
'4'
:
1
,
'5'
:
14
,
'6'
:
'.conductor_state.ReleasePhase'
,
'10'
:
'curren
tPhase'
},
const
{
'1'
:
'conductor
V
ersion'
,
'3'
:
10
,
'4'
:
1
,
'5'
:
9
,
'10'
:
'conductorVersion'
},
],
};
/// Descriptor for `ConductorState`. Decode as a `google.protobuf.DescriptorProto`.
final
$typed_data
.
Uint8List
conductorStateDescriptor
=
$convert
.
base64Decode
(
'Cg5Db25kdWN0b3JTdGF0ZRImCg5yZWxlYXNlQ2hhbm5lbBgBIAEoCVIOcmVsZWFzZUNoYW5uZWwSJgoOcmVsZWFzZVZlcnNpb24YAiABKAlSDnJlbGVhc2VWZXJzaW9uEjMKBmVuZ2luZRgEIAEoCzIbLmNvbmR1Y3Rvcl9zdGF0ZS5SZXBvc2l0b3J5UgZlbmdpbmUSOQoJZnJhbWV3b3JrGAUgASgLMhsuY29uZHVjdG9yX3N0YXRlLlJlcG9zaXRvcnlSCWZyYW1ld29yaxIgCgtjcmVhdGVkRGF0ZRgGIAEoA1ILY3JlYXRlZERhdGUSKAoPbGFzdFVwZGF0ZWREYXRlGAcgASgDUg9sYXN0VXBkYXRlZERhdGUSEgoEbG9ncxgIIAMoCVIEbG9ncx
I7CglsYXN0UGhhc2UYCSABKA4yHS5jb25kdWN0b3Jfc3RhdGUuUmVsZWFzZVBoYXNlUglsYXN0UGhhc2USKwoRY29uZHVjdG9yX3ZlcnNpb24YCiABKAlSEGNvbmR1Y3RvclZlcnNpb24
='
);
'Cg5Db25kdWN0b3JTdGF0ZRImCg5yZWxlYXNlQ2hhbm5lbBgBIAEoCVIOcmVsZWFzZUNoYW5uZWwSJgoOcmVsZWFzZVZlcnNpb24YAiABKAlSDnJlbGVhc2VWZXJzaW9uEjMKBmVuZ2luZRgEIAEoCzIbLmNvbmR1Y3Rvcl9zdGF0ZS5SZXBvc2l0b3J5UgZlbmdpbmUSOQoJZnJhbWV3b3JrGAUgASgLMhsuY29uZHVjdG9yX3N0YXRlLlJlcG9zaXRvcnlSCWZyYW1ld29yaxIgCgtjcmVhdGVkRGF0ZRgGIAEoA1ILY3JlYXRlZERhdGUSKAoPbGFzdFVwZGF0ZWREYXRlGAcgASgDUg9sYXN0VXBkYXRlZERhdGUSEgoEbG9ncxgIIAMoCVIEbG9ncx
JBCgxjdXJyZW50UGhhc2UYCSABKA4yHS5jb25kdWN0b3Jfc3RhdGUuUmVsZWFzZVBoYXNlUgxjdXJyZW50UGhhc2USKgoQY29uZHVjdG9yVmVyc2lvbhgKIAEoCVIQY29uZHVjdG9yVmVyc2lvbg=
='
);
dev/conductor/lib/proto/conductor_state.proto
View file @
c3822edb
...
...
@@ -10,21 +10,23 @@ message Remote {
enum
ReleasePhase
{
// Release was started with `conductor start` and repositories cloned.
INITIALIZE
=
0
;
APPLY_ENGINE_CHERRYPICKS
=
1
;
CODESIGN_ENGINE_BINARIES
=
2
;
APPLY_FRAMEWORK_CHERRYPICKS
=
3
;
APPLY_ENGINE_CHERRYPICKS
=
0
;
CODESIGN_ENGINE_BINARIES
=
1
;
APPLY_FRAMEWORK_CHERRYPICKS
=
2
;
// Git tag applied to framework RC branch HEAD and pushed upstream.
PUBLISH_VERSION
=
4
;
PUBLISH_VERSION
=
3
;
// RC branch HEAD pushed to upstream release branch.
//
// For example, flutter-1.2-candidate.3 -> upstream/beta
PUBLISH_CHANNEL
=
5
;
PUBLISH_CHANNEL
=
4
;
// Package artifacts verified to exist on cloud storage.
VERIFY_RELEASE
=
6
;
VERIFY_RELEASE
=
5
;
// There is no further work to be done.
RELEASE_COMPLETED
=
6
;
}
enum
CherrypickState
{
...
...
@@ -98,9 +100,9 @@ message ConductorState {
repeated
string
logs
=
8
;
// The
last [ReleasePhase] that was successfully
completed.
ReleasePhase
las
tPhase
=
9
;
// The
current [ReleasePhase] that has yet to be
completed.
ReleasePhase
curren
tPhase
=
9
;
// Commit hash of the Conductor tool.
string
conductor
_v
ersion
=
10
;
string
conductor
V
ersion
=
10
;
}
dev/conductor/lib/repository.dart
View file @
c3822edb
This diff is collapsed.
Click to expand it.
dev/conductor/lib/roll_dev.dart
View file @
c3822edb
...
...
@@ -13,7 +13,7 @@ import './stdio.dart';
import
'./version.dart'
;
const
String
kIncrement
=
'increment'
;
const
String
kC
ommit
=
'commit
'
;
const
String
kC
andidateBranch
=
'candidate-branch
'
;
const
String
kRemoteName
=
'remote'
;
const
String
kJustPrint
=
'just-print'
;
const
String
kYes
=
'yes'
;
...
...
@@ -40,9 +40,9 @@ class RollDevCommand extends Command<void> {
},
);
argParser
.
addOption
(
kC
ommit
,
help:
'Specifies which git
commit
to roll to the dev branch. Required.'
,
valueHelp:
'
has
h'
,
kC
andidateBranch
,
help:
'Specifies which git
branch
to roll to the dev branch. Required.'
,
valueHelp:
'
branc
h'
,
defaultsTo:
null
,
// This option is required
);
argParser
.
addFlag
(
...
...
@@ -112,17 +112,16 @@ bool rollDev({
})
{
final
String
remoteName
=
argResults
[
kRemoteName
]
as
String
;
final
String
level
=
argResults
[
kIncrement
]
as
String
;
final
String
c
ommit
=
argResults
[
kCommit
]
as
String
;
final
String
c
andidateBranch
=
argResults
[
kCandidateBranch
]
as
String
;
final
bool
justPrint
=
argResults
[
kJustPrint
]
as
bool
;
final
bool
autoApprove
=
argResults
[
kYes
]
as
bool
;
final
bool
force
=
argResults
[
kForce
]
as
bool
;
final
bool
skipTagging
=
argResults
[
kSkipTagging
]
as
bool
;
if
(
level
==
null
||
c
ommit
==
null
)
{
stdio
.
printStatus
(
'roll_dev.dart --
increment=level --commit=has
h • update the version tags '
if
(
level
==
null
||
c
andidateBranch
==
null
)
{
throw
Exception
(
'roll_dev.dart --
$kIncrement
=level --
$kCandidateBranch
=branc
h • update the version tags '
'and roll a new dev build.
\n
$usage
'
);
return
false
;
}
final
String
remoteUrl
=
repository
.
remoteUrl
(
remoteName
);
...
...
@@ -136,14 +135,16 @@ bool rollDev({
repository
.
fetch
(
remoteName
);
// Verify [commit] is valid
repository
.
reverseParse
(
commit
);
final
String
commit
=
repository
.
reverseParse
(
candidateBranch
);
stdio
.
printStatus
(
'remoteName is
$remoteName
'
);
final
Version
lastVersion
=
Version
.
fromString
(
repository
.
getFullTag
(
remoteName
));
// Get the name of the last dev release
final
Version
lastVersion
=
Version
.
fromString
(
repository
.
getFullTag
(
remoteName
,
'dev'
),
);
final
Version
version
=
skipTagging
?
lastVersion
:
Version
.
increment
(
lastVersion
,
level
);
skipTagging
?
lastVersion
:
Version
.
fromCandidateBranch
(
candidateBranch
);
final
String
tagName
=
version
.
toString
();
if
(
repository
.
reverseParse
(
lastVersion
.
toString
()).
contains
(
commit
.
trim
()))
{
...
...
dev/conductor/lib/start.dart
View file @
c3822edb
...
...
@@ -4,8 +4,6 @@
// @dart = 2.8
import
'dart:convert'
show
jsonEncode
;
import
'package:args/command_runner.dart'
;
import
'package:file/file.dart'
;
import
'package:fixnum/fixnum.dart'
;
...
...
@@ -20,6 +18,7 @@ import './proto/conductor_state.pbenum.dart' show ReleasePhase;
import
'./repository.dart'
;
import
'./state.dart'
;
import
'./stdio.dart'
;
import
'./version.dart'
;
const
String
kCandidateOption
=
'candidate-branch'
;
const
String
kDartRevisionOption
=
'dart-revision'
;
...
...
@@ -28,6 +27,7 @@ const String kEngineUpstreamOption = 'engine-upstream';
const
String
kFrameworkCherrypicksOption
=
'framework-cherrypicks'
;
const
String
kFrameworkMirrorOption
=
'framework-mirror'
;
const
String
kFrameworkUpstreamOption
=
'framework-upstream'
;
const
String
kIncrementOption
=
'increment'
;
const
String
kEngineMirrorOption
=
'engine-mirror'
;
const
String
kReleaseOption
=
'release-channel'
;
const
String
kStateOption
=
'state-file'
;
...
...
@@ -91,6 +91,18 @@ class StartCommand extends Command<void> {
kDartRevisionOption
,
help:
'New Dart revision to cherrypick.'
,
);
argParser
.
addOption
(
kIncrementOption
,
help:
'Specifies which part of the x.y.z version number to increment. Required.'
,
valueHelp:
'level'
,
allowed:
<
String
>[
'y'
,
'z'
,
'm'
,
'n'
],
allowedHelp:
<
String
,
String
>{
'y'
:
'Indicates the first dev release after a beta release.'
,
'z'
:
'Indicates a hotfix to a stable release.'
,
'm'
:
'Indicates a standard dev release.'
,
'n'
:
'Indicates a hotfix to a dev release.'
,
},
);
final
Git
git
=
Git
(
processManager
);
conductorVersion
=
git
.
getOutput
(
<
String
>[
'rev-parse'
,
'HEAD'
],
...
...
@@ -183,6 +195,12 @@ class StartCommand extends Command<void> {
platform
.
environment
,
allowNull:
true
,
);
final
String
incrementLetter
=
getValueFromEnvOrArgs
(
kIncrementOption
,
argResults
,
platform
.
environment
,
);
if
(!
releaseCandidateBranchRegex
.
hasMatch
(
candidateBranch
))
{
throw
ConductorException
(
'Invalid release candidate branch "
$candidateBranch
". Text should '
...
...
@@ -200,11 +218,11 @@ class StartCommand extends Command<void> {
final
EngineRepository
engine
=
EngineRepository
(
checkouts
,
initialRef:
candidateBranch
,
fetch
Remote:
Remote
(
upstream
Remote:
Remote
(
name:
RemoteName
.
upstream
,
url:
engineUpstream
,
),
push
Remote:
Remote
(
mirror
Remote:
Remote
(
name:
RemoteName
.
mirror
,
url:
engineMirror
,
),
...
...
@@ -249,15 +267,17 @@ class StartCommand extends Command<void> {
checkoutPath:
engine
.
checkoutDirectory
.
path
,
cherrypicks:
engineCherrypicks
,
dartRevision:
dartRevision
,
upstream:
pb
.
Remote
(
name:
'upstream'
,
url:
engine
.
upstreamRemote
.
url
),
mirror:
pb
.
Remote
(
name:
'mirror'
,
url:
engine
.
mirrorRemote
.
url
),
);
final
FrameworkRepository
framework
=
FrameworkRepository
(
checkouts
,
initialRef:
candidateBranch
,
fetch
Remote:
Remote
(
upstream
Remote:
Remote
(
name:
RemoteName
.
upstream
,
url:
frameworkUpstream
,
),
push
Remote:
Remote
(
mirror
Remote:
Remote
(
name:
RemoteName
.
mirror
,
url:
frameworkMirror
,
),
...
...
@@ -287,6 +307,16 @@ class StartCommand extends Command<void> {
}
}
// Get framework version
final
Version
lastVersion
=
Version
.
fromString
(
framework
.
getFullTag
(
framework
.
upstreamRemote
.
name
,
candidateBranch
,
exact:
false
));
Version
nextVersion
;
if
(
incrementLetter
==
'm'
)
{
nextVersion
=
Version
.
fromCandidateBranch
(
candidateBranch
);
}
else
{
nextVersion
=
Version
.
increment
(
lastVersion
,
incrementLetter
);
}
state
.
releaseVersion
=
nextVersion
.
toString
();
final
String
frameworkHead
=
framework
.
reverseParse
(
'HEAD'
);
state
.
framework
=
pb
.
Repository
(
candidateBranch:
candidateBranch
,
...
...
@@ -294,20 +324,17 @@ class StartCommand extends Command<void> {
currentGitHead:
frameworkHead
,
checkoutPath:
framework
.
checkoutDirectory
.
path
,
cherrypicks:
frameworkCherrypicks
,
upstream:
pb
.
Remote
(
name:
'upstream'
,
url:
framework
.
upstreamRemote
.
url
),
mirror:
pb
.
Remote
(
name:
'mirror'
,
url:
framework
.
mirrorRemote
.
url
),
);
state
.
lastPhase
=
ReleasePhase
.
INITIALIZE
;
state
.
currentPhase
=
ReleasePhase
.
APPLY_ENGINE_CHERRYPICKS
;
state
.
conductorVersion
=
conductorVersion
;
stdio
.
printTrace
(
'Writing state to file
${stateFile.path}
...'
);
state
.
logs
.
addAll
(
stdio
.
logs
);
stateFile
.
writeAsStringSync
(
jsonEncode
(
state
.
toProto3Json
()),
flush:
true
,
);
writeStateToFile
(
stateFile
,
state
,
stdio
.
logs
);
stdio
.
printStatus
(
presentState
(
state
));
}
...
...
@@ -340,8 +367,8 @@ class StartCommand extends Command<void> {
}
final
String
branchPoint
=
repository
.
branchPoint
(
'
${repository.
fetch
Remote.name}
/
$upstreamRef
'
,
'
${repository.
fetch
Remote.name}
/
$releaseRef
'
,
'
${repository.
upstream
Remote.name}
/
$upstreamRef
'
,
'
${repository.
upstream
Remote.name}
/
$releaseRef
'
,
);
// `git rev-list` returns newest first, so reverse this list
...
...
dev/conductor/lib/state.dart
View file @
c3822edb
...
...
@@ -4,6 +4,9 @@
// @dart = 2.8
import
'dart:convert'
show
jsonDecode
,
jsonEncode
;
import
'package:file/file.dart'
show
File
;
import
'package:platform/platform.dart'
;
import
'./globals.dart'
;
...
...
@@ -37,6 +40,7 @@ String presentState(pb.ConductorState state) {
final
StringBuffer
buffer
=
StringBuffer
();
buffer
.
writeln
(
'Conductor version:
${state.conductorVersion}
'
);
buffer
.
writeln
(
'Release channel:
${state.releaseChannel}
'
);
buffer
.
writeln
(
'Release version:
${state.releaseVersion}
'
);
buffer
.
writeln
(
''
);
buffer
.
writeln
(
'Release started at:
${DateTime.fromMillisecondsSinceEpoch(state.createdDate.toInt())}
'
);
...
...
@@ -76,14 +80,14 @@ String presentState(pb.ConductorState state) {
buffer
.
writeln
(
'0 Framework cherrypicks.'
);
}
buffer
.
writeln
(
''
);
if
(
state
.
las
tPhase
==
ReleasePhase
.
VERIFY_RELEASE
)
{
if
(
state
.
curren
tPhase
==
ReleasePhase
.
VERIFY_RELEASE
)
{
buffer
.
writeln
(
'
${state.releaseChannel}
release
${state.releaseVersion}
has been published and verified.
\n
'
,
);
return
buffer
.
toString
();
}
buffer
.
writeln
(
'The
next step
is:'
);
buffer
.
writeln
(
presentPhases
(
state
.
las
tPhase
));
buffer
.
writeln
(
'The
current phase
is:'
);
buffer
.
writeln
(
presentPhases
(
state
.
curren
tPhase
));
buffer
.
writeln
(
phaseInstructions
(
state
));
buffer
.
writeln
(
''
);
...
...
@@ -91,15 +95,14 @@ String presentState(pb.ConductorState state) {
return
buffer
.
toString
();
}
String
presentPhases
(
ReleasePhase
lastPhase
)
{
final
ReleasePhase
nextPhase
=
getNextPhase
(
lastPhase
);
String
presentPhases
(
ReleasePhase
currentPhase
)
{
final
StringBuffer
buffer
=
StringBuffer
();
bool
phaseCompleted
=
true
;
for
(
final
ReleasePhase
phase
in
ReleasePhase
.
values
)
{
if
(
phase
==
nex
tPhase
)
{
if
(
phase
==
curren
tPhase
)
{
// This phase will execute the next time `conductor next` is run.
buffer
.
writeln
(
'>
${phase.name}
(
nex
t)'
);
buffer
.
writeln
(
'>
${phase.name}
(
curren
t)'
);
phaseCompleted
=
false
;
}
else
if
(
phaseCompleted
)
{
// This phase was already completed.
...
...
@@ -113,8 +116,8 @@ String presentPhases(ReleasePhase lastPhase) {
}
String
phaseInstructions
(
pb
.
ConductorState
state
)
{
switch
(
state
.
las
tPhase
)
{
case
ReleasePhase
.
INITIALIZE
:
switch
(
state
.
curren
tPhase
)
{
case
ReleasePhase
.
APPLY_ENGINE_CHERRYPICKS
:
if
(
state
.
engine
.
cherrypicks
.
isEmpty
)
{
return
<
String
>[
'There are no engine cherrypicks, so issue `conductor next` to continue'
,
...
...
@@ -128,31 +131,33 @@ String phaseInstructions(pb.ConductorState state) {
'
\t
${cherrypick.trunkRevision}
'
,
'See
$kReleaseDocumentationUrl
for more information.'
,
].
join
(
'
\n
'
);
case
ReleasePhase
.
APPLY_ENGINE_CHERRYPICK
S
:
case
ReleasePhase
.
CODESIGN_ENGINE_BINARIE
S
:
return
<
String
>[
'You must verify Engine CI builds are successful and then codesign the'
,
'binaries at revision
${state.engine.currentGitHead}
.'
,
].
join
(
'
\n
'
);
case
ReleasePhase
.
CODESIGN_ENGINE_BINARIES
:
case
ReleasePhase
.
APPLY_FRAMEWORK_CHERRYPICKS
:
final
List
<
pb
.
Cherrypick
>
outstandingCherrypicks
=
state
.
framework
.
cherrypicks
.
where
(
(
pb
.
Cherrypick
cp
)
{
return
cp
.
state
==
pb
.
CherrypickState
.
PENDING
||
cp
.
state
==
pb
.
CherrypickState
.
PENDING_WITH_CONFLICT
;
},
).
toList
();
return
<
String
>[
'You must now manually apply the following framework cherrypicks to the checkout'
,
'at
${state.framework.checkoutPath}
in order:'
,
for
(
final
pb
.
Cherrypick
cherrypick
in
state
.
framework
.
c
herrypicks
)
for
(
final
pb
.
Cherrypick
cherrypick
in
outstandingC
herrypicks
)
'
\t
${cherrypick.trunkRevision}
'
,
].
join
(
'
\n
'
);
case
ReleasePhase
.
APPLY_FRAMEWORK_CHERRYPICKS
:
case
ReleasePhase
.
PUBLISH_VERSION
:
return
<
String
>[
'You must verify Framework CI builds are successful.'
,
'See
$kReleaseDocumentationUrl
for more information.'
,
].
join
(
'
\n
'
);
case
ReleasePhase
.
PUBLISH_VERSION
:
return
'Issue `conductor next` to publish your release to the release branch.'
;
case
ReleasePhase
.
PUBLISH_CHANNEL
:
return
<
String
>[
'Release archive packages must be verified on cloud storage. Issue'
,
'`conductor next` to check if they are ready.'
,
].
join
(
'
\n
'
);
return
'Issue `conductor next` to publish your release to the release branch.'
;
case
ReleasePhase
.
VERIFY_RELEASE
:
return
'Release archive packages must be verified on cloud storage.'
;
case
ReleasePhase
.
RELEASE_COMPLETED
:
return
'This release has been completed.'
;
}
assert
(
false
);
...
...
@@ -161,12 +166,29 @@ String phaseInstructions(pb.ConductorState state) {
/// Returns the next phase in the ReleasePhase enum.
///
/// Will throw a [ConductorException] if [ReleasePhase.RELEASE_
VERIFI
ED] is
/// Will throw a [ConductorException] if [ReleasePhase.RELEASE_
COMPLET
ED] is
/// passed as an argument, as there is no next phase.
ReleasePhase
getNextPhase
(
ReleasePhase
previousPhase
)
{
assert
(
previousPhase
!=
null
);
if
(
previousPhase
==
ReleasePhase
.
VERIFY_RELEASE
)
{
if
(
previousPhase
==
ReleasePhase
.
RELEASE_COMPLETED
)
{
throw
ConductorException
(
'There is no next ReleasePhase!'
);
}
return
ReleasePhase
.
valueOf
(
previousPhase
.
value
+
1
);
}
void
writeStateToFile
(
File
file
,
pb
.
ConductorState
state
,
List
<
String
>
logs
)
{
state
.
logs
.
addAll
(
logs
);
file
.
writeAsStringSync
(
jsonEncode
(
state
.
toProto3Json
()),
flush:
true
,
);
}
pb
.
ConductorState
readStateFromFile
(
File
file
)
{
final
pb
.
ConductorState
state
=
pb
.
ConductorState
();
final
String
stateAsString
=
file
.
readAsStringSync
();
state
.
mergeFromProto3Json
(
jsonDecode
(
stateAsString
),
);
return
state
;
}
dev/conductor/lib/status.dart
View file @
c3822edb
...
...
@@ -4,8 +4,6 @@
// @dart = 2.8
import
'dart:convert'
show
jsonDecode
;
import
'package:args/command_runner.dart'
;
import
'package:file/file.dart'
;
import
'package:meta/meta.dart'
;
...
...
@@ -59,8 +57,8 @@ class StatusCommand extends Command<void> {
'No persistent state file found at
${argResults[kStateOption]}
.'
);
return
;
}
final
pb
.
ConductorState
state
=
pb
.
ConductorState
(
);
state
.
mergeFromProto3Json
(
jsonDecode
(
stateFile
.
readAsStringSync
()));
final
pb
.
ConductorState
state
=
readStateFromFile
(
stateFile
);
stdio
.
printStatus
(
presentState
(
state
));
if
(
argResults
[
kVerboseFlag
]
as
bool
)
{
stdio
.
printStatus
(
'
\n
Logs:'
);
...
...
dev/conductor/lib/version.dart
View file @
c3822edb
...
...
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'./globals.dart'
show
ConductorException
;
/// Possible string formats that `flutter --version` can return.
enum
VersionType
{
/// A stable flutter release.
...
...
@@ -20,12 +22,18 @@ enum VersionType {
///
/// The last number is the number of commits past the last tagged version.
latest
,
/// A master channel flutter version from git describe.
///
/// Example: '1.2.3-4.0.pre-10-gabc123'.
gitDescribe
,
}
final
Map
<
VersionType
,
RegExp
>
versionPatterns
=
<
VersionType
,
RegExp
>{
VersionType
.
stable
:
RegExp
(
r'^(\d+)\.(\d+)\.(\d+)$'
),
VersionType
.
development
:
RegExp
(
r'^(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.pre$'
),
VersionType
.
latest
:
RegExp
(
r'^(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.pre\.(\d+)$'
),
VersionType
.
gitDescribe
:
RegExp
(
r'^(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.pre-(\d+)-g[a-f0-9]+$'
),
};
class
Version
{
...
...
@@ -54,6 +62,10 @@ class Version {
assert
(
n
!=
null
);
assert
(
commits
!=
null
);
break
;
case
VersionType
.
gitDescribe
:
throw
ConductorException
(
'VersionType.gitDescribe not supported! Use VersionType.latest instead.'
,
);
}
}
...
...
@@ -115,6 +127,24 @@ class Version {
type:
VersionType
.
latest
,
);
}
match
=
versionPatterns
[
VersionType
.
gitDescribe
]!.
firstMatch
(
versionString
);
if
(
match
!=
null
)
{
// parse latest
final
List
<
int
>
parts
=
match
.
groups
(
<
int
>[
1
,
2
,
3
,
4
,
5
,
6
],
).
map
(
(
String
?
s
)
=>
int
.
parse
(
s
!),
).
toList
();
return
Version
(
x:
parts
[
0
],
y:
parts
[
1
],
z:
parts
[
2
],
m:
parts
[
3
],
n:
parts
[
4
],
commits:
parts
[
5
],
type:
VersionType
.
latest
,
);
}
throw
Exception
(
'
${versionString.trim()}
cannot be parsed'
);
}
...
...
@@ -131,7 +161,7 @@ class Version {
int
?
nextM
=
previousVersion
.
m
;
int
?
nextN
=
previousVersion
.
n
;
if
(
nextVersionType
==
null
)
{
if
(
previousVersion
.
type
==
VersionType
.
latest
)
{
if
(
previousVersion
.
type
==
VersionType
.
latest
||
previousVersion
.
type
==
VersionType
.
gitDescribe
)
{
nextVersionType
=
VersionType
.
development
;
}
else
{
nextVersionType
=
previousVersion
.
type
;
...
...
@@ -157,10 +187,7 @@ class Version {
nextZ
+=
1
;
break
;
case
'm'
:
// Regular dev release.
assert
(
previousVersion
.
type
==
VersionType
.
development
);
nextM
=
nextM
!
+
1
;
nextN
=
0
;
assert
(
false
,
"Do not increment 'm' via Version.increment, use instead Version.fromCandidateBranch()"
);
break
;
case
'n'
:
// Hotfix to internal roll.
...
...
@@ -179,6 +206,31 @@ class Version {
);
}
factory
Version
.
fromCandidateBranch
(
String
branchName
)
{
// Regular dev release.
final
RegExp
pattern
=
RegExp
(
r'flutter-(\d+)\.(\d+)-candidate.(\d+)'
);
final
RegExpMatch
?
match
=
pattern
.
firstMatch
(
branchName
);
late
final
int
x
;
late
final
int
y
;
late
final
int
m
;
try
{
x
=
int
.
parse
(
match
!.
group
(
1
)!);
y
=
int
.
parse
(
match
.
group
(
2
)!);
m
=
int
.
parse
(
match
.
group
(
3
)!);
}
on
Exception
{
throw
ConductorException
(
'branch named
$branchName
not recognized as a valid candidate branch'
);
}
return
Version
(
type:
VersionType
.
development
,
x:
x
,
y:
y
,
z:
0
,
m:
m
,
n:
0
,
);
}
/// Major version.
final
int
x
;
...
...
@@ -208,6 +260,8 @@ class Version {
return
'
$x
.
$y
.
$z
-
$m
.
$n
.pre'
;
case
VersionType
.
latest
:
return
'
$x
.
$y
.
$z
-
$m
.
$n
.pre.
$commits
'
;
case
VersionType
.
gitDescribe
:
return
'
$x
.
$y
.
$z
-
$m
.
$n
.pre.
$commits
'
;
}
}
}
dev/conductor/test/codesign_test.dart
View file @
c3822edb
...
...
@@ -4,7 +4,6 @@
import
'package:args/command_runner.dart'
;
import
'package:conductor/codesign.dart'
;
import
'package:conductor/globals.dart'
;
import
'package:conductor/repository.dart'
;
import
'package:file/file.dart'
;
import
'package:file/memory.dart'
;
...
...
@@ -16,7 +15,7 @@ import '../../../packages/flutter_tools/test/src/fake_process_manager.dart';
void
main
(
)
{
group
(
'codesign command'
,
()
{
const
String
flutterRoot
=
'/flutter'
;
const
String
checkoutsParentDirectory
=
'
$flutterRoot
/dev/
tools
/'
;
const
String
checkoutsParentDirectory
=
'
$flutterRoot
/dev/
conductor
/'
;
const
String
flutterCache
=
'
${checkoutsParentDirectory}
flutter_conductor_checkouts/framework/bin/cache'
;
const
String
flutterBin
=
...
...
@@ -387,18 +386,13 @@ void main() {
stdout:
'application/x-mach-binary'
,
),
]);
try
{
await
runner
.
run
(<
String
>[
'codesign'
,
'--
$kVerify
'
,
'--no-
$kSignatures
'
,
'--
$kRevision
'
,
revision
,
]);
}
on
ConductorException
{
//print(stdio.error);
rethrow
;
}
await
runner
.
run
(<
String
>[
'codesign'
,
'--
$kVerify
'
,
'--no-
$kSignatures
'
,
'--
$kRevision
'
,
revision
,
]);
expect
(
processManager
.
hasRemainingExpectations
,
false
,
...
...
dev/conductor/test/common.dart
View file @
c3822edb
...
...
@@ -9,6 +9,16 @@ import 'package:test/test.dart';
export
'package:test/test.dart'
hide
isInstanceOf
;
Matcher
throwsAssertionWith
(
String
messageSubString
)
{
return
throwsA
(
isA
<
AssertionError
>().
having
(
(
AssertionError
e
)
=>
e
.
toString
(),
'description'
,
contains
(
messageSubString
),
),
);
}
Matcher
throwsExceptionWith
(
String
messageSubString
)
{
return
throwsA
(
isA
<
Exception
>().
having
(
...
...
@@ -28,11 +38,12 @@ class TestStdio extends Stdio {
String
get
error
=>
logs
.
where
((
String
log
)
=>
log
.
startsWith
(
r'[error] '
)).
join
(
'
\n
'
);
String
get
stdout
=>
logs
.
where
((
String
log
)
{
return
log
.
startsWith
(
r'[status] '
)
||
log
.
startsWith
(
r'[trace] '
);
return
log
.
startsWith
(
r'[status] '
)
||
log
.
startsWith
(
r'[trace] '
)
||
log
.
startsWith
(
r'[write] '
)
;
}).
join
(
'
\n
'
);
final
bool
verbose
;
late
final
List
<
String
>
_stdin
;
List
<
String
>
get
stdin
=>
_stdin
;
@override
String
readLineSync
()
{
...
...
@@ -46,7 +57,7 @@ class TestStdio extends Stdio {
class
FakeArgResults
implements
ArgResults
{
FakeArgResults
({
required
String
level
,
required
String
c
ommit
,
required
String
c
andidateBranch
,
String
remote
=
'upstream'
,
bool
justPrint
=
false
,
bool
autoApprove
=
true
,
// so we don't have to mock stdin
...
...
@@ -55,7 +66,7 @@ class FakeArgResults implements ArgResults {
bool
skipTagging
=
false
,
})
:
_parsedArgs
=
<
String
,
dynamic
>{
'increment'
:
level
,
'c
ommit'
:
commit
,
'c
andidate-branch'
:
candidateBranch
,
'remote'
:
remote
,
'just-print'
:
justPrint
,
'yes'
:
autoApprove
,
...
...
dev/conductor/test/next_test.dart
0 → 100644
View file @
c3822edb
This diff is collapsed.
Click to expand it.
dev/conductor/test/roll_dev_integration_test.dart
deleted
100644 → 0
View file @
567586b4
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:conductor/repository.dart'
;
import
'package:conductor/roll_dev.dart'
show
rollDev
;
import
'package:conductor/version.dart'
;
import
'package:file/file.dart'
;
import
'package:file/local.dart'
;
import
'package:platform/platform.dart'
;
import
'package:process/process.dart'
;
import
'./common.dart'
;
void
main
(
)
{
group
(
'roll-dev'
,
()
{
late
TestStdio
stdio
;
late
Platform
platform
;
late
ProcessManager
processManager
;
late
FileSystem
fileSystem
;
const
String
usageString
=
'Usage: flutter conductor.'
;
late
Checkouts
checkouts
;
late
FrameworkRepository
frameworkUpstream
;
late
FrameworkRepository
framework
;
late
Directory
tempDir
;
setUp
(()
{
platform
=
const
LocalPlatform
();
fileSystem
=
const
LocalFileSystem
();
processManager
=
const
LocalProcessManager
();
stdio
=
TestStdio
(
verbose:
true
);
tempDir
=
fileSystem
.
systemTempDirectory
.
createTempSync
(
'flutter_conductor_checkouts.'
);
checkouts
=
Checkouts
(
fileSystem:
fileSystem
,
parentDirectory:
tempDir
,
platform:
platform
,
processManager:
processManager
,
stdio:
stdio
,
);
frameworkUpstream
=
FrameworkRepository
(
checkouts
,
localUpstream:
true
);
// This repository has [frameworkUpstream] set as its push/pull remote.
framework
=
FrameworkRepository
(
checkouts
,
name:
'test-framework'
,
fetchRemote:
Remote
(
name:
RemoteName
.
upstream
,
url:
'file://
${frameworkUpstream.checkoutDirectory.path}
/'
),
);
});
test
(
'increment m'
,
()
{
final
Version
initialVersion
=
framework
.
flutterVersion
();
final
String
latestCommit
=
framework
.
authorEmptyCommit
();
final
FakeArgResults
fakeArgResults
=
FakeArgResults
(
level:
'm'
,
commit:
latestCommit
,
// Ensure this test passes after a dev release with hotfixes
force:
true
,
remote:
'upstream'
,
);
expect
(
rollDev
(
usage:
usageString
,
argResults:
fakeArgResults
,
stdio:
stdio
,
repository:
framework
,
),
true
,
);
expect
(
stdio
.
stdout
,
contains
(
RegExp
(
r'Publishing Flutter \d+\.\d+\.\d+-\d+\.\d+\.pre \('
)),
);
final
Version
finalVersion
=
framework
.
flutterVersion
();
expect
(
initialVersion
.
toString
()
!=
finalVersion
.
toString
(),
true
,
reason:
'initialVersion =
$initialVersion
; finalVersion =
$finalVersion
'
,
);
expect
(
finalVersion
.
n
,
0
);
expect
(
finalVersion
.
commits
,
null
);
});
},
onPlatform:
<
String
,
dynamic
>{
'windows'
:
const
Skip
(
'Flutter Conductor only supported on macos/linux'
),
});
}
dev/conductor/test/roll_dev_test.dart
View file @
c3822edb
...
...
@@ -20,7 +20,8 @@ void main() {
const
String
commit
=
'abcde012345'
;
const
String
remote
=
'origin'
;
const
String
lastVersion
=
'1.2.0-0.0.pre'
;
const
String
nextVersion
=
'1.2.0-1.0.pre'
;
const
String
nextVersion
=
'1.2.0-2.0.pre'
;
const
String
candidateBranch
=
'flutter-1.2-candidate.2'
;
const
String
checkoutsParentDirectory
=
'/path/to/directory/'
;
FakeArgResults
fakeArgResults
;
MemoryFileSystem
fileSystem
;
...
...
@@ -45,37 +46,20 @@ void main() {
repo
=
FrameworkRepository
(
checkouts
);
});
test
(
'
returns false
if level not provided'
,
()
{
test
(
'
throws Exception
if level not provided'
,
()
{
fakeArgResults
=
FakeArgResults
(
level:
null
,
c
ommit:
commit
,
c
andidateBranch:
candidateBranch
,
remote:
remote
,
);
expect
(
rollDev
(
argResults:
fakeArgResults
,
repository:
repo
,
stdio:
stdio
,
usage:
usage
,
),
false
,
);
});
test
(
'returns false if commit not provided'
,
()
{
fakeArgResults
=
FakeArgResults
(
level:
level
,
commit:
null
,
remote:
remote
,
);
expect
(
rollDev
(
()
=>
rollDev
(
argResults:
fakeArgResults
,
repository:
repo
,
stdio:
stdio
,
usage:
usage
,
),
false
,
throwsExceptionWith
(
usage
)
,
);
});
...
...
@@ -109,24 +93,18 @@ void main() {
]);
fakeArgResults
=
FakeArgResults
(
level:
level
,
c
ommit:
commit
,
c
andidateBranch:
candidateBranch
,
remote:
remote
,
);
Exception
exception
;
try
{
rollDev
(
expect
(
()
=>
rollDev
(
argResults:
fakeArgResults
,
repository:
repo
,
stdio:
stdio
,
usage:
usage
,
);
}
on
Exception
catch
(
e
)
{
exception
=
e
;
}
const
String
pattern
=
r'Your git repository is not clean. Try running '
'"git clean -fd". Warning, this will delete files! Run with -n to find '
'out which ones.'
;
expect
(
exception
?.
toString
(),
contains
(
pattern
));
),
throwsExceptionWith
(
'Your git repository is not clean.'
),
);
});
test
(
'does not reset or tag if --just-print is specified'
,
()
{
...
...
@@ -165,13 +143,13 @@ void main() {
const
FakeCommand
(
command:
<
String
>[
'git'
,
'rev-parse'
,
c
ommit
,
c
andidateBranch
,
],
stdout:
commit
),
const
FakeCommand
(
command:
<
String
>[
'git'
,
'describe'
,
'--match'
,
'*.*.*
-*.*.pre
'
,
'*.*.*'
,
'--exact-match'
,
'--tags'
,
'refs/remotes/
$remote
/dev'
,
...
...
@@ -185,7 +163,7 @@ void main() {
fakeArgResults
=
FakeArgResults
(
level:
level
,
c
ommit:
commit
,
c
andidateBranch:
candidateBranch
,
remote:
remote
,
justPrint:
true
,
);
...
...
@@ -237,13 +215,13 @@ void main() {
const
FakeCommand
(
command:
<
String
>[
'git'
,
'rev-parse'
,
c
ommit
,
c
andidateBranch
,
],
stdout:
commit
),
const
FakeCommand
(
command:
<
String
>[
'git'
,
'describe'
,
'--match'
,
'*.*.*
-*.*.pre
'
,
'*.*.*'
,
'--exact-match'
,
'--tags'
,
'refs/remotes/
$remote
/dev'
,
...
...
@@ -268,7 +246,7 @@ void main() {
fakeArgResults
=
FakeArgResults
(
level:
level
,
c
ommit:
commit
,
c
andidateBranch:
candidateBranch
,
remote:
remote
,
skipTagging:
true
,
);
...
...
@@ -319,13 +297,13 @@ void main() {
const
FakeCommand
(
command:
<
String
>[
'git'
,
'rev-parse'
,
c
ommit
,
c
andidateBranch
,
],
stdout:
commit
),
const
FakeCommand
(
command:
<
String
>[
'git'
,
'describe'
,
'--match'
,
'*.*.*
-*.*.pre
'
,
'*.*.*'
,
'--exact-match'
,
'--tags'
,
'refs/remotes/
$remote
/dev'
,
...
...
@@ -339,7 +317,7 @@ void main() {
]);
fakeArgResults
=
FakeArgResults
(
level:
level
,
c
ommit:
commit
,
c
andidateBranch:
candidateBranch
,
remote:
remote
,
justPrint:
true
,
);
...
...
@@ -394,13 +372,13 @@ void main() {
const
FakeCommand
(
command:
<
String
>[
'git'
,
'rev-parse'
,
c
ommit
,
c
andidateBranch
,
],
stdout:
commit
),
const
FakeCommand
(
command:
<
String
>[
'git'
,
'describe'
,
'--match'
,
'*.*.*
-*.*.pre
'
,
'*.*.*'
,
'--exact-match'
,
'--tags'
,
'refs/remotes/
$remote
/dev'
,
...
...
@@ -421,7 +399,7 @@ void main() {
fakeArgResults
=
FakeArgResults
(
level:
level
,
c
ommit:
commit
,
c
andidateBranch:
candidateBranch
,
remote:
remote
,
);
const
String
errorMessage
=
'The previous dev tag
$lastVersion
is not a '
...
...
@@ -473,13 +451,13 @@ void main() {
const
FakeCommand
(
command:
<
String
>[
'git'
,
'rev-parse'
,
c
ommit
,
c
andidateBranch
,
],
stdout:
commit
),
const
FakeCommand
(
command:
<
String
>[
'git'
,
'describe'
,
'--match'
,
'*.*.*
-*.*.pre
'
,
'*.*.*'
,
'--exact-match'
,
'--tags'
,
'refs/remotes/
$remote
/dev'
,
...
...
@@ -517,7 +495,7 @@ void main() {
]);
fakeArgResults
=
FakeArgResults
(
level:
level
,
c
ommit:
commit
,
c
andidateBranch:
candidateBranch
,
remote:
remote
,
skipTagging:
true
,
);
...
...
@@ -568,13 +546,13 @@ void main() {
const
FakeCommand
(
command:
<
String
>[
'git'
,
'rev-parse'
,
c
ommit
,
c
andidateBranch
,
],
stdout:
commit
),
const
FakeCommand
(
command:
<
String
>[
'git'
,
'describe'
,
'--match'
,
'*.*.*
-*.*.pre
'
,
'*.*.*'
,
'--exact-match'
,
'--tags'
,
'refs/remotes/
$remote
/dev'
,
...
...
@@ -617,7 +595,7 @@ void main() {
]);
fakeArgResults
=
FakeArgResults
(
level:
level
,
c
ommit:
commit
,
c
andidateBranch:
candidateBranch
,
remote:
remote
,
);
expect
(
...
...
@@ -667,13 +645,13 @@ void main() {
const
FakeCommand
(
command:
<
String
>[
'git'
,
'rev-parse'
,
c
ommit
,
c
andidateBranch
,
],
stdout:
commit
),
const
FakeCommand
(
command:
<
String
>[
'git'
,
'describe'
,
'--match'
,
'*.*.*
-*.*.pre
'
,
'*.*.*'
,
'--exact-match'
,
'--tags'
,
'refs/remotes/
$remote
/dev'
,
...
...
@@ -711,7 +689,7 @@ void main() {
fakeArgResults
=
FakeArgResults
(
level:
level
,
c
ommit:
commit
,
c
andidateBranch:
candidateBranch
,
remote:
remote
,
force:
true
,
);
...
...
dev/conductor/test/start_test.dart
View file @
c3822edb
...
...
@@ -122,6 +122,8 @@ void main() {
const
String
revision3
=
'123abc'
;
const
String
previousDartRevision
=
'171876a4e6cf56ee6da1f97d203926bd7afda7ef'
;
const
String
nextDartRevision
=
'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'
;
const
String
previousVersion
=
'1.2.0-1.0.pre'
;
const
String
nextVersion
=
'1.2.0-3.0.pre'
;
final
Directory
engine
=
fileSystem
.
directory
(
checkoutsParentDirectory
)
.
childDirectory
(
'flutter_conductor_checkouts'
)
...
...
@@ -182,6 +184,7 @@ void main() {
stdout:
revision2
,
),
];
final
List
<
FakeCommand
>
frameworkCommands
=
<
FakeCommand
>[
FakeCommand
(
command:
<
String
>[
...
...
@@ -219,11 +222,23 @@ void main() {
'cherrypicks-
$candidateBranch
'
,
],
),
const
FakeCommand
(
command:
<
String
>[
'git'
,
'describe'
,
'--match'
,
'*.*.*'
,
'--tags'
,
'refs/remotes/upstream/
$candidateBranch
'
,
],
stdout:
'
$previousVersion
-42-gabc123'
,
),
const
FakeCommand
(
command:
<
String
>[
'git'
,
'rev-parse'
,
'HEAD'
],
stdout:
revision3
,
),
];
final
CommandRunner
<
void
>
runner
=
createRunner
(
commands:
<
FakeCommand
>[
const
FakeCommand
(
...
...
@@ -254,6 +269,8 @@ void main() {
stateFilePath
,
'--
$kDartRevisionOption
'
,
nextDartRevision
,
'--
$kIncrementOption
'
,
'm'
,
]);
final
File
stateFile
=
fileSystem
.
file
(
stateFilePath
);
...
...
@@ -265,12 +282,13 @@ void main() {
expect
(
state
.
isInitialized
(),
true
);
expect
(
state
.
releaseChannel
,
releaseChannel
);
expect
(
state
.
releaseVersion
,
nextVersion
);
expect
(
state
.
engine
.
candidateBranch
,
candidateBranch
);
expect
(
state
.
engine
.
startingGitHead
,
revision2
);
expect
(
state
.
engine
.
dartRevision
,
nextDartRevision
);
expect
(
state
.
framework
.
candidateBranch
,
candidateBranch
);
expect
(
state
.
framework
.
startingGitHead
,
revision3
);
expect
(
state
.
lastPhase
,
ReleasePhase
.
INITIALIZE
);
expect
(
state
.
currentPhase
,
ReleasePhase
.
APPLY_ENGINE_CHERRYPICKS
);
expect
(
state
.
conductorVersion
,
revision
);
});
},
onPlatform:
<
String
,
dynamic
>{
...
...
dev/conductor/test/version_test.dart
View file @
c3822edb
...
...
@@ -44,29 +44,26 @@ void main() {
});
test
(
'successfully increments z'
,
()
{
const
String
level
=
'
m
'
;
const
String
level
=
'
z
'
;
Version
version
=
Version
.
fromString
(
'1.0.0
-0.0.pre
'
);
expect
(
Version
.
increment
(
version
,
level
).
toString
(),
'1.0.
0-1.0.pre
'
);
Version
version
=
Version
.
fromString
(
'1.0.0'
);
expect
(
Version
.
increment
(
version
,
level
).
toString
(),
'1.0.
1
'
);
version
=
Version
.
fromString
(
'10.20.0
-40.50.pre
'
);
expect
(
Version
.
increment
(
version
,
level
).
toString
(),
'10.20.
0-41.0.pre
'
);
version
=
Version
.
fromString
(
'10.20.0'
);
expect
(
Version
.
increment
(
version
,
level
).
toString
(),
'10.20.
1
'
);
version
=
Version
.
fromString
(
'1.18.
0-3.0.pre
'
);
expect
(
Version
.
increment
(
version
,
level
).
toString
(),
'1.18.
0-4.0.pre
'
);
version
=
Version
.
fromString
(
'1.18.
3
'
);
expect
(
Version
.
increment
(
version
,
level
).
toString
(),
'1.18.
4
'
);
});
test
(
'
successfully increments
m'
,
()
{
test
(
'
does not support incrementing
m'
,
()
{
const
String
level
=
'm'
;
Version
version
=
Version
.
fromString
(
'1.0.0-0.0.pre'
);
expect
(
Version
.
increment
(
version
,
level
).
toString
(),
'1.0.0-1.0.pre'
);
version
=
Version
.
fromString
(
'10.20.0-40.50.pre'
);
expect
(
Version
.
increment
(
version
,
level
).
toString
(),
'10.20.0-41.0.pre'
);
version
=
Version
.
fromString
(
'1.18.0-3.0.pre'
);
expect
(
Version
.
increment
(
version
,
level
).
toString
(),
'1.18.0-4.0.pre'
);
final
Version
version
=
Version
.
fromString
(
'1.0.0-0.0.pre'
);
expect
(
()
=>
Version
.
increment
(
version
,
level
).
toString
(),
throwsAssertionWith
(
"Do not increment 'm' via Version.increment"
),
);
});
test
(
'successfully increments n'
,
()
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment