Series 2 of 2 — Part 4 of 4
Building DevFeed — Part 4: Shipping v1.0.1 with GitHub Actions and a Changelog
Series: Building DevFeed — A Proper Flutter MVVM App from Day One
DevFeed started as a practice project. At some point during development it stopped feeling like practice and started feeling like a real app. That shift happened when I set up the GitHub Actions release workflow and wrote the first changelog entry.
Treating a learning project like a real product — versioning it, writing release notes, automating the build — changes how you think about it.
Why bother with releases for a practice project
- The low-stakes answer: Setting up a release workflow on a practice project is good practice for doing it on a real project. You make mistakes when there are no consequences.
- The portfolio answer: A versioned changelog shows you think about the full software development lifecycle, not just writing features. It is a small signal that reads clearly to anyone reviewing your work.
The GitHub Actions workflow
I set up two workflows: one for changelog generation on push to main, and one for the release build when a version tag is pushed.
name: Release on: push: tags: - 'v*' jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2 with: flutter-version: '3.x' - run: flutter pub get - run: flutter build apk --release - uses: actions/upload-artifact@v4 with: name: release-apk path: build/app/outputs/flutter-apk/app-release.apk Keeping action versions current
My first version used older action versions — actions/checkout@v2 and actions/upload-artifact@v3. GitHub started showing deprecation warnings. I updated all of them to v4 and added an environment variable for the Flutter version to make future updates a one-line change.
This is a small maintenance detail but it matters: deprecated action versions will eventually break your builds. Keeping CI/CD dependencies current is the same discipline as keeping pubspec.yaml current.
Writing the v1.0.1 changelog
The changelog covers the features from the initial commits: in-app WebView for article reading, sharing actions, the INTERNET permission fix, and the ConsumerStatefulWidget refactor.
Writing a changelog for a practice project taught me the value of conventional commits. When every commit starts with feat:, fix:, refactor:, or chore:, generating a changelog is easy. DevFeed's commit history followed conventional commits from the beginning — every commit is changelog-ready.
What done looks like for a learning project
DevFeed does not have user accounts, saved reading lists, or offline support. But it has a working feature set, a clean architecture, a release workflow, and versioned changelogs. It is done in the sense that matters for a learning project — polished enough to show, documented enough to explain, and structured enough to extend.
Wrapping up Series 2
Over four posts, DevFeed went from a full MVVM scaffold on the first commit to a shipped app at v1.0.1. No big refactors, because the architecture was right from the start. Tagging a new version automatically builds a release APK.
The contrast with the shopping app series is the whole point. Series 1 shows you what learning the hard way looks like. Series 2 shows you what applying those lessons looks like. You need both. You need to build the messy version before the clean version makes sense.
Thanks for following along.


