mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Replace Towncrier with GitHub releases + labels. (#2966)
* Set up GitHub generated release notes. * Remove Towncrier from the release script. * Add changelog failures for Labels with Danger and stop requesting a changelog file. * Update changelog documentation.
This commit is contained in:
parent
567f22b806
commit
82823c94ce
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,8 +1,8 @@
|
|||||||
### Pull Request Checklist
|
### Pull Request Checklist
|
||||||
|
|
||||||
- [ ] I read the [contributing guide](https://github.com/element-hq/element-ios/blob/develop/CONTRIBUTING.md)
|
- [ ] I read the [contributing guide](https://github.com/element-hq/element-ios/blob/develop/CONTRIBUTING.md).
|
||||||
- [ ] Pull request contains a [changelog file](https://github.com/matrix-org/matrix-ios-sdk/blob/develop/CONTRIBUTING.md#changelog) in ./changelog.d
|
- [ ] Pull request contains a [changelog label](https://github.com/element-hq/element-x-ios/blob/develop/CONTRIBUTING.md#changelog).
|
||||||
- [ ] Pull request includes a [sign off](https://github.com/matrix-org/matrix-ios-sdk/blob/develop/CONTRIBUTING.md#sign-off)
|
- [ ] Pull request includes a [sign off](https://github.com/matrix-org/matrix-ios-sdk/blob/develop/CONTRIBUTING.md#sign-off).
|
||||||
|
|
||||||
**UI changes have been tested with:**
|
**UI changes have been tested with:**
|
||||||
- [ ] iPhone and iPad simulators in portrait and landscape orientations.
|
- [ ] iPhone and iPad simulators in portrait and landscape orientations.
|
||||||
|
31
.github/release.yml
vendored
Normal file
31
.github/release.yml
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
changelog:
|
||||||
|
categories:
|
||||||
|
- title: ✨ Features
|
||||||
|
labels:
|
||||||
|
- pr-feature
|
||||||
|
- title: 🙌 Improvements
|
||||||
|
labels:
|
||||||
|
- pr-change
|
||||||
|
- title: 🐛 Bugfixes
|
||||||
|
labels:
|
||||||
|
- pr-bugfix
|
||||||
|
- title: ⚠️ API Changes
|
||||||
|
labels:
|
||||||
|
- pr-api
|
||||||
|
- title: 🗣 Translations
|
||||||
|
labels:
|
||||||
|
- pr-i18n
|
||||||
|
- title: 🧱 Build
|
||||||
|
labels:
|
||||||
|
- pr-build
|
||||||
|
- title: 📄 Documentation
|
||||||
|
labels:
|
||||||
|
- pr-doc
|
||||||
|
- title: 🚧 In development 🚧
|
||||||
|
labels:
|
||||||
|
- pr-wip
|
||||||
|
|
||||||
|
- title: Others
|
||||||
|
labels:
|
||||||
|
- pr-misc
|
||||||
|
- "*"
|
@ -99,55 +99,7 @@ New screen flows are currently using the MVVM-Coordinator pattern. Please refer
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
All changes, even minor ones, need a corresponding changelog / newsfragment
|
Our [changelog](CHANGES.md) is automatically generated by GitHub, based on the PR title that you use when opening the issue. The changelog can be categorised by applying on of the [`pr-` labels](https://github.com/element-hq/element-x-ios/labels?q=pr-) to your PR. The mapping of Label → Section can be found in the [release.yml](.github/release.yml) file. The contribution will be automatically credited to your GitHub username.
|
||||||
entry. These are managed by [Towncrier](https://github.com/twisted/towncrier).
|
|
||||||
|
|
||||||
To create a changelog entry, make a new file in the `changelog.d` directory
|
|
||||||
named in the format of `ElementXiOSIssueNumber.type`. The type can be one of the
|
|
||||||
following:
|
|
||||||
|
|
||||||
- `feature` for a new feature
|
|
||||||
- `change` for updates to an existing feature
|
|
||||||
- `bugfix` for bug fix
|
|
||||||
- `api` for an api break
|
|
||||||
- `i18n` for translations
|
|
||||||
- `build` for changes related to build, tools, CI/CD
|
|
||||||
- `doc` for updates to the documentation
|
|
||||||
- `wip` for anything that isn't ready to ship and will be enabled at a later date
|
|
||||||
- `misc` for other changes
|
|
||||||
|
|
||||||
This file will become part of our [changelog](CHANGES.md) at the next
|
|
||||||
release, so the content of the file should be a short description of your
|
|
||||||
change in the same style as the rest of the changelog. The file must only
|
|
||||||
contain one line. It can contain Markdown formatting. It should start with the
|
|
||||||
area of the change (screen, module, ...) and end with a full stop (.) or an
|
|
||||||
exclamation mark (!) for consistency.
|
|
||||||
|
|
||||||
Adding credits to the changelog is encouraged, we value your
|
|
||||||
contributions and would like to have you shouted out in the release notes!
|
|
||||||
|
|
||||||
For example, a fix for an issue #1234 would have its changelog entry in
|
|
||||||
`changelog.d/1234.bugfix`, and contain content like:
|
|
||||||
|
|
||||||
> Voice Messages: Fix a crash when sending a voice message. Contributed by
|
|
||||||
> Jane Matrix.
|
|
||||||
|
|
||||||
If there are multiple pull requests involved in a single bugfix/feature/etc,
|
|
||||||
then the content for each `changelog.d` file should be the same. Towncrier will
|
|
||||||
merge the matching files together into a single changelog entry when we come to
|
|
||||||
release.
|
|
||||||
|
|
||||||
There are exceptions on the `ElementXiOSIssueNumber.type` entry format. Even if
|
|
||||||
it is not encouraged, you can use:
|
|
||||||
|
|
||||||
- `pr-[PRNumber].type` for a PR with no related issue
|
|
||||||
- `x-nolink-[AnyNumber].type` for a PR with a change entry that will not have a link automatically appended. It must be used for internal project update only. `AnyNumber` should be a value that does not clash with existing files.
|
|
||||||
|
|
||||||
To preview the changelog for pending changelog entries, use:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ towncrier build --draft --version 1.2.3
|
|
||||||
```
|
|
||||||
|
|
||||||
## Coding style
|
## Coding style
|
||||||
|
|
||||||
|
@ -5,6 +5,9 @@ SwiftLint.lint(inline: true)
|
|||||||
|
|
||||||
let danger = Danger()
|
let danger = Danger()
|
||||||
|
|
||||||
|
// All of the new and modified files together.
|
||||||
|
let editedFiles = danger.git.modifiedFiles + danger.git.createdFiles
|
||||||
|
|
||||||
// Warn when there is a big PR
|
// Warn when there is a big PR
|
||||||
if (danger.github.pullRequest.additions ?? 0) > 1000 {
|
if (danger.github.pullRequest.additions ?? 0) > 1000 {
|
||||||
warn("This pull request seems relatively large. Please consider splitting it into multiple smaller ones.")
|
warn("This pull request seems relatively large. Please consider splitting it into multiple smaller ones.")
|
||||||
@ -15,14 +18,6 @@ if danger.github.pullRequest.body?.isEmpty ?? true {
|
|||||||
warn("Please provide a description for this PR.")
|
warn("Please provide a description for this PR.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request a changelog for each app change
|
|
||||||
let editedFiles = danger.git.modifiedFiles + danger.git.createdFiles
|
|
||||||
let changelogFiles = editedFiles.filter { $0.hasPrefix("changelog.d/") }
|
|
||||||
|
|
||||||
if editedFiles.count > 0, changelogFiles.isEmpty {
|
|
||||||
warn("Please add a changelog.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for a ticket number
|
// Check for a ticket number
|
||||||
if let ticketNumberRegex = try? NSRegularExpression(pattern: "#\\d+") {
|
if let ticketNumberRegex = try? NSRegularExpression(pattern: "#\\d+") {
|
||||||
let missingTicketNumber = !danger.git.commits.filter {
|
let missingTicketNumber = !danger.git.commits.filter {
|
||||||
@ -84,3 +79,11 @@ let hasPngs = !editedFiles.filter { $0.lowercased().contains(".xcassets") && $0.
|
|||||||
if hasPngs {
|
if hasPngs {
|
||||||
warn("You seem to have made changes to some resource images. Please consider using an SVG or PDF.")
|
warn("You seem to have made changes to some resource images. Please consider using an SVG or PDF.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if danger.github.pullRequest.title.hasSuffix("…") {
|
||||||
|
fail("Please provide a complete title that can be used as a changelog entry.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if danger.github.issue.labels.filter({ $0.name.hasPrefix("pr-") }).count != 1 {
|
||||||
|
fail("Please add a `pr-` label to categorise the changelog entry.")
|
||||||
|
}
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
{# iOS Repositories #}
|
|
||||||
{%- set gh_sdk = "https://github.com/matrix-org/matrix-rust-sdk" -%}
|
|
||||||
{%- set gh_element = "https://github.com/element-hq/element-x-ios" -%}
|
|
||||||
|
|
||||||
## {{ versiondata.name }} {{ versiondata.version }} ({{ versiondata.date }})
|
|
||||||
{% for section, _ in sections.items() %}
|
|
||||||
|
|
||||||
{% if sections[section] %}
|
|
||||||
{% for category, val in definitions.items() if category in sections[section]%}
|
|
||||||
{{ definitions[category]['name'] }}
|
|
||||||
|
|
||||||
{% if definitions[category]['showcontent'] %}
|
|
||||||
{% for text, values in sections[section][category].items() %}
|
|
||||||
{# Build all types of links we can have from our different repositories #}
|
|
||||||
{%- set links = [] -%}
|
|
||||||
{%- for value in values %}
|
|
||||||
{%- if value.startswith("sdk-") %}
|
|
||||||
{%- set gh_issue = value.replace("sdk-", "") -%}
|
|
||||||
{{- links.append( "[#%s](%s/issues/%s)" | format(gh_issue, gh_sdk, gh_issue) ) | default("", True) -}}
|
|
||||||
{%- elif value.startswith("#") %}
|
|
||||||
{%- set gh_issue = value.replace("#", "") -%}
|
|
||||||
{{- links.append( "[#%s](%s/issues/%s)" | format(gh_issue, gh_element, gh_issue) ) | default("", True) -}}
|
|
||||||
{%- elif value.startswith("pr-") %}
|
|
||||||
{%- set pr = value.replace("pr-", "") -%}
|
|
||||||
{{- links.append( "[#%s](%s/pull/%s)" | format(pr, gh_element, pr) ) | default("", True) -}}
|
|
||||||
{%- elif value.startswith("x-nolink-") %}
|
|
||||||
{{- nil | default("", True) -}}
|
|
||||||
{% else %}
|
|
||||||
{{- links.append(value) | default("", True) -}}
|
|
||||||
{% endif -%}
|
|
||||||
{% endfor -%}
|
|
||||||
{% if links|length == 0 %}
|
|
||||||
- {{ text }}
|
|
||||||
{% else %}
|
|
||||||
- {{ text }} ({{ links | join(', ') }})
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
- {{ sections[section][category]['']|join(', ') }}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
{% if sections[section][category]|length == 0 %}
|
|
||||||
No significant changes.
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
No significant changes.
|
|
||||||
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
@ -38,10 +38,6 @@ install_xcode_cloud_brew_dependencies () {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install_xcode_cloud_python_dependencies () {
|
|
||||||
pip3 install towncrier # Install towncrier for generating changelogs
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_github_actions_environment() {
|
setup_github_actions_environment() {
|
||||||
unset HOMEBREW_NO_INSTALL_FROM_API
|
unset HOMEBREW_NO_INSTALL_FROM_API
|
||||||
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
||||||
|
@ -11,8 +11,6 @@ bundle exec fastlane upload_dsyms_to_sentry dsym_path:"$CI_ARCHIVE_PATH/dSYMs"
|
|||||||
generate_what_to_test_notes
|
generate_what_to_test_notes
|
||||||
|
|
||||||
if [ "$CI_WORKFLOW" = "Release" ]; then
|
if [ "$CI_WORKFLOW" = "Release" ]; then
|
||||||
install_xcode_cloud_python_dependencies
|
|
||||||
|
|
||||||
bundle exec fastlane release_to_github
|
bundle exec fastlane release_to_github
|
||||||
bundle exec fastlane prepare_next_release
|
bundle exec fastlane prepare_next_release
|
||||||
elif [ "$CI_WORKFLOW" = "Nightly" ]; then
|
elif [ "$CI_WORKFLOW" = "Nightly" ]; then
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
require 'yaml'
|
require 'yaml'
|
||||||
require 'semantic'
|
require 'semantic'
|
||||||
require_relative 'changelog'
|
|
||||||
|
|
||||||
before_all do
|
before_all do
|
||||||
xcversion(version: "15.2")
|
xcversion(version: "15.2")
|
||||||
@ -208,35 +207,30 @@ lane :release_to_github do
|
|||||||
api_token = ENV["GITHUB_TOKEN"]
|
api_token = ENV["GITHUB_TOKEN"]
|
||||||
UI.user_error!("Invalid GitHub API token.") unless !api_token.to_s.empty?
|
UI.user_error!("Invalid GitHub API token.") unless !api_token.to_s.empty?
|
||||||
|
|
||||||
# Get the Diawi link from Diawi action shared value
|
|
||||||
diawi_link = lane_context[SharedValues::UPLOADED_FILE_LINK_TO_DIAWI]
|
|
||||||
|
|
||||||
release_version = get_version_number(target: "ElementX")
|
release_version = get_version_number(target: "ElementX")
|
||||||
|
|
||||||
changes = export_version_changes(version: release_version)
|
|
||||||
|
|
||||||
description = ""
|
|
||||||
if diawi_link.nil?
|
|
||||||
description = "#{changes}"
|
|
||||||
else
|
|
||||||
# Generate the Diawi QR code file link
|
|
||||||
diawi_app_id = URI(diawi_link).path.split('/').last
|
|
||||||
diawi_qr_code_link = "https://www.diawi.com/qrcode/link/#{diawi_app_id}"
|
|
||||||
|
|
||||||
"[iOS AdHoc Release - Diawi Link](#{diawi_link})
|
|
||||||

|
|
||||||
#{changes}"
|
|
||||||
end
|
|
||||||
|
|
||||||
github_release = set_github_release(
|
github_release = set_github_release(
|
||||||
repository_name: "element-hq/element-x-ios",
|
repository_name: "element-hq/element-x-ios",
|
||||||
api_token: api_token,
|
api_token: api_token,
|
||||||
name: release_version,
|
name: release_version,
|
||||||
tag_name: release_version,
|
tag_name: release_version,
|
||||||
is_generate_release_notes: false,
|
is_generate_release_notes: true,
|
||||||
description: description
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
release_date = Date.today.strftime("%Y-%m-%d")
|
||||||
|
generated_notes = github_release["body"].gsub(/<!-- .*? -->/, '').gsub("### ", "\n").gsub("## ", "### ")
|
||||||
|
UI.user_error!("The generated release notes are missing!") unless !generated_notes.to_s.empty?
|
||||||
|
|
||||||
|
# Prepend the new release notes to the CHANGES.md file
|
||||||
|
changes_file = "../CHANGES.md"
|
||||||
|
File.open(changes_file, "r+") do |file|
|
||||||
|
content = file.read
|
||||||
|
file.rewind
|
||||||
|
file.write("## Changes in #{release_version} (#{release_date})#{generated_notes}\n\n#{content}")
|
||||||
|
end
|
||||||
|
|
||||||
|
# The changelog will be committed when prepare_next_release is called.
|
||||||
|
sh("git add #{changes_file}")
|
||||||
end
|
end
|
||||||
|
|
||||||
lane :prepare_next_release do
|
lane :prepare_next_release do
|
||||||
@ -366,13 +360,6 @@ private_lane :bump_build_number do
|
|||||||
increment_build_number(build_number: build_number)
|
increment_build_number(build_number: build_number)
|
||||||
end
|
end
|
||||||
|
|
||||||
private_lane :export_version_changes do |options|
|
|
||||||
Dir.chdir("..") do
|
|
||||||
Changelog.update_topmost_section(version: options[:version], additional_entries: {})
|
|
||||||
Changelog.extract_first_section
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private_lane :update_app_icon do |options|
|
private_lane :update_app_icon do |options|
|
||||||
caption_text = options[:caption_text]
|
caption_text = options[:caption_text]
|
||||||
UI.user_error!("Invalid caption text.") unless !caption_text.to_s.empty?
|
UI.user_error!("Invalid caption text.") unless !caption_text.to_s.empty?
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2020 New Vector Ltd
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require "tempfile"
|
|
||||||
require "fileutils"
|
|
||||||
require "date"
|
|
||||||
|
|
||||||
# Helper methods to handle updates of the Changelog file
|
|
||||||
#
|
|
||||||
module Changelog
|
|
||||||
CHANGES_SEPARATOR_REGEX = /^\#\#\ Changes/.freeze
|
|
||||||
FILE = "CHANGES.md"
|
|
||||||
|
|
||||||
# Update the topmost section of the changelog to put version+date in title + add entry for dependency updates
|
|
||||||
#
|
|
||||||
# @param [String] version The version that we are releasing to use in the new title of the first section
|
|
||||||
# @param [Hash<String, Array<String>>] additional_entries
|
|
||||||
# List of lines/entries to add under the each subsection of the first section
|
|
||||||
# The keys of the hash are the name of the subsections, without trailing`:`, e.g. "Improvements".
|
|
||||||
# The values are the list of lines to add to that subsection
|
|
||||||
# (the ` * ` bullet point will be added automatically for each line)
|
|
||||||
#
|
|
||||||
def self.update_topmost_section(version:, additional_entries:)
|
|
||||||
|
|
||||||
# Create temporary towncrier changelog entries for additional entries
|
|
||||||
# Use a low index to make them appear first
|
|
||||||
# Those additional entries are basically dependency updates
|
|
||||||
entry_count = 0
|
|
||||||
additional_entries.each do |subsection, entries|
|
|
||||||
entries.each do |entry|
|
|
||||||
file = "changelog.d/x-nolink-#{entry_count}.#{subsection}"
|
|
||||||
File.write(file, "#{entry}")
|
|
||||||
Git.add!(files: file)
|
|
||||||
Git.commit!(message: "changelog.d: #{entry}", add_all: true)
|
|
||||||
entry_count += 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Let towncrier update the change
|
|
||||||
system("towncrier", "build", "--version", "#{version}", "--yes")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the first section of the Changelog, corresponding to the changes in the latest version
|
|
||||||
#
|
|
||||||
def self.extract_first_section
|
|
||||||
lines = []
|
|
||||||
File.open(FILE, "r") do |file|
|
|
||||||
section_index = 0
|
|
||||||
file.each_line do |line|
|
|
||||||
is_separator_line = (line.chomp =~ CHANGES_SEPARATOR_REGEX)
|
|
||||||
section_index += 1 if is_separator_line
|
|
||||||
break if section_index >= 2
|
|
||||||
|
|
||||||
lines.append(line) if section_index == 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
lines[0..-2].join # Remove last line (title of section 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,50 +0,0 @@
|
|||||||
[tool.towncrier]
|
|
||||||
name = "Changes in"
|
|
||||||
filename = "CHANGES.md"
|
|
||||||
directory = "changelog.d"
|
|
||||||
template = "changelog.d/_template.md.jinja"
|
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
|
||||||
directory = "feature"
|
|
||||||
name = "✨ Features"
|
|
||||||
showcontent = true
|
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
|
||||||
directory = "change"
|
|
||||||
name = "🙌 Improvements"
|
|
||||||
showcontent = true
|
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
|
||||||
directory = "bugfix"
|
|
||||||
name = "🐛 Bugfixes"
|
|
||||||
showcontent = true
|
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
|
||||||
directory = "api"
|
|
||||||
name = "⚠️ API Changes"
|
|
||||||
showcontent = true
|
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
|
||||||
directory = "i18n"
|
|
||||||
name = "🗣 Translations"
|
|
||||||
showcontent = true
|
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
|
||||||
directory = "build"
|
|
||||||
name = "🧱 Build"
|
|
||||||
showcontent = true
|
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
|
||||||
directory = "doc"
|
|
||||||
name = "📄 Documentation"
|
|
||||||
showcontent = true
|
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
|
||||||
directory = "wip"
|
|
||||||
name = "🚧 In development 🚧"
|
|
||||||
showcontent = true
|
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
|
||||||
directory = "misc"
|
|
||||||
name = "Others"
|
|
||||||
showcontent = true
|
|
Loading…
x
Reference in New Issue
Block a user