Fresher: Keeps Projects Up to Date

SDK version Supported platforms Supported SDKs

Cover - Fresher: Keeps Projects Up to Date

GitHub License Pub Package Code Size Publisher

Build Status Pull Requests Issues Pub Score

An invisible (means that maintenance packages are not aware of this tool) tool to help keep your multiple projects in multiple repositories up to date: automated upgrade dependencies, update links and sections in README, CONTRIBUTING, STYLEGUIDE, wiki, etc. The easy-to-use and well-tested Dart CLI. Feel free to use it in your awesome project.

CodeFactor

Share some ❤️ and star repo to support the Fresher: Keeps Projects Up to Date.

If you write an article about Fresher or any of these packages, let me know and I'll post the URL of the article in the README 🤝

🔥 Motivation

The road to 🖤 is paved with good intentions.

I just wanted to show in the READMEs of my packages how to contribute to open-source, because I remember how hard it was to start doing that for me. The problem was that when the thought came to my mind, I already had dozens packages in pub.dev... Well, I did it manually that time.

After seeing the shields in other packages (thanks for that, guys and gals) and wanting to add them to my packages too... And this time I did it by hand.

One sunny afternoon I read on Reddit that people are looking for projects to help the open-source community, and I read in the comments about CodeTriangle - Free community tools for contributing... And that time I did it by hand for some of my packages.

When I came across resources like The ultimate Flutter resources and Learn Dart in Y minutes, I wanted to add them too because both Dart and Flutter are really 🌟 awesome.

More packages were added, and more time was spent on updating them. Should I go on?

Honestly, I didn't want to create this package because I realized the complexity and I heard: "Melos / Cider / Publish Tools / Sidekick will solve your problems with Dart / Flutter package maintenance". I spent ~2 weeks researching the available tools and I've tabulated my research below.

📊 Research

The purpose of the project Fresher is to "keep packages up to date", so I wrote out features for that purpose and for those purposes that seemed to be needed in the future.

Cider Fresher Melos PublishTools Sidekick
Analyze Dart code
Commit to GitHub
Create meta.dart
Custom scripts
Format Dart code
Generate documentation
Git log output
Keep CHANGELOG up to date
Keep README up to date
Keep other files up to date
📗 Monorepos
📚 Multirepos
Publish to pub.dev
Setting version
Upgrade dependencies

I guess now you will be able to choose the right tool for your needs much faster.

🌟 Features

The Fresher has significant differences from researched products:

  1. Invisible to maintained projects. You can update your awesome projects with Fresher and then switch to another tool(s) or even drop the tools altogether and not even notice it: Fresher doesn't make a single change to the configuration of your projects. So if you decide to stop using Fresher, you could still manage your projects. But you lose the automation and all the magic 🪄️

  2. Freedom to choose the structure and variables for your projects. Below I'll show you what I chose, but my solution is not the only possible one.

It can do the following:

  1. Updates any folders and files from 3 tiers - root, sdk and project - inheriting changes.

  2. Upgrades pubspec.yaml files with resolvable versions.

  3. Displays the git logs of the supported projects after the first 2 steps.

  4. Keeps up to date (maintains) multiple projects with multiple repositories (multirepos).

That's all I needed. I have upgraded all my packages and am enjoying working with this functionality.

The Fresher got 2 more unplanned uses:

  1. It can be used for keep any your libraries up to date: GitHub, npm, PyPi, Maven, NuGet, RubyGems, etc.

  2. You can use Fresher to build any template with any complex folder-file-content structure.

And it has limitation:

  • All maintained projects must be placed in the same folder as fresher.

🚀 Usage

Please, read the Features above before reading Usage.

Let's take a look at this folder structure:

Root folders of any Dart project

I am using VS Code, so forgive me these screenshots if you are using a different IDE.

Above we have seen the root structure of any Dart project, haven't we?

So in our base, we see the following folders:

Root folders for base

Which includes:

Folders
+
files & folders to be copied
Files for add from root base
dart
projects on Dart
Files for add from Dart SDK base
flutter
projects on Flutter
Files for add from Flutter SDK base

This is a project structure, SDKs, and our (ok, mine) maintaned projects.

All files in the folder + will be copied to each maintaned project.

Take a look inside id_gen folder:

Folder
id_gen
the project
Files for add from id_gen Dart SDK base

As you see, we keep the same file structure as for any Dart project with additional folder +README.md (yes, it's a folder) and +.yaml file.

Take a look at the file id_gen/+/+.yaml (a project tier):

variables:
  project_id: id_gen
  project_title: IdGen
  project_title_for_readme: ID Generators

... the file dart/+/+.yaml (an SDK tier):

variables:
  workflow_file_name: dart-ci.yml

... the file ./+/+.yaml (a root tier):

file_conflict_resolutions:
  - name: CHANGELOG.md
    resolution: doNotOverwrite

variables:
  current_year: 2025

  owner_full_name: Andrii Syrokomskyi
  owner_id: signmotion
  owner_website: https://syrokomskyi.com

  publisher_id: syrokomskyi.com

Pay attention to variables: their values we can use in any other values. How? Just look at file id_gen/+README.md/description.md:

The standardized, easy-to-use, and [well-tested](https://github.com/{owner_id}/{project_id}/tree/master/test) set for generating IDs.

The {owner_id}/{project_id} part will be replaced by signmotion/fresher, which was defined above in several +.yaml files.

We can even redefine owner_website as:

  ...
  owner_website: https://{publisher_id}
  ...

and the final value will be https://syrokomskyi.com. Easy, isn't it?

Just replace it with your own publisher-website-description and get your basic structure for your packages!

  • You can add any names you want and use them in any files.
  • Any depth of nesting will be addressed to the final content.
  • The values of all variables and files with the same name will be replaced by those defined at a deeper tier.

For example, you can define the contents of ./+/README.md for all your projects as follows:

README file from root base

Notice: The filename is the name of the variable.

Running Fresher will produce this result.

The base (template, configuration) of your projects is defined as separate project.

I've done this for my packages, I'm using this for the new projects, and I'm sharing this solution with you. Welcome back from boring hell!

File Conflict Resolutions

What is file_conflict_resolutions in +.yaml file?

The Fresher is invisible for all maintananted packages. In the best SOLID principles. Therefore, it must know how to resolve conflicts for files. For example, with a declaration like this:

file_conflict_resolutions:
  - name: CHANGELOG.md
    resolution: doNotOverwrite

the CHANGELOG.md file is not replaced by the new version if it is already present in the project. Thus, using Fresher for your wonderful projects is safe.

Resolutions
doNotOverwrite A file will be skipped when present and added otherwise.
overwrite A file will be overwrite.

The default is overwrite.

Summary

We have 3 tiers:

  1. Root.
  2. SDK.
  3. Project.

In each tier, we declare our files, variables, and their values.

Deeper tier definitions replace variables and files with the same name.

The folder named + contains files and folders that will be added to maintained projects.

The folder prefixed with + contains variables named the same as the files whose contents are their values.

The file named +.yaml contains some (or many) variables with values.

The value is templated with mustache syntactic text. We can utilize any variables defined in +.yaml files and + folders.

In light of this, we (you) can construct a hierarchy of any complexity.

We create an external folder (call it the "base project") and put this folder in the same folder where all our packages are located. Then we run in CLI from the "base project"

cls | dart ../fresher/bin/fresher.dart .

to upgrade all projects or

cls | dart ../fresher/bin/fresher.dart --projects id_gen,title_widget .

to upgrade only the id_gen and title_widget projects. Of course, replace with your good project names.

I'm sharing my "base project". Just clone it and create your own base for your packages.

🤝 Who is Using Fresher

When you start using Fresher in your projects, let me know and I'd be happy to help you with it.

Just tell me and I'll add a link to your project here.

TODO

Badge for README if you want to support Fresher:

Style 1

fresher

[![fresher](https://img.shields.io/badge/maintained%20with-fresher-darkgreen.svg?style=for-the-badge)](https://github.com/signmotion/fresher)

Style 2

fresher

[![fresher](https://img.shields.io/badge/maintained%20with-fresher-darkgreen.svg)](https://github.com/signmotion/fresher)

⚡ Commands

> dart bin/fresher.dart --help

Usage:
dart bin/fresher.dart [flags] [options] ../path/to/project/bases

--projects        Project IDs to update. If empty, all known projects will be updated.
--leave-spaces    All spaces at the ends will be preserved.
--no-changes      Leave destination files without changes: just a log output.
--no-git-logs     Skip the fetching git logs.
--no-upgrade      Skip updating dependencies.

📜 Log Output

Log - Fresher

Log - Fresher

💛 Thanks

While working on the project, I meet people who make the project better with their outsider and professional view. I want to write down their names here... and I'd be happy to add your name as well.

✨ What's New

Look at changelog.

👋 Welcome

If you encounter any problems, feel free to open an issue. If you feel the package is missing a feature, please raise a ticket on Github and I'll look into it. Requests and suggestions are warmly welcome. Danke!

Contributions are what make the open-source community such a great place to learn, create, take a new skills, and be inspired.

If this is your first contribution, I'll leave you with some of the best links I've found: they will help you get started or/and become even more efficient.

The package Fresher is open-source, stable and well-tested. Development happens on GitHub. Feel free to report issues or create a pull-request there.

General questions are best asked on StackOverflow.

And here is a curated list of how you can help:

  • Documenting the undocumented. Whenever you come across a class, property, or method within our codebase that you're familiar with and notice it lacks documentation, kindly spare a couple of minutes to jot down some helpful notes for your fellow developers.
  • Refining the code. While I'm aware it's primarily my responsibility to refactor the code, I wholeheartedly welcome any contributions you're willing to make in this area. Your insights and improvements are appreciated!
  • Constructive code reviews. Should you discover a more efficient approach to achieve something, I'm all ears. Your suggestions for enhancement are invaluable.
  • Sharing your examples. If you've experimented with our use cases or have crafted some examples of your own, feel free to add them to the example directory. Your practical insights can enrich our resource pool.
  • Fix typos/grammar mistakes.
  • Report bugs and scenarios that are difficult to implement.
  • Implement new features by making a pull-request.

✅ TODO (perhaps)

Once you start using the Fresher, it will become easy to choose the functionality to contribute. But if you already get everything you need from this package but have some free time, let me write here what I have planned:

  • The section Who is Using with links.

  • Result output. Group by status and order by file path.

  • Use a fixed with emojis mustache instead EmojiTemplate.

  • ? Optimize. Cache the heavy values for Fresher: projectFileConflictResolutions, etc.

  • DartTest command.

  • Full-fledged CLI. 1

It's just a habit of mine: writing down ideas that come to mind while working on a project. I confess that I rarely return to these notes. But now, hopefully, even if you don't have an idea yet, the above notes will help you choose the suitable "feature" and become a contributor to the open-source community.

Ready for 🪙

Created with ❤️

fresher

Libraries

fresher
tool_fresher