blob: 592934ea2f29037627aa459502f7bb060a70b96e [file] [log] [blame]
// Copyright 2019 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:gcloud/db.dart';
import 'package:github/github.dart';
import 'package:json_annotation/json_annotation.dart';
import '../../service/datastore.dart';
import '../../service/logging.dart';
import 'key_converter.dart';
part 'commit.g.dart';
/// Class that represents a commit that has landed on the master branch of a
/// Flutter repository.
@Kind(name: 'Checklist', idType: IdType.String)
class Commit extends Model<String> {
Commit({
Key<String>? key,
this.sha,
this.timestamp,
this.author,
this.authorAvatarUrl,
this.message,
this.repository,
this.branch = 'master',
}) {
parentKey = key?.parent;
id = key?.id;
}
/// Create a [Key] that can be used to lookup a [Commit] from Datastore.
static Key<String> createKey({
required DatastoreDB db,
required RepositorySlug slug,
required String gitBranch,
required String sha,
}) {
return db.emptyKey.append(
Commit,
id: '${slug.fullName}/$gitBranch/$sha',
);
}
/// Lookup [Commit] from Datastore.
static Future<Commit> fromDatastore({
required DatastoreService datastore,
required Key<String> key,
}) async {
log.fine('Looking up commit by key with id: ${key.id}');
return datastore.lookupByValue<Commit>(key);
}
/// The timestamp (in milliseconds since the Epoch) of when the commit
/// landed.
@IntProperty(propertyName: 'CreateTimestamp', required: true)
int? timestamp;
/// The SHA1 hash of the commit.
@StringProperty(propertyName: 'Commit.Sha', required: true)
String? sha;
/// The GitHub username of the commit author.
@StringProperty(propertyName: 'Commit.Author.Login')
String? author;
/// URL of the [author]'s profile image / avatar.
///
/// The bytes loaded from the URL are expected to be encoded image bytes.
@StringProperty(propertyName: 'Commit.Author.AvatarURL')
String? authorAvatarUrl;
/// The commit message.
///
/// This may be null, since we didn't always load/store this property in
/// the datastore, so historical entries won't have this information.
@StringProperty(propertyName: 'Commit.Message', required: false)
String? message;
/// A serializable form of [slug].
///
/// This will be of the form `<org>/<repo>`. e.g. `flutter/flutter`.
@StringProperty(propertyName: 'FlutterRepositoryPath', required: true)
String? repository;
/// The branch of the commit.
@StringProperty(propertyName: 'Branch')
String? branch;
/// [RepositorySlug] of where this commit exists.
RepositorySlug get slug => RepositorySlug.full(repository!);
@override
String toString() {
final StringBuffer buf = StringBuffer()
..write('$runtimeType(')
..write('id: $id')
..write(', parentKey: ${parentKey?.id}')
..write(', key: ${parentKey == null ? null : key.id}')
..write(', timestamp: $timestamp')
..write(', sha: $sha')
..write(', author: $author')
..write(', authorAvatarUrl: $authorAvatarUrl')
..write(', message: ${message?.split("\n").first}')
..write(', repository: $repository')
..write(', branch: $branch')
..write(')');
return buf.toString();
}
}
/// The serialized representation of a [Commit].
// TODO(tvolkert): Directly serialize [Commit] once frontends migrate to new serialization format.
@JsonSerializable(createFactory: false, ignoreUnannotated: true)
class SerializableCommit {
const SerializableCommit(this.commit);
final Commit commit;
@JsonKey(name: 'Key')
@StringKeyConverter()
Key<String>? get key => commit.key;
@JsonKey(name: 'Checklist')
Map<String, dynamic> get facade {
return <String, dynamic>{
'FlutterRepositoryPath': commit.repository,
'CreateTimestamp': commit.timestamp,
'Commit': <String, dynamic>{
'Sha': commit.sha,
'Message': commit.message,
'Author': <String, dynamic>{
'Login': commit.author,
'avatar_url': commit.authorAvatarUrl,
},
},
'Branch': commit.branch,
};
}
/// Serializes this object to a JSON primitive.
Map<String, dynamic> toJson() => _$SerializableCommitToJson(this);
}