Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,27 @@

### Breaking Changes

_None_
- Generated PO files now have entries sorted **alphabetically by `msgctxt`** for deterministic output. This may affect tests or tooling that depend on a specific entry order. [#684]
- Existing translator comments (`#.` lines) in PO files will be **lost** when regenerating unless explicitly added to the `source_files` parameter. See `MIGRATION.md` for instructions on preserving comments. [#684]

### New Features

_None_
- Add `commit_changes` option to `gp_update_metadata_source` to optionally commit changes after updating the PO file. [#684]
- Add support for translator comments in `gp_update_metadata_source` via a new hash format for `source_files` entries: `{ path: 'file.txt', comment: 'translators: ...' }`. Simple string paths are still supported for entries without comments. [#684]

### Bug Fixes

_None_

### Internal Changes

_None_
- Consolidate PO file update logic on `gp_update_metadata_source` action. [#684]
- Remove legacy `MetadataBlock` classes replaced by the new `PoFileGenerator`. [#684]

### Deprecated

- `an_update_metadata_source` action is deprecated; use `gp_update_metadata_source` instead. The API is unchanged, but generated PO files will have different ordering and comments will be lost unless migrated to use the new comment format. [#684]
- `ios_update_metadata_source` action is deprecated; use `gp_update_metadata_source` with `commit_changes: true` instead. The API is unchanged, but generated PO files will have different ordering and comments will be lost unless migrated to use the new comment format. [#684]

## 13.8.1

Expand Down
15 changes: 15 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ PATH
chroma (= 0.2.0)
diffy (~> 3.3)
fastlane (~> 2.213)
gettext (~> 3.5)
git (~> 1.3)
google-cloud-storage (~> 1.31)
java-properties (~> 0.3.0)
Expand Down Expand Up @@ -163,6 +164,7 @@ GEM
dotenv (2.8.1)
drb (2.2.1)
emoji_regex (3.2.3)
erubi (1.13.1)
escape (0.0.4)
ethon (0.16.0)
ffi (>= 1.15.0)
Expand Down Expand Up @@ -243,8 +245,15 @@ GEM
fastlane-sirp (1.0.0)
sysrandom (~> 1.0)
ffi (1.17.1)
forwardable (1.3.3)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gettext (3.5.1)
erubi
locale (>= 2.0.5)
prime
racc
text (>= 1.3.0)
gh_inspector (1.1.3)
git (1.19.1)
addressable (~> 2.8)
Expand Down Expand Up @@ -304,6 +313,7 @@ GEM
kramdown (~> 2.0)
language_server-protocol (3.17.0.4)
lint_roller (1.1.0)
locale (2.1.4)
logger (1.6.6)
method_source (0.9.2)
mini_magick (4.13.2)
Expand Down Expand Up @@ -336,6 +346,9 @@ GEM
racc
pkg-config (1.6.0)
plist (3.7.2)
prime (0.1.3)
forwardable
singleton
progress_bar (1.3.4)
highline (>= 1.6)
options (~> 2.3.0)
Expand Down Expand Up @@ -413,10 +426,12 @@ GEM
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
singleton (0.3.0)
sysrandom (1.0.5)
terminal-notifier (2.0.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
text (1.3.1)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.2)
Expand Down
67 changes: 67 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,72 @@
# Migration Instructions for Major Releases

## From 13.x to 14.0.0

### Metadata Source Actions

The `ios_update_metadata_source` and `an_update_metadata_source` actions are now deprecated. Use `gp_update_metadata_source` instead:

```ruby
# Before (iOS)
ios_update_metadata_source(
po_file_path: 'path/to/AppStoreStrings.pot',
source_files: { app_name: 'path/to/name.txt' },
release_version: '1.0'
)

# Before (Android)
an_update_metadata_source(
po_file_path: 'path/to/PlayStoreStrings.po',
source_files: { app_name: 'path/to/name.txt' },
release_version: '1.0'
)

# After (both platforms)
gp_update_metadata_source(
po_file_path: 'path/to/AppStoreStrings.pot',
source_files: { app_name: 'path/to/name.txt' },
release_version: '1.0',
commit_changes: true # Set to true if you want auto-commit (like ios_update_metadata_source did)
)
```

### Translator Comments in PO Files

**Important:** The new `gp_update_metadata_source` action regenerates PO files from scratch. Any existing translator comments (lines starting with `#.`) in your PO files will be **lost** unless you explicitly add them to your `source_files` hash.

To preserve translator comments, update your `source_files` to use the new hash format with `:path` and `:comment` keys:

```ruby
# Before (comments in PO file will be lost)
source_files: {
app_store_subtitle: 'path/to/subtitle.txt',
app_store_keywords: 'path/to/keywords.txt'
}

# After (comments are preserved in generated PO)
source_files: {
app_store_subtitle: {
path: 'path/to/subtitle.txt',
comment: 'translators: Limit to 30 characters!'
},
app_store_keywords: {
path: 'path/to/keywords.txt',
comment: "translators: Delimit with commas.\nLimit to 100 characters."
},
# Simple paths still work for entries without comments
app_name: 'path/to/name.txt'
}
```

**Migration steps:**
1. Check your existing `.po`/`.pot` files for any `#.` comment lines
2. Extract those comments and add them to the `source_files` hash in your Fastfile
3. Replace `ios_update_metadata_source`/`an_update_metadata_source` with `gp_update_metadata_source`

### PO File Entry Ordering

Generated PO files now have entries sorted **alphabetically by `msgctxt`**. This ensures deterministic output across runs. If you have tests or tooling that depend on a specific entry order, they may need to be updated.

## From 12.x to 13.0.0

- The `prototype_build_details_comment` action have been updated to work with Firebase App Distribution instead of App Center [#630].
Expand Down
5 changes: 3 additions & 2 deletions fastlane-plugin-wpmreleasetoolkit.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'fastlane/plugin/wpmreleasetoolkit/version'

Gem::Specification.new do |spec|
spec.name = 'fastlane-plugin-wpmreleasetoolkit'
spec.name = Fastlane::Wpmreleasetoolkit::NAME
spec.version = Fastlane::Wpmreleasetoolkit::VERSION
spec.author = 'Automattic'
spec.email = 'mobile@automattic.com'

spec.summary = 'GitHub helper functions'
spec.summary = 'Fastlane plugin for release automation'
spec.homepage = 'https://github.com/wordpress-mobile/release-toolkit'
spec.license = 'MIT'

Expand All @@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
spec.add_dependency 'chroma', '0.2.0'
spec.add_dependency 'diffy', '~> 3.3'
spec.add_dependency 'fastlane', '~> 2.213'
spec.add_dependency 'gettext', '~> 3.5'
spec.add_dependency 'git', '~> 1.3'
spec.add_dependency 'java-properties', '~> 0.3.0'
spec.add_dependency 'nokogiri', '~> 1.11'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,157 +1,51 @@
# frozen_string_literal: true

require 'fastlane/action'
require_relative '../../helper/metadata/release_note_metadata_block'
require_relative '../../helper/metadata/release_note_short_metadata_block'
require_relative '../../helper/metadata/whats_new_metadata_block'

module Fastlane
module Actions
class AnUpdateMetadataSourceAction < Action
def self.run(params)
# fastlane will take care of reading in the parameter and fetching the environment variable:
UI.message "Parameter .po file path: #{params[:po_file_path]}"
UI.message "Release version: #{params[:release_version]}"

# Init
create_block_parsers(params[:release_version], params[:source_files])

# Do
check_source_files(params[:source_files])
temp_po_name = create_temp_po(params)
swap_po(params[:po_file_path], temp_po_name)

UI.message "File #{params[:po_file_path]} updated!"
end

# Verifies that all the source files are available
# to this action
def self.check_source_files(source_files)
source_files.each_value do |file_path|
UI.user_error!("Couldn't find file at path '#{file_path}'") unless File.exist?(file_path)
end
end

# Creates a temp po file merging
# new data for known tags
# and the data already in the original
# .po fo the others.
def self.create_temp_po(params)
orig = params[:po_file_path]
target = create_target_file_path(orig)

# Clear if older exists
FileUtils.rm_f(target)

# Create the new one
begin
File.open(target, 'a') do |fw|
File.open(orig, 'r').each do |fr|
write_target_block(fw, fr)
end
end
rescue StandardError
FileUtils.rm_f(target)
raise
end

target
end

# Deletes the old po and moves the temp one
# to the final location
def self.swap_po(orig_file_path, temp_file_path)
FileUtils.rm_f(orig_file_path)
File.rename(temp_file_path, orig_file_path)
end

# Generates the temp file path
def self.create_target_file_path(orig_file_path)
"#{File.dirname(orig_file_path)}/#{File.basename(orig_file_path, '.*')}.tmp"
end

# Creates the block instances
def self.create_block_parsers(release_version, block_files)
@blocks = []

# Inits default handler
@blocks.push Fastlane::Helper::UnknownMetadataBlock.new

# Init special handlers
block_files.each do |key, file_path|
case key
when :release_note
@blocks.push Fastlane::Helper::ReleaseNoteMetadataBlock.new(key, file_path, release_version)
when :release_note_short
@blocks.push Fastlane::Helper::ReleaseNoteShortMetadataBlock.new(key, file_path, release_version)
else
@blocks.push Fastlane::Helper::StandardMetadataBlock.new(key, file_path)
end
end

# Sets the default
@current_block = @blocks[0]
end

# Manages tags depending on the type
def self.write_target_block(fw, line)
if is_block_id(line)
key = line.split[1].tr('\"', '')
@blocks.each do |block|
@current_block = block if block.is_handler_for(key)
end
end

@current_block = @blocks.first if is_comment(line)
UI.deprecated('`an_update_metadata_source` is deprecated. Please use `gp_update_metadata_source` instead.')

@current_block.handle_line(fw, line)
end

def self.is_block_id(line)
line.start_with?('msgctxt')
end

def self.is_comment(line)
line.start_with?('#')
other_action.gp_update_metadata_source(
po_file_path: params[:po_file_path],
source_files: params[:source_files],
release_version: params[:release_version]
)
end

#####################################################
# @!group Documentation
#####################################################

def self.description
'Updates a .po file with new data from .txt files'
'Generates a .po file from source .txt files'
end

def self.details
'You can use this action to update the .po file that contains the string to load to GlotPress for localization.'
'Generates a .po file from source .txt files for localization via GlotPress.'
end

def self.available_options
# Define all options your action supports.

# Below a few examples
[
FastlaneCore::ConfigItem.new(key: :po_file_path,
env_name: 'FL_UPDATE_METADATA_SOURCE_PO_FILE_PATH',
description: 'The path of the .po file to update',
description: 'The path of the .po file to generate',
type: String,
verify_block: proc do |value|
UI.user_error!("No .po file path for UpdateMetadataSourceAction given, pass using `po_file_path: 'file path'`") unless value && !value.empty?
UI.user_error!("Couldn't find file at path '#{value}'") unless File.exist?(value)
UI.user_error!("No .po file path given, pass using `po_file_path: 'file path'`") unless value && !value.empty?
end),
FastlaneCore::ConfigItem.new(key: :release_version,
env_name: 'FL_UPDATE_METADATA_SOURCE_RELEASE_VERSION',
description: 'The release version of the app (to use to mark the release notes)',
description: 'The release version of the app (used for release notes)',
verify_block: proc do |value|
UI.user_error!("No relase version for UpdateMetadataSourceAction given, pass using `release_version: 'version'`") unless value && !value.empty?
UI.user_error!("No release version given, pass using `release_version: 'version'`") unless value && !value.empty?
end),
FastlaneCore::ConfigItem.new(key: :source_files,
env_name: 'FL_UPDATE_METADATA_SOURCE_SOURCE_FILES',
description: 'The hash with the path to the source files and the key to use to include their content',
description: 'Hash mapping keys to source file paths',
type: Hash,
verify_block: proc do |value|
UI.user_error!("No source file hash for UpdateMetadataSourceAction given, pass using `source_files: 'source file hash'`") unless value && !value.empty?
UI.user_error!("No source files given, pass using `source_files: { key: 'path' }`") unless value && !value.empty?
end),
]
end
Expand All @@ -160,7 +54,6 @@ def self.output
end

def self.return_value
# If your method provides a return value, you can describe here what it does
end

def self.authors
Expand All @@ -170,6 +63,10 @@ def self.authors
def self.is_supported?(platform)
[:android].include?(platform)
end

def self.deprecated?
true
end
end
end
end
Loading