Skip to content

Commit

Permalink
dev.1
Browse files Browse the repository at this point in the history
  • Loading branch information
f3ath committed Jul 24, 2020
1 parent 66d6dc7 commit 81614d3
Show file tree
Hide file tree
Showing 36 changed files with 901 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .cider.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
changelog:
diff_link_template: 'https://github.com/f3ath/cider/compare/%from%...%to%'
24 changes: 24 additions & 0 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Dart CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:

runs-on: ubuntu-latest

container:
image: google/dart:latest

steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: pub get
- name: Analyzer
run: dartanalyzer lib test example --fatal-infos --fatal-warnings
- name: Tests
run: pub run test
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## 0.0.0+dev.1 - 2020-07-23
### Added
- Initial version

[Unreleased]: https://github.com/f3ath/cider/compare/0.0.0+dev.1...HEAD
89 changes: 87 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,87 @@
# dart-ci
Tools for Dart package maintainers
# CIDER (CI for Dart. Efficient Releases)
A command-line utility to automate package maintenance. It manipulates the changelog and pubspec.yaml.

This tool assumes that the changelog:
- is called `CHANGELOG.md`
- is sitting in the project root folder
- strictly follows the [Keep a Changelog v1.0.0](https://keepachangelog.com/en/1.0.0/) format
- uses basic markdown (no HTML and complex formatting supported)

It also assumes that your project follows [Semantic Versioning v2.0.0](https://semver.org/spec/v2.0.0.html).

## Install
```
pub global activate cider
```

## Usage
### Logging changes to CHANGELOG
This command will add a new line to the `Unreleased` section of the changelog
```
cider log <type> <description>
```
- **type** is one of: `added`, `changed`, `deprecated`, `removed`, `fixed`, `security`
- **description** is a markdown text line

Examples
```
cider log change 'New turbo engine installed'
cider log add 'Support for rocket fuel and kerosene'
cider log fix 'No more wheels falling off'
```

### Bumping the project version
```
cider bump <version>
```
- **version** can be any of: `breaking`, `major`, `minor`, `patch`, `build`

Use `--keep-build` or `-b` to retain the build part of the version.

Use `--print` or `-p` to print the new version.

Version before | Command | Version after
--- | --- | ---
1.2.3 | `cider bump breaking` | 2.0.0
0.2.1 | `cider bump breaking` | 0.3.0
0.2.1 | `cider bump major` | 1.0.0
0.2.1 | `cider bump minor` | 0.3.0
0.2.1 | `cider bump patch` | 0.2.2
0.2.1 | `cider bump build` | 0.2.1+1
0.2.1+42 | `cider bump build` | 0.2.1+43
0.2.1+foo | `cider bump build` | 0.2.1+foo.1
0.2.1+42.foo | `cider bump build` | 0.2.1+43.foo
0.2.1+foo.bar.1.2 | `cider bump build` | 0.2.1+foo.bar.2.0

The `cider bump build` command is a bit tricky. It either increments the first numeric part of the build (if there is a
numeric part) setting other numeric parts to zeroes, or appends `.1` to the build (otherwise).

Retaining the build part:

Version before | Command | Version after
--- | --- | ---
1.2.3+42 | `cider bump breaking` | 2.0.0
0.2.1+42 | `cider bump breaking -b` | 0.3.0+42
0.2.1+42 | `cider bump patch` | 0.2.2
0.2.1+42 | `cider bump patch -b` | 0.2.2+42

### Releasing the unreleased changes
This command takes all changes from the `Unreleased` section on the changelog and creates a new release with the
version from pubspec.yaml

```
cider release
```

Use `--date` to provide the release date (the default is today).

### Printing the current project version
```
cider version
```

### Printing the list of changes in a given version
```
cider print <version>
```
- **version** is an existing version from the changelog
5 changes: 5 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
include: package:pedantic/analysis_options.yaml
linter:
rules:
- sort_constructors_first
- sort_unnamed_constructors_first
6 changes: 6 additions & 0 deletions bin/cider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import 'dart:io';

import 'package:cider/cider.dart';

void main(List<String> args) async => exit(
(await ConsoleApplication('cider').run(args)) ?? ExitCode.missingArgument);
1 change: 1 addition & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Please see the README.md in the project root.
3 changes: 3 additions & 0 deletions lib/cider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export 'package:cider/src/console/console.dart';
export 'package:cider/src/console/console_application.dart';
export 'package:cider/src/console/exit_code.dart';
62 changes: 62 additions & 0 deletions lib/src/application.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'dart:io';

import 'package:change/model.dart';
import 'package:cider/src/application_exception.dart';
import 'package:cider/src/changelog_file.dart';
import 'package:cider/src/config.dart';
import 'package:cider/src/pubspec_file.dart';
import 'package:marker/flavors.dart' as flavors;
import 'package:marker/marker.dart';
import 'package:maybe_just_nothing/maybe_just_nothing.dart';
import 'package:path/path.dart';
import 'package:version_manipulation/mutations.dart';

class Application {
Application({String projectRoot = '.'})
: _pubspec = PubspecFile(projectRoot),
_changelogFile = ChangelogFile(projectRoot),
_config = Config.readFile(File(join(projectRoot, '.cider.yaml')));

final PubspecFile _pubspec;
final ChangelogFile _changelogFile;
final Config _config;

void logChange(ChangeType type, String text) =>
_changelogFile.update((changelog) {
changelog.unreleased.changes.addText(type, text);
return changelog;
});

String bump(VersionMutation mutation) {
final current = _pubspec.readVersion();
final updated = mutation(current);
_pubspec.writeVersion(updated);
return updated.toString();
}

void release(String date) {
final version = _pubspec.readVersion().toString();
_changelogFile.update((changelog) {
if (changelog.releases.any((release) => release.version == version)) {
throw ApplicationException('Release already exists');
}
changelog.release(version, date, link: _config.diffLinkTemplate.or(''));
return changelog;
});
}

/// Reads the current project version from pubspec.yaml
String readVersion() => _pubspec.readVersion().toString();

/// Reads the markdown description for the given release
String describe([String version]) {
final changelog = _changelogFile.read();
if (changelog.releases.isEmpty) throw 'No releases found in CHANGELOG';
final release = Maybe(version)
.map((ver) => changelog.releases.firstWhere(
(release) => release.version == ver,
orElse: () => throw 'Version $ver not found'))
.or(changelog.releases.last);
return render(release.toMarkdown(), flavor: flavors.changelog);
}
}
8 changes: 8 additions & 0 deletions lib/src/application_exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class ApplicationException implements Exception {
ApplicationException(this.message);

final String message;

@override
String toString() => message;
}
24 changes: 24 additions & 0 deletions lib/src/changelog_file.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'dart:io';

import 'package:change/model.dart';
import 'package:path/path.dart';

class ChangelogFile {
ChangelogFile(this._dir);

static final name = 'CHANGELOG.md';

final String _dir;

/// Updates the changelog in-place
void update(Changelog Function(Changelog changelog) mutate) =>
_write(mutate(read()));

/// Reads the changelog from file
Changelog read() => Changelog.fromLines(
(_file..createSync(recursive: true)).readAsLinesSync());

void _write(Changelog changelog) => _file.writeAsStringSync(changelog.dump());

File get _file => File(join(_dir, name));
}
22 changes: 22 additions & 0 deletions lib/src/config.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'dart:io';

import 'package:maybe_just_nothing/maybe_just_nothing.dart';
import 'package:yaml/yaml.dart';

class Config {
Config(this._data);

static Config readFile(File file) {
if (!file.existsSync()) return Config(YamlMap());
final yaml = loadYaml(file.readAsStringSync()) ?? YamlMap();
if (yaml is YamlMap) return Config(yaml);
throw 'Invalid config format';
}

final YamlMap _data;

Maybe<String> get diffLinkTemplate => Maybe(_data['changelog'])
.type<Map>()
.map((_) => _['diff_link_template'])
.type<String>();
}
7 changes: 7 additions & 0 deletions lib/src/console/command/application_command.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'package:args/command_runner.dart';
import 'package:cider/src/application.dart';

abstract class ApplicationCommand extends Command<int> {
Application createApp() =>
Application(projectRoot: globalResults['project-root']);
}
44 changes: 44 additions & 0 deletions lib/src/console/command/bump_command.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'package:cider/src/console/command/application_command.dart';
import 'package:cider/src/console/console.dart';
import 'package:cider/src/console/exit_code.dart';
import 'package:version_manipulation/mutations.dart';

class BumpCommand extends ApplicationCommand {
BumpCommand(this.name, this.mutation, this._console) {
argParser
// ..addOption('date',
// help: 'Release date',
// defaultsTo: DateFormat('y-MM-dd').format(DateTime.now()))
..addFlag('print',
help: 'Prints the updated version', abbr: 'p', defaultsTo: false)
..addFlag('keep-build',
help: 'Keeps the build part of the version',
abbr: 'b',
defaultsTo: false);
}

final Console _console;

@override
String get description => 'Bumps the $name version';

@override
final name;
final VersionMutation mutation;

@override
int run() {
final app = createApp();
final keepBuild = argResults['keep-build'];
try {
final updated= app.bump(keepBuild ? KeepBuild(mutation) : mutation);
if (argResults['print']) _console.log(updated);
// app.release(
// keepBuild ? KeepBuild(mutation) : mutation, argResults['date']);
return ExitCode.ok;
} catch (e) {
_console.error(e);
return ExitCode.applicationError;
}
}
}
27 changes: 27 additions & 0 deletions lib/src/console/command/describe_command.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:cider/cider.dart';
import 'package:cider/src/console/command/application_command.dart';
import 'package:cider/src/console/console.dart';

class DescribeCommand extends ApplicationCommand {
DescribeCommand(this._console);

final Console _console;
@override
final description = 'Prints the changelog entry for the given version';

@override
final name = 'describe';

@override
final aliases = ['desc'];

@override
int run() {
if (argResults.rest.isEmpty) {
_console.log(createApp().describe());
} else {
_console.log(createApp().describe(argResults.rest.single));
}
return ExitCode.ok;
}
}
31 changes: 31 additions & 0 deletions lib/src/console/command/log_change_command.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'package:change/model.dart';
import 'package:cider/cider.dart';
import 'package:cider/src/console/command/application_command.dart';
import 'package:cider/src/console/console.dart';

class LogChangeCommand extends ApplicationCommand {
LogChangeCommand(
this.name, this.aliases, this.description, this._type, this._console);

final Console _console;

final ChangeType _type;

@override
final String description;
@override
final String name;
@override
final List<String> aliases;

@override
int run() {
if (argResults.rest.isEmpty) {
_console.error('Please specify the change description');
return ExitCode.missingArgument;
}
final app = createApp();
app.logChange(_type, argResults.rest.first);
return ExitCode.ok;
}
}
Loading

0 comments on commit 81614d3

Please sign in to comment.