changelog-notifier 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.gitlab-ci.yml +30 -0
- data/.rspec +3 -0
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +49 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Dockerfile +60 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +75 -0
- data/LICENSE.txt +21 -0
- data/README.md +152 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/changelog-notifier.gemspec +35 -0
- data/lib/changelog/notifier.rb +17 -0
- data/lib/changelog/notifier/adapters/active_record.rb +57 -0
- data/lib/changelog/notifier/adapters/base.rb +24 -0
- data/lib/changelog/notifier/adapters/slack.rb +60 -0
- data/lib/changelog/notifier/capistrano.rb +11 -0
- data/lib/changelog/notifier/capistrano/tasks/changelog_notifier.rake +33 -0
- data/lib/changelog/notifier/entrypoints/capistrano.rb +112 -0
- data/lib/changelog/notifier/errors.rb +13 -0
- data/lib/changelog/notifier/formatters/active_record.rb +47 -0
- data/lib/changelog/notifier/formatters/slack.rb +77 -0
- data/lib/changelog/notifier/git_commit_author_fetcher.rb +22 -0
- data/lib/changelog/notifier/git_tag_fetcher.rb +20 -0
- data/lib/changelog/notifier/parsers/markdown.rb +113 -0
- data/lib/changelog/notifier/version.rb +7 -0
- data/screenshots/changelog-notifiier_slack.png +0 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 374a3a79445b96144828a772b1cf324709a2cc69299facf1d29c4b1811ab0a37
|
4
|
+
data.tar.gz: c419bfa4d08532dc332789372018c7f6d1ce70b92e7d07289f4a74907a595cc6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f3a42bfdea37eef6b474c803ad6761426171ee44d471d00af49943be9b104ccc4a6a3af762e0670acfab2614011915591c8d5696fc754c9d6d7d542d6365fd24
|
7
|
+
data.tar.gz: 2c40c703e172c8bb94667818924d434a4758be09d6117e7714856ef4df3ccefcb0732066565cf8bc74114b37abeeccb27e9b0db74c10be5e34e1e967f0abf4a4
|
data/.gitignore
ADDED
data/.gitlab-ci.yml
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# This file is a template, and might need editing before it works on your project.
|
2
|
+
docker-build-master:
|
3
|
+
# Official docker image.
|
4
|
+
image: docker:latest
|
5
|
+
stage: build
|
6
|
+
services:
|
7
|
+
- docker:dind
|
8
|
+
before_script:
|
9
|
+
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
10
|
+
script:
|
11
|
+
- docker build --pull -t "$CI_REGISTRY_IMAGE" .
|
12
|
+
- docker run --rm "$CI_REGISTRY_IMAGE"
|
13
|
+
- docker push "$CI_REGISTRY_IMAGE"
|
14
|
+
only:
|
15
|
+
- master
|
16
|
+
|
17
|
+
docker-build:
|
18
|
+
# Official docker image.
|
19
|
+
image: docker:latest
|
20
|
+
stage: build
|
21
|
+
services:
|
22
|
+
- docker:dind
|
23
|
+
before_script:
|
24
|
+
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
25
|
+
script:
|
26
|
+
- docker build --pull -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" .
|
27
|
+
- docker run --rm "$CI_REGISTRY_IMAGE"
|
28
|
+
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
|
29
|
+
except:
|
30
|
+
- master
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [Unreleased]
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
## [1.5.0] - 2020-10-18
|
12
|
+
### Added
|
13
|
+
- ActiveRecord adapter
|
14
|
+
|
15
|
+
## [1.4.0] - 2020-10-13
|
16
|
+
### Added
|
17
|
+
- Screenshot in the `README.md` file
|
18
|
+
|
19
|
+
### Removed
|
20
|
+
- Remaning debugs
|
21
|
+
|
22
|
+
## [1.3.0] - 2020-10-13
|
23
|
+
### Fixed
|
24
|
+
- Running commands remotely
|
25
|
+
|
26
|
+
## [1.2.0] - 2020-10-13
|
27
|
+
### Fixed
|
28
|
+
- Using git on a Capistrano server
|
29
|
+
|
30
|
+
## [1.1.0] - 2020-10-13
|
31
|
+
### Added
|
32
|
+
- Improves application name formatting in Slack adapter
|
33
|
+
|
34
|
+
## [1.0.0] - 2020-10-12
|
35
|
+
### Added
|
36
|
+
- Capistrano entrypoint
|
37
|
+
- CHANGELOG.md parser based on http://keepachangelog.com
|
38
|
+
- Version fetching based on git tags
|
39
|
+
- Version commit author fetching
|
40
|
+
- Slack adapter to post the changelog to a Slack channel
|
41
|
+
- Slack formatter
|
42
|
+
|
43
|
+
[Unreleased]: https://gitlab.com/zedtux/changelog-notifier/-/compare/v1.5.0...master
|
44
|
+
[1.5.0]: https://gitlab.com/zedtux/changelog-notifier/-/compare/v1.4.0...v1.5.0
|
45
|
+
[1.4.0]: https://gitlab.com/zedtux/changelog-notifier/-/compare/v1.3.0...v1.4.0
|
46
|
+
[1.3.0]: https://gitlab.com/zedtux/changelog-notifier/-/compare/v1.2.0...v1.3.0
|
47
|
+
[1.2.0]: https://gitlab.com/zedtux/changelog-notifier/-/compare/v1.1.0...v1.2.0
|
48
|
+
[1.1.0]: https://gitlab.com/zedtux/changelog-notifier/-/compare/v1.0.0...v1.1.0
|
49
|
+
[1.0.0]: https://gitlab.com/zedtux/changelog-notifier/-/tags/v1.0.0
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at zedtux@zedroot.org. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Dockerfile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#
|
2
|
+
# Builds a temporary image, with all the required dependencies used to compile
|
3
|
+
# the dependencies' dependencies.
|
4
|
+
# This image will be destroyed at the end of the build command.
|
5
|
+
#
|
6
|
+
FROM ruby:2.7-alpine3.12 AS build-env
|
7
|
+
|
8
|
+
ARG GEM_ROOT=/gem
|
9
|
+
ARG BUILD_PACKAGES="build-base git"
|
10
|
+
ARG DEV_PACKAGES="sqlite-dev"
|
11
|
+
ARG RUBY_PACKAGES="tzdata"
|
12
|
+
|
13
|
+
RUN apk update && \
|
14
|
+
apk upgrade && \
|
15
|
+
apk add --update --no-cache $BUILD_PACKAGES \
|
16
|
+
$DEV_PACKAGES \
|
17
|
+
$RUBY_PACKAGES && \
|
18
|
+
mkdir -p /gem/
|
19
|
+
|
20
|
+
WORKDIR $GEM_ROOT
|
21
|
+
|
22
|
+
COPY Gemfile* *.gemspec /gem/
|
23
|
+
COPY lib/changelog/notifier/version.rb /gem/lib/changelog/notifier/version.rb
|
24
|
+
|
25
|
+
RUN touch ~/.gemrc && \
|
26
|
+
echo "gem: --no-ri --no-rdoc" >> ~/.gemrc && \
|
27
|
+
gem install rubygems-update && \
|
28
|
+
update_rubygems && \
|
29
|
+
gem install bundler && \
|
30
|
+
bundle install --jobs $(nproc) && \
|
31
|
+
rm -rf /usr/local/bundle/cache/*.gem && \
|
32
|
+
find /usr/local/bundle/gems/ -name "*.c" -delete && \
|
33
|
+
find /usr/local/bundle/gems/ -name "*.o" -delete
|
34
|
+
|
35
|
+
COPY . /gem/
|
36
|
+
|
37
|
+
#
|
38
|
+
# Builds the final image with the minimum of system packages
|
39
|
+
# and copy the gem's sources, Bundler gems and Yarn packages.
|
40
|
+
#
|
41
|
+
|
42
|
+
FROM ruby:2.7-alpine3.12
|
43
|
+
|
44
|
+
LABEL maintainer="zedtux"
|
45
|
+
|
46
|
+
ARG GEM_ROOT=/gem
|
47
|
+
ARG PACKAGES="git sqlite sqlite-libs tzdata"
|
48
|
+
|
49
|
+
RUN apk update && \
|
50
|
+
apk upgrade && \
|
51
|
+
apk add --update --no-cache $PACKAGES && \
|
52
|
+
mkdir -p /gem/
|
53
|
+
|
54
|
+
WORKDIR $GEM_ROOT
|
55
|
+
|
56
|
+
COPY --from=build-env /usr/local/bundle/ /usr/local/bundle/
|
57
|
+
COPY --from=build-env $GEM_ROOT $GEM_ROOT
|
58
|
+
|
59
|
+
ENTRYPOINT ["bundle", "exec"]
|
60
|
+
CMD ["rake"]
|
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in changelog-notifier.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'activerecord', '~> 6.0'
|
7
|
+
gem 'database_cleaner-active_record', '~> 1.8'
|
8
|
+
gem 'rake', '~> 12.0'
|
9
|
+
gem 'rspec', '~> 3.0'
|
10
|
+
gem 'slack-notifier', '~> 2'
|
11
|
+
gem 'sqlite3', '~> 1.4'
|
12
|
+
gem 'webmock', '~> 3.9'
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
changelog-notifier (1.4.0)
|
5
|
+
titleize (~> 1.4.1)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activemodel (6.0.3.4)
|
11
|
+
activesupport (= 6.0.3.4)
|
12
|
+
activerecord (6.0.3.4)
|
13
|
+
activemodel (= 6.0.3.4)
|
14
|
+
activesupport (= 6.0.3.4)
|
15
|
+
activesupport (6.0.3.4)
|
16
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
17
|
+
i18n (>= 0.7, < 2)
|
18
|
+
minitest (~> 5.1)
|
19
|
+
tzinfo (~> 1.1)
|
20
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
21
|
+
addressable (2.7.0)
|
22
|
+
public_suffix (>= 2.0.2, < 5.0)
|
23
|
+
concurrent-ruby (1.1.7)
|
24
|
+
crack (0.4.4)
|
25
|
+
database_cleaner (1.8.5)
|
26
|
+
database_cleaner-active_record (1.8.0)
|
27
|
+
activerecord
|
28
|
+
database_cleaner (~> 1.8.0)
|
29
|
+
diff-lcs (1.4.4)
|
30
|
+
hashdiff (1.0.1)
|
31
|
+
i18n (1.8.5)
|
32
|
+
concurrent-ruby (~> 1.0)
|
33
|
+
minitest (5.14.2)
|
34
|
+
public_suffix (4.0.6)
|
35
|
+
rake (12.3.3)
|
36
|
+
rspec (3.9.0)
|
37
|
+
rspec-core (~> 3.9.0)
|
38
|
+
rspec-expectations (~> 3.9.0)
|
39
|
+
rspec-mocks (~> 3.9.0)
|
40
|
+
rspec-core (3.9.3)
|
41
|
+
rspec-support (~> 3.9.3)
|
42
|
+
rspec-expectations (3.9.2)
|
43
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
44
|
+
rspec-support (~> 3.9.0)
|
45
|
+
rspec-mocks (3.9.1)
|
46
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
47
|
+
rspec-support (~> 3.9.0)
|
48
|
+
rspec-support (3.9.3)
|
49
|
+
slack-notifier (2.3.2)
|
50
|
+
sqlite3 (1.4.2)
|
51
|
+
thread_safe (0.3.6)
|
52
|
+
titleize (1.4.1)
|
53
|
+
tzinfo (1.2.7)
|
54
|
+
thread_safe (~> 0.1)
|
55
|
+
webmock (3.9.1)
|
56
|
+
addressable (>= 2.3.6)
|
57
|
+
crack (>= 0.3.2)
|
58
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
59
|
+
zeitwerk (2.4.0)
|
60
|
+
|
61
|
+
PLATFORMS
|
62
|
+
ruby
|
63
|
+
|
64
|
+
DEPENDENCIES
|
65
|
+
activerecord (~> 6.0)
|
66
|
+
changelog-notifier!
|
67
|
+
database_cleaner-active_record (~> 1.8)
|
68
|
+
rake (~> 12.0)
|
69
|
+
rspec (~> 3.0)
|
70
|
+
slack-notifier (~> 2)
|
71
|
+
sqlite3 (~> 1.4)
|
72
|
+
webmock (~> 3.9)
|
73
|
+
|
74
|
+
BUNDLED WITH
|
75
|
+
2.1.4
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Guillaume Hain
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
# changelog-notifier
|
2
|
+
|
3
|
+
This gem reads [your `CHANGELOG.md` file](https://keepachangelog.com) and extract the release note for your project's version (fetched from your git tags) and posts it to a Slack channel when deploying your app with Capistrano.
|
4
|
+
|
5
|
+
This allows you to keep informed your team about releases deployments.
|
6
|
+
|
7
|
+
To summarize, it runs your `CHANGELOG.md` file into this:
|
8
|
+
|
9
|
+

|
10
|
+
|
11
|
+
## Concepts
|
12
|
+
|
13
|
+
### Entrypoints
|
14
|
+
|
15
|
+
[Entrypoints](https://gitlab.com/zedtux/changelog-notifier/-/tree/master/lib/changelog/notifier/entrypoints) are the inputs, or the triggers. As of now, only the Capistrano entrypoint exists, which means you can only publish your `CHANGELOG.md` *FROM* a Capistrano deployment.
|
16
|
+
|
17
|
+
You can add any kind of entrypoints like a cron one, a bot and more!
|
18
|
+
|
19
|
+
### Parsers
|
20
|
+
|
21
|
+
[Parsers](https://gitlab.com/zedtux/changelog-notifier/-/tree/master/lib/changelog/notifier/parsers) are the heart of this gem, and are responsible to read and transform a `CHANGELOG.md` file into a standardized `Hash`.
|
22
|
+
|
23
|
+
In other words they are transforming something like that:
|
24
|
+
|
25
|
+
```
|
26
|
+
## [1.1.0] - 2020-10-13
|
27
|
+
### Added
|
28
|
+
- Improves application name formatting in Slack adapter
|
29
|
+
|
30
|
+
### Removed
|
31
|
+
- All the bad code
|
32
|
+
```
|
33
|
+
|
34
|
+
Into that:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
{
|
38
|
+
version: '1.1.0',
|
39
|
+
date: '2020-10-13',
|
40
|
+
url: 'https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...v1.1.0',
|
41
|
+
changes: {
|
42
|
+
added: [
|
43
|
+
'Improves application name formatting in Slack adapter',
|
44
|
+
],
|
45
|
+
removed: [
|
46
|
+
'All the bad code'
|
47
|
+
]
|
48
|
+
}
|
49
|
+
}
|
50
|
+
```
|
51
|
+
|
52
|
+
### Adapters
|
53
|
+
|
54
|
+
[Adapters](https://gitlab.com/zedtux/changelog-notifier/-/tree/master/lib/changelog/notifier/adapters) are the output. Adapters are using [formatters](https://gitlab.com/zedtux/changelog-notifier/-/tree/master/lib/changelog/notifier/formatters) in order to transform the parsed `CHANGELOG.md` into something that can be used by the adapters.
|
55
|
+
|
56
|
+
As of now, there are 2 supported adapters:
|
57
|
+
|
58
|
+
* the Slack adapter which allows you to publish your `CHANGELOG.md` *TO* a Slack channel
|
59
|
+
* the ActiveRecord which allows you to create an ActiveRecord into your database
|
60
|
+
|
61
|
+
You can use many adapters at the same time so if you'd like to post to Slack *AND* to create an entry in your database, configures both and you'll get both!
|
62
|
+
|
63
|
+
You can add adapters for anythings like Twitter, Mails, SMS, WhatsApp and more!
|
64
|
+
|
65
|
+
## Installation
|
66
|
+
|
67
|
+
Add this line to your application's Gemfile:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
gem 'changelog-notifier', '~> 1.4'
|
71
|
+
gem 'slack-notifier', '~> 2' # For Slack notifications
|
72
|
+
```
|
73
|
+
|
74
|
+
And then execute:
|
75
|
+
|
76
|
+
$ bundle
|
77
|
+
|
78
|
+
Or install it yourself as:
|
79
|
+
|
80
|
+
$ gem install changelog-notifier
|
81
|
+
|
82
|
+
## Usage
|
83
|
+
|
84
|
+
### First
|
85
|
+
|
86
|
+
As of now there's only one [Entrypoint](#entrypoints) which is Capistrano, so you have to import the gem's Capistrano entrypoint:
|
87
|
+
|
88
|
+
1. Add the following `require` to your `Capfile`
|
89
|
+
```ruby
|
90
|
+
require 'changelog/notifier/capistrano'
|
91
|
+
```
|
92
|
+
2. Add and configure the options in your `config/deploy.rb` file:
|
93
|
+
```ruby
|
94
|
+
# Where should changelog-notifier run?
|
95
|
+
set :changelog_notifier_role, :app
|
96
|
+
```
|
97
|
+
|
98
|
+
### Using the Slack adapter
|
99
|
+
|
100
|
+
3. Configure the Slack adapter:
|
101
|
+
```ruby
|
102
|
+
# Slack options
|
103
|
+
#
|
104
|
+
# Your webhook URL
|
105
|
+
set :changelog_notifier_slack_webhook_url, 'https://hooks.slack.com/services/...'
|
106
|
+
# The Slack channel where to post the release note
|
107
|
+
set :changelog_notifier_slack_channel, '#general'
|
108
|
+
# The Icon Emoji to be used when posting the release note
|
109
|
+
set :changelog_notifier_slack_icon_emoji, ':package:'
|
110
|
+
```
|
111
|
+
|
112
|
+
### Using the ActiveRecord adapter
|
113
|
+
|
114
|
+
3. Configure the ActiveRecord adapter:
|
115
|
+
```ruby
|
116
|
+
# ActiveRecord options
|
117
|
+
#
|
118
|
+
# Your ActiveRecord model name
|
119
|
+
set :changelog_notifier_active_record_model, Release
|
120
|
+
# The column/field from your ActiveRecord model where to set the version
|
121
|
+
set :changelog_notifier_active_record_version_field, 'version'
|
122
|
+
# The column/field from your ActiveRecord model where to store the release note
|
123
|
+
set :changelog_notifier_active_record_release_node_field, 'release_note'
|
124
|
+
# The columns/fields from your ActiveRecord model that you need to set (optional)
|
125
|
+
set :changelog_notifier_active_record_other_fields, { field1: 'ok', field2: true }
|
126
|
+
```
|
127
|
+
|
128
|
+
### Finally
|
129
|
+
|
130
|
+
3. Maintain your `CHANGELOG.md` file as described at https://keepachangelog.com
|
131
|
+
4. Tag with your version
|
132
|
+
5. Deploy with Capistrano
|
133
|
+
|
134
|
+
When you will deploy a tagged commit, and a matching version exists in your `CHANGELOG.md` file, a Slack post will be sent in the case the Capistrano deployment suceeded.
|
135
|
+
|
136
|
+
## Development
|
137
|
+
|
138
|
+
After checking out the repo, and installed [Docker](https://docs.docker.com/get-docker/), run `docker build -t $(whoami)/changelog-notifier .` to build the development Docker image. Then, run `docker run --rm --volume "$PWD":/gem $(whoami)/changelog-notifier` to run the tests. You can also run `docker run --rm -it --volume "$PWD":/gem $(whoami)/changelog-notifier bin/console` for an interactive prompt that will allow you to experiment.
|
139
|
+
|
140
|
+
To release a new version, update the version number in `version.rb`, and then run `docker run --rm --volume "$PWD":/gem $(whoami)/changelog-notifier release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
141
|
+
|
142
|
+
## Contributing
|
143
|
+
|
144
|
+
Bug reports and merge requests are welcome on Gitlab at https://gitlab.com/zedtux/changelog-notifier. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
145
|
+
|
146
|
+
## License
|
147
|
+
|
148
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
149
|
+
|
150
|
+
## Code of Conduct
|
151
|
+
|
152
|
+
Everyone interacting in the Changelog::Notifier project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://gitlab.com/zedtux/changelog-notifier/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'changelog/notifier'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/changelog/notifier/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'changelog-notifier'
|
7
|
+
spec.version = Changelog::Notifier::VERSION
|
8
|
+
spec.authors = ['Guillaume Hain']
|
9
|
+
spec.email = ['zedtux@zedroot.org']
|
10
|
+
|
11
|
+
spec.summary = "Sends current version's release note from your " \
|
12
|
+
'CHANGELOG.md file'
|
13
|
+
spec.description = 'This gem sends the release note, extracted from your ' \
|
14
|
+
'CHANGELOG.md file, to Slack when deployin with ' \
|
15
|
+
'Capistrano'
|
16
|
+
spec.homepage = 'https://gitlab.com/zedtux/changelog-notifier'
|
17
|
+
spec.license = 'MIT'
|
18
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
|
19
|
+
|
20
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
21
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
22
|
+
spec.metadata['source_code_uri'] = 'https://gitlab.com/zedtux/changelog-notifier'
|
23
|
+
spec.metadata['changelog_uri'] = 'https://gitlab.com/zedtux/changelog-notifier/-/blob/master/CHANGELOG.md'
|
24
|
+
|
25
|
+
# Specify which files should be added to the gem when it is released.
|
26
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
27
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
28
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
29
|
+
end
|
30
|
+
spec.bindir = 'exe'
|
31
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
|
+
spec.require_paths = ['lib']
|
33
|
+
|
34
|
+
spec.add_dependency 'titleize', '~> 1.4.1'
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'changelog/notifier/errors'
|
4
|
+
require 'changelog/notifier/adapters/base'
|
5
|
+
require 'changelog/notifier/adapters/active_record'
|
6
|
+
require 'changelog/notifier/adapters/slack'
|
7
|
+
require 'changelog/notifier/formatters/active_record'
|
8
|
+
require 'changelog/notifier/formatters/slack'
|
9
|
+
require 'changelog/notifier/git_commit_author_fetcher'
|
10
|
+
require 'changelog/notifier/git_tag_fetcher'
|
11
|
+
require 'changelog/notifier/parsers/markdown'
|
12
|
+
require 'changelog/notifier/version'
|
13
|
+
|
14
|
+
module Changelog
|
15
|
+
module Notifier
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Changelog
|
4
|
+
module Notifier
|
5
|
+
module Adapters
|
6
|
+
#
|
7
|
+
# Creates an ActiveRecord with the changelog
|
8
|
+
#
|
9
|
+
class ActiveRecord < Base
|
10
|
+
def publish!(release_note_hash, version)
|
11
|
+
formatted_release_note = format_release_note_hash(release_note_hash)
|
12
|
+
|
13
|
+
create_attributes = {}
|
14
|
+
create_attributes[version_field] = version
|
15
|
+
create_attributes[release_node_field] = formatted_release_note
|
16
|
+
|
17
|
+
Array(@other_fields).each do |field, value|
|
18
|
+
create_attributes[field] = value
|
19
|
+
end
|
20
|
+
|
21
|
+
@model.create!(create_attributes)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
#
|
27
|
+
# Fetches all the configuration variables from Capistrano.
|
28
|
+
#
|
29
|
+
def fetches_adapter_configuration
|
30
|
+
@model = @capistrano.fetch(:changelog_notifier_active_record_model)
|
31
|
+
@version_field = @capistrano.fetch(
|
32
|
+
:changelog_notifier_active_record_version_field
|
33
|
+
)
|
34
|
+
@release_node_field = @capistrano.fetch(
|
35
|
+
:changelog_notifier_active_record_release_node_field
|
36
|
+
)
|
37
|
+
@other_fields = @capistrano.fetch(
|
38
|
+
:changelog_notifier_active_record_other_fields
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def format_release_note_hash(release_note_hash)
|
43
|
+
Changelog::Notifier::Formatters::ActiveRecord.new(release_note_hash)
|
44
|
+
.format
|
45
|
+
end
|
46
|
+
|
47
|
+
def release_node_field
|
48
|
+
@release_node_field || 'release_node'
|
49
|
+
end
|
50
|
+
|
51
|
+
def version_field
|
52
|
+
@version_field || 'version'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Changelog
|
4
|
+
module Notifier
|
5
|
+
module Adapters
|
6
|
+
class Base
|
7
|
+
def initialize(capistrano)
|
8
|
+
@capistrano = capistrano
|
9
|
+
|
10
|
+
unless @capistrano
|
11
|
+
raise ArgumentError, 'No Capistrano instance passed while it is ' \
|
12
|
+
'required.'
|
13
|
+
end
|
14
|
+
|
15
|
+
fetches_adapter_configuration
|
16
|
+
end
|
17
|
+
|
18
|
+
def publish!(release_note_hash, version)
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'slack-notifier'
|
4
|
+
|
5
|
+
module Changelog
|
6
|
+
module Notifier
|
7
|
+
module Adapters
|
8
|
+
#
|
9
|
+
# Slack adapter sends the release note in a Slack channel.
|
10
|
+
#
|
11
|
+
class Slack < Base
|
12
|
+
def publish!(release_note_hash, version)
|
13
|
+
formatted_release_note = format_release_note_hash(release_note_hash)
|
14
|
+
|
15
|
+
notifier = instantiate_slack_notifier
|
16
|
+
|
17
|
+
@capistrano.info "Posting #{version}'s release note in the " \
|
18
|
+
"Slack #{channel} channel using the #{icon_emoji} " \
|
19
|
+
'emoji icon ...'
|
20
|
+
|
21
|
+
notifier.post formatted_release_note
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def channel
|
27
|
+
@channel || '#general'
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Fetches all the configuration variables from Capistrano.
|
32
|
+
#
|
33
|
+
def fetches_adapter_configuration
|
34
|
+
@webhook_url = @capistrano.fetch(
|
35
|
+
:changelog_notifier_slack_webhook_url
|
36
|
+
)
|
37
|
+
@channel = @capistrano.fetch(:changelog_notifier_slack_channel)
|
38
|
+
@icon_emoji = @capistrano.fetch(:changelog_notifier_slack_icon_emoji)
|
39
|
+
end
|
40
|
+
|
41
|
+
def format_release_note_hash(release_note_hash)
|
42
|
+
Changelog::Notifier::Formatters::Slack.new(release_note_hash).format
|
43
|
+
end
|
44
|
+
|
45
|
+
def icon_emoji
|
46
|
+
@icon_emoji || ':package:'
|
47
|
+
end
|
48
|
+
|
49
|
+
def instantiate_slack_notifier
|
50
|
+
::Slack::Notifier.new(
|
51
|
+
@webhook_url,
|
52
|
+
channel: channel,
|
53
|
+
icon_emoji: icon_emoji,
|
54
|
+
username: 'ChangeLog Notifier'
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'changelog/notifier/entrypoints/capistrano'
|
4
|
+
require 'changelog/notifier/git_tag_fetcher'
|
5
|
+
require 'changelog/notifier/git_commit_author_fetcher'
|
6
|
+
require 'changelog/notifier/errors'
|
7
|
+
require 'changelog/notifier/parsers/markdown'
|
8
|
+
require 'changelog/notifier/adapters/slack'
|
9
|
+
require 'changelog/notifier/formatters/slack'
|
10
|
+
|
11
|
+
load File.expand_path('capistrano/tasks/changelog_notifier.rake', __dir__)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
namespace :load do
|
4
|
+
task :defaults do
|
5
|
+
set :changelog_notifier_role, :app
|
6
|
+
|
7
|
+
# Slack
|
8
|
+
set :changelog_notifier_slack_webhook_url, nil
|
9
|
+
set :changelog_notifier_slack_channel, '#general'
|
10
|
+
set :changelog_notifier_slack_icon_emoji, ':package:'
|
11
|
+
|
12
|
+
# ActiveRecord
|
13
|
+
set :changelog_notifier_active_record_model, nil # nil means disabled
|
14
|
+
set :changelog_notifier_active_record_version_field, 'version'
|
15
|
+
set :changelog_notifier_active_record_release_node_field, 'release_note'
|
16
|
+
set :changelog_notifier_active_record_other_fields, {}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
namespace :deploy do
|
21
|
+
after :deploy, 'changelog_notifier:post_release_note'
|
22
|
+
end
|
23
|
+
|
24
|
+
namespace :changelog_notifier do
|
25
|
+
desc "Posts version's release notee do Slack"
|
26
|
+
task :post_release_note do
|
27
|
+
on roles(fetch(:changelog_notifier_role)) do
|
28
|
+
within current_path do
|
29
|
+
Changelog::Notifier::Entrypoints::Capistrano.run!(self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Changelog
|
4
|
+
module Notifier
|
5
|
+
module Entrypoints
|
6
|
+
#
|
7
|
+
# Tries to publish the version's release note after a successful
|
8
|
+
# Capistrano deployment.
|
9
|
+
#
|
10
|
+
class Capistrano
|
11
|
+
def initialize(instance)
|
12
|
+
@capistrano = instance
|
13
|
+
end
|
14
|
+
|
15
|
+
def publish_release_note
|
16
|
+
ensure_release_has_changelog_file &&
|
17
|
+
fetch_version_from_git_tags_and_commit_author &&
|
18
|
+
parse_changelog_file &&
|
19
|
+
run_through_adapters
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.run!(instance)
|
23
|
+
entrypoint = Changelog::Notifier::Entrypoints::Capistrano.new(instance)
|
24
|
+
entrypoint.publish_release_note
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def ensure_release_has_changelog_file
|
30
|
+
return true if File.file?('CHANGELOG.md')
|
31
|
+
|
32
|
+
@capistrano.warn 'You repository has no CHANGELOG.md file. ' \
|
33
|
+
'Skipping sending release note.'
|
34
|
+
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
def fetch_version_from_git_tags_and_commit_author
|
39
|
+
@git_repo_path = @capistrano.fetch(:repo_path)
|
40
|
+
|
41
|
+
@capistrano.info "Git dir is now #{@git_repo_path}."
|
42
|
+
|
43
|
+
fetch_version_from_git_tags && fetch_commit_author
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_version_from_git_tags
|
47
|
+
# Retrives the current's commit version tag if any
|
48
|
+
@version = Changelog::Notifier::GitTagFetcher.fetch(
|
49
|
+
capistrano: @capistrano,
|
50
|
+
path: @git_repo_path
|
51
|
+
)
|
52
|
+
|
53
|
+
return true if @version
|
54
|
+
|
55
|
+
@capistrano.warn 'No version tag found from the currernt commit. ' \
|
56
|
+
'Skipping sending release note.'
|
57
|
+
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
def fetch_commit_author
|
62
|
+
# Retrives the current's commit author
|
63
|
+
@author = Changelog::Notifier::GitCommitAuthorFetcher.fetch(
|
64
|
+
capistrano: @capistrano,
|
65
|
+
path: @git_repo_path
|
66
|
+
)
|
67
|
+
|
68
|
+
return true if @author
|
69
|
+
|
70
|
+
@capistrano.warn 'Commit author cannot be found from the currernt ' \
|
71
|
+
' commit. Skipping sending release note.'
|
72
|
+
|
73
|
+
false
|
74
|
+
end
|
75
|
+
|
76
|
+
def parse_changelog_file
|
77
|
+
parser = Changelog::Notifier::Parsers::Markdown.new(
|
78
|
+
File.read('CHANGELOG.md')
|
79
|
+
)
|
80
|
+
|
81
|
+
@release_note_hash = parser.extract(@version)
|
82
|
+
|
83
|
+
@release_note_hash[:author] = @author
|
84
|
+
@release_note_hash[:application] = @capistrano.fetch(
|
85
|
+
:application,
|
86
|
+
'the application'
|
87
|
+
)
|
88
|
+
|
89
|
+
true
|
90
|
+
rescue ArgumentError => error
|
91
|
+
@capistrano.error "Parsing CHANGELOG.md failed: #{error.message}. " \
|
92
|
+
'Skipping sending release note.'
|
93
|
+
rescue Changelog::Notifier::ReleaseNoteNotFound
|
94
|
+
@capistrano.error 'Parsing CHANGELOG.md failed: Missing release ' \
|
95
|
+
"note for version #{@version}." \
|
96
|
+
'Skipping sending release note.'
|
97
|
+
end
|
98
|
+
|
99
|
+
def run_through_adapters
|
100
|
+
[
|
101
|
+
Changelog::Notifier::Adapters::ActiveRecord,
|
102
|
+
Changelog::Notifier::Adapters::Slack
|
103
|
+
].each do |adapter|
|
104
|
+
adapter.new(@capistrano).publish!(@release_note_hash, @version)
|
105
|
+
end
|
106
|
+
rescue StandardError => error
|
107
|
+
@capistrano.error error.message
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Changelog
|
4
|
+
module Notifier
|
5
|
+
# The CHANGELOG doesn't include the given version
|
6
|
+
class ReleaseNoteNotFound < StandardError; end
|
7
|
+
# A git command failed with an exit code higher than 0
|
8
|
+
class GitCommandFailed < StandardError; end
|
9
|
+
|
10
|
+
# A class is not implementing an expected method
|
11
|
+
class NotImplementedError < StandardError; end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'titleize'
|
5
|
+
|
6
|
+
module Changelog
|
7
|
+
module Notifier
|
8
|
+
module Formatters
|
9
|
+
#
|
10
|
+
# Format the given release note hash for ActiveRecord as a multiline text
|
11
|
+
#
|
12
|
+
class ActiveRecord
|
13
|
+
def initialize(release_note_hash)
|
14
|
+
@release_note_hash = release_note_hash
|
15
|
+
end
|
16
|
+
|
17
|
+
def format
|
18
|
+
release_note = description_text + "\n\n"
|
19
|
+
|
20
|
+
Array(@release_note_hash[:changes]).each do |change, logs|
|
21
|
+
release_note << "#{change.capitalize}\n#{logs.join("\n")}\n\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
# TODO : Avoids adding newlines for the last change ...
|
25
|
+
release_note.gsub(/\n\z/, '')
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def description_text
|
31
|
+
"*#{formatted_application_name}* version " \
|
32
|
+
"*#{@release_note_hash[:version]}* has just been released by " \
|
33
|
+
"*#{@release_note_hash[:author]}* on the " \
|
34
|
+
"*#{formatted_release_date}*.\nPlease find bellow the release note:"
|
35
|
+
end
|
36
|
+
|
37
|
+
def formatted_application_name
|
38
|
+
@release_note_hash[:application].gsub(/_/, ' ').titleize
|
39
|
+
end
|
40
|
+
|
41
|
+
def formatted_release_date
|
42
|
+
Date.parse(@release_note_hash[:date]).strftime('%b %d')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'titleize'
|
5
|
+
|
6
|
+
module Changelog
|
7
|
+
module Notifier
|
8
|
+
module Formatters
|
9
|
+
#
|
10
|
+
# Format the given release note hash for Slack
|
11
|
+
#
|
12
|
+
class Slack
|
13
|
+
def initialize(release_note_hash)
|
14
|
+
@release_note_hash = release_note_hash
|
15
|
+
end
|
16
|
+
|
17
|
+
def format
|
18
|
+
{
|
19
|
+
attachments: build_attachments,
|
20
|
+
text: description_text
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def build_attachments
|
27
|
+
Array(@release_note_hash[:changes]).map do |change, logs|
|
28
|
+
{
|
29
|
+
mrkdwn_in: ['text'],
|
30
|
+
color: color_for(change),
|
31
|
+
title: change.to_s.capitalize,
|
32
|
+
fields: logs.map { |log| { title: log } }
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def color_for(change)
|
38
|
+
case change
|
39
|
+
when :added then green
|
40
|
+
when :changed then yellow
|
41
|
+
when :deprecated then yellow
|
42
|
+
when :fixed then green
|
43
|
+
when :removed then red
|
44
|
+
when :security then red
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def description_text
|
49
|
+
"*#{formatted_application_name}* version " \
|
50
|
+
"*#{@release_note_hash[:version]}* has just been released by " \
|
51
|
+
"*#{@release_note_hash[:author]}* on the " \
|
52
|
+
"*#{formatted_release_date}*.\n\nPlease find bellow the release note:"
|
53
|
+
end
|
54
|
+
|
55
|
+
def formatted_application_name
|
56
|
+
@release_note_hash[:application].gsub(/_/, ' ').titleize
|
57
|
+
end
|
58
|
+
|
59
|
+
def formatted_release_date
|
60
|
+
Date.parse(@release_note_hash[:date]).strftime('%b %d')
|
61
|
+
end
|
62
|
+
|
63
|
+
def green
|
64
|
+
'#36a64f'
|
65
|
+
end
|
66
|
+
|
67
|
+
def red
|
68
|
+
'#fc464a'
|
69
|
+
end
|
70
|
+
|
71
|
+
def yellow
|
72
|
+
'#fd9134'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
|
5
|
+
module Changelog
|
6
|
+
module Notifier
|
7
|
+
#
|
8
|
+
# Fetches a Git commit author from the current commit.
|
9
|
+
#
|
10
|
+
class GitCommitAuthorFetcher
|
11
|
+
def self.fetch(options = {})
|
12
|
+
output = options[:capistrano].capture(
|
13
|
+
"git --git-dir=#{options[:path] || '.'} log -1 --pretty=format:'%an'"
|
14
|
+
)
|
15
|
+
|
16
|
+
return nil if output.empty?
|
17
|
+
|
18
|
+
output.gsub(/(^\'|'$)/, '')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Changelog
|
4
|
+
module Notifier
|
5
|
+
#
|
6
|
+
# Fetches a Git tag from the current commit being a version.
|
7
|
+
#
|
8
|
+
class GitTagFetcher
|
9
|
+
def self.fetch(options = {})
|
10
|
+
output = options[:capistrano].capture(
|
11
|
+
"git --git-dir #{options[:path] || '.'} tag --contains HEAD"
|
12
|
+
)
|
13
|
+
|
14
|
+
return nil if output.empty?
|
15
|
+
|
16
|
+
output.split("\n").detect { |tag| tag =~ /[\d\.]+/ }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Changelog
|
4
|
+
module Notifier
|
5
|
+
module Parsers
|
6
|
+
#
|
7
|
+
# Parses the given `content` as Markdown following the specifications from
|
8
|
+
# https://keepachangelog.com.
|
9
|
+
#
|
10
|
+
class Markdown
|
11
|
+
def initialize(content)
|
12
|
+
@content = content
|
13
|
+
end
|
14
|
+
|
15
|
+
def extract(version)
|
16
|
+
version_is_valid?(version) || raise(ArgumentError, 'Invalid version')
|
17
|
+
|
18
|
+
parse!
|
19
|
+
|
20
|
+
version_release_note = detect_version_release_note_for(version)
|
21
|
+
version_release_note || raise(Changelog::Notifier::ReleaseNoteNotFound)
|
22
|
+
|
23
|
+
version_release_note_hash = create_hash_from(version_release_note)
|
24
|
+
|
25
|
+
url = fetch_version_url_for(version)
|
26
|
+
version_release_note_hash[:url] = url
|
27
|
+
|
28
|
+
version_release_note_hash
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# See https://keepachangelog.com/en/1.0.0/#how
|
34
|
+
def change_types
|
35
|
+
%w[
|
36
|
+
added
|
37
|
+
changed
|
38
|
+
deprecated
|
39
|
+
removed
|
40
|
+
fixed
|
41
|
+
security
|
42
|
+
]
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_hash_from(version_release_note)
|
46
|
+
sections = version_release_note.split('### ')
|
47
|
+
|
48
|
+
# Removes trailing whitespaces
|
49
|
+
sections = sections.map { |section| section.gsub(/\s+$/, '') }
|
50
|
+
|
51
|
+
version, date = extract_version_and_date_from(sections.shift)
|
52
|
+
|
53
|
+
changes = extract_actions_from(sections)
|
54
|
+
|
55
|
+
{ version: version, date: date, changes: changes }
|
56
|
+
end
|
57
|
+
|
58
|
+
def detect_version_release_note_for(version)
|
59
|
+
version_number = fetch_version_number_from(version)
|
60
|
+
|
61
|
+
@versions.detect do |changelog_version|
|
62
|
+
changelog_version.start_with?("#{version_number}]") ||
|
63
|
+
changelog_version.start_with?("#{version}]")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def extract_actions_from(sections)
|
68
|
+
sections.each_with_object({}) do |section, accumulator|
|
69
|
+
type, logs = section.match(/^(#{change_types.join('|')})\n(.*)/mi)
|
70
|
+
&.captures
|
71
|
+
|
72
|
+
next unless type
|
73
|
+
|
74
|
+
type = type.downcase.to_sym
|
75
|
+
|
76
|
+
logs = logs.split(/\s+-/)
|
77
|
+
.reject(&:empty?)
|
78
|
+
.map { |log| log.gsub(/^\s+/, '') }
|
79
|
+
.map { |log| log.gsub("\n", ' ') }
|
80
|
+
|
81
|
+
accumulator[type] = logs
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def extract_version_and_date_from(section)
|
86
|
+
section.match(/([\d\.]+)\]\s+-\s+([\d+-]+)/)&.captures
|
87
|
+
end
|
88
|
+
|
89
|
+
def fetch_version_number_from(version)
|
90
|
+
version.match(/([\d\.]+)/)&.captures&.first
|
91
|
+
end
|
92
|
+
|
93
|
+
def fetch_version_url_for(version)
|
94
|
+
version_number = fetch_version_number_from(version)
|
95
|
+
@content.match(%r{\[#{version_number}\]: (https://[\S]+)})
|
96
|
+
&.captures
|
97
|
+
&.first
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Split the file on the double dashes, representing version sections.
|
102
|
+
#
|
103
|
+
def parse!
|
104
|
+
@versions = @content.split(/##\s\[/)
|
105
|
+
end
|
106
|
+
|
107
|
+
def version_is_valid?(version)
|
108
|
+
version =~ /[\d\.]+/
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: changelog-notifier
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Guillaume Hain
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-12-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: titleize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.4.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.4.1
|
27
|
+
description: This gem sends the release note, extracted from your CHANGELOG.md file,
|
28
|
+
to Slack when deployin with Capistrano
|
29
|
+
email:
|
30
|
+
- zedtux@zedroot.org
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".gitignore"
|
36
|
+
- ".gitlab-ci.yml"
|
37
|
+
- ".rspec"
|
38
|
+
- ".rubocop.yml"
|
39
|
+
- CHANGELOG.md
|
40
|
+
- CODE_OF_CONDUCT.md
|
41
|
+
- Dockerfile
|
42
|
+
- Gemfile
|
43
|
+
- Gemfile.lock
|
44
|
+
- LICENSE.txt
|
45
|
+
- README.md
|
46
|
+
- Rakefile
|
47
|
+
- bin/console
|
48
|
+
- bin/setup
|
49
|
+
- changelog-notifier.gemspec
|
50
|
+
- lib/changelog/notifier.rb
|
51
|
+
- lib/changelog/notifier/adapters/active_record.rb
|
52
|
+
- lib/changelog/notifier/adapters/base.rb
|
53
|
+
- lib/changelog/notifier/adapters/slack.rb
|
54
|
+
- lib/changelog/notifier/capistrano.rb
|
55
|
+
- lib/changelog/notifier/capistrano/tasks/changelog_notifier.rake
|
56
|
+
- lib/changelog/notifier/entrypoints/capistrano.rb
|
57
|
+
- lib/changelog/notifier/errors.rb
|
58
|
+
- lib/changelog/notifier/formatters/active_record.rb
|
59
|
+
- lib/changelog/notifier/formatters/slack.rb
|
60
|
+
- lib/changelog/notifier/git_commit_author_fetcher.rb
|
61
|
+
- lib/changelog/notifier/git_tag_fetcher.rb
|
62
|
+
- lib/changelog/notifier/parsers/markdown.rb
|
63
|
+
- lib/changelog/notifier/version.rb
|
64
|
+
- screenshots/changelog-notifiier_slack.png
|
65
|
+
homepage: https://gitlab.com/zedtux/changelog-notifier
|
66
|
+
licenses:
|
67
|
+
- MIT
|
68
|
+
metadata:
|
69
|
+
allowed_push_host: https://rubygems.org
|
70
|
+
homepage_uri: https://gitlab.com/zedtux/changelog-notifier
|
71
|
+
source_code_uri: https://gitlab.com/zedtux/changelog-notifier
|
72
|
+
changelog_uri: https://gitlab.com/zedtux/changelog-notifier/-/blob/master/CHANGELOG.md
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options: []
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 2.3.0
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubygems_version: 3.0.4
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: Sends current version's release note from your CHANGELOG.md file
|
92
|
+
test_files: []
|