Skip to content

Commit

Permalink
Replace Travis CI with github actions
Browse files Browse the repository at this point in the history
  • Loading branch information
sndnv committed Dec 17, 2023
1 parent bd3a2b9 commit 74f8be7
Show file tree
Hide file tree
Showing 7 changed files with 317 additions and 16 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: asciichart Build

on: [push, pull_request]

env:
MIX_ENV: test

jobs:
elixir:
runs-on: ubuntu-latest
name: OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}}
strategy:
matrix:
otp: ['24.3']
elixir: ['1.13', '1.14', '1.15']

steps:
- uses: actions/checkout@v3

- uses: erlef/setup-beam@v1
with:
otp-version: ${{matrix.otp}}
elixir-version: ${{matrix.elixir}}

- name: Run QA
run: |
mix deps.get
mix deps.compile
mix test
mix coveralls.json
- name: Push Coverage Result
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
42 changes: 42 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: asciichart Publish

on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
workflow_dispatch:

env:
ELIXIR_VERSION: "1.15"
OTP_VERSION: "24.3"
HEX_API_KEY: ${{ secrets.HEX_API_KEY }}

jobs:
elixir:
runs-on: ubuntu-latest

permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@v4

- uses: erlef/setup-beam@v1
with:
elixir-version: ${{ env.ELIXIR_VERSION }}
otp-version: ${{ env.OTP_VERSION }}

- name: Build and publish
run: |
mix deps.get
mix deps.compile
mix hex.publish --yes
release:
runs-on: ubuntu-latest
needs:
- elixir
steps:
- name: Release
uses: softprops/action-gh-release@v1
48 changes: 48 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: asciichart Release

on:
workflow_dispatch:
inputs:
next_version:
description: 'Next release version'
required: true
default: 'patch'
type: choice
options:
- patch
- minor
- major
verbose:
description: 'Enable debug logging during release'
required: false
type: boolean

jobs:
release:
runs-on: ubuntu-latest

if: github.ref == 'refs/heads/master'

steps:
- uses: actions/checkout@v4
with:
ssh-key: ${{secrets.RELEASE_KEY}}
ref: master

- name: Setup Python 3
uses: actions/setup-python@v4
with:
python-version: '3.10'

- name: Release project
run: |
pip install semver
git config --global user.name ${{github.actor}}
git config --global user.email ${{github.actor}}@users.noreply.github.com
./release.py $VERBOSE --next $NEXT_VERSION
git push
git push --tags
env:
NEXT_VERSION: ${{ inputs.next_version }}
VERBOSE: ${{ inputs.verbose && '--verbose' || '' }}
14 changes: 0 additions & 14 deletions .travis.yml

This file was deleted.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# asciichart

[![Hex version badge](https://img.shields.io/hexpm/v/asciichart.svg)](https://hex.pm/packages/asciichart) [![Travis](https://travis-ci.org/sndnv/asciichart.svg?branch=master)](https://travis-ci.org/sndnv/asciichart) [![Coverage Status](https://coveralls.io/repos/github/sndnv/asciichart/badge.svg?branch=master)](https://coveralls.io/github/sndnv/asciichart?branch=master) [![license](https://img.shields.io/github/license/sndnv/asciichart.svg)]()
[![Hex version badge](https://img.shields.io/hexpm/v/asciichart.svg)](https://hex.pm/packages/asciichart) [![codecov](https://codecov.io/gh/sndnv/asciichart/graph/badge.svg?token=EVAYGZRRZB)](https://codecov.io/gh/sndnv/asciichart) [![license](https://img.shields.io/github/license/sndnv/asciichart.svg)]()

Terminal ASCII line charts in Elixir with no dependencies.

Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Asciichart.MixProject do
[
app: :asciichart,
version: "1.1.1-SNAPSHOT",
elixir: "~> 1.15",
elixir: "~> 1.7",
start_permanent: Mix.env() == :prod,
package: package(),
deps: deps(),
Expand Down
190 changes: 190 additions & 0 deletions release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#!/usr/bin/env python3

import argparse
import logging
import re
import semver
import subprocess
import sys

DESCRIPTION = ('Bumps all versions across the project to the next release version, '
'commits and tags the changes, and updates to the next snapshot version')


def require_no_changes():
build_result = subprocess.run(['git', 'status', '--porcelain'], capture_output=True, text=True)
output = build_result.stdout.split('\n') + build_result.stderr.split('\n')
output = list(filter(None, output))

if len(output) == 0:
logging.debug('No changes found in repo')
else:
logging.error('Release failed - uncommitted changes found in repo [\n {}\n]'.format('\n '.join(output)))
sys.exit(1)


def require_version_updated(next_version, updated_version):
if updated_version == next_version:
logging.debug('Version change applied')
else:
logging.error(
'Release failed - expected updated version to be [{}] but [{}] found'.format(
next_version,
updated_version
)
)
sys.exit(1)


def get_version_from(version_file, with_version_regex):
with open(version_file) as f:
content = f.readlines()
pattern = re.compile(with_version_regex)
match = next(filter(lambda m: m is not None, map(lambda line: pattern.match(line), content)), None)
if match:
logging.debug(
'Loaded version [{}] from file [{}] with regex [{}]'.format(
match.group(1),
version_file,
with_version_regex
)
)
return match.group(1).replace('+', '-')
else:
logging.error('Release failed - could not find version in [{}]'.format(version_file))
sys.exit(1)


def get_current_version(version_files):
versions = {}
for version_file, version_regex in version_files.items():
versions[version_file] = get_version_from(version_file=version_file, with_version_regex=version_regex)

unique_versions = list(set(versions.values()))

if len(unique_versions) != 1:
logging.error(
'Release failed - found [{}] different versions ({}) in [\n {}\n]'.format(
len(unique_versions),
', '.join(unique_versions),
'\n '.join(map(lambda e: '[{}] in {}'.format(e[1], e[0]), versions.items()))
)
)
sys.exit(1)
else:
return list(versions.values())[0]


def get_next_version(current_version, next_version):
current = semver.Version.parse(current_version)

next = {
'patch': current.bump_patch() if not current_version.endswith('-SNAPSHOT') else semver.Version.parse(
current_version.replace('-SNAPSHOT', '')),
'minor': current.bump_minor(),
'major': current.bump_major(),
}.get(next_version.lower())

return str(next or semver.Version.parse(next_version))


def apply_next_version_to(version_file, current_version, next_version, with_version_regex):
with open(version_file, 'r') as f:
content = f.readlines()
pattern = re.compile(with_version_regex)
actual_current_version = current_version.replace('-', '+') if 'setup.py' in version_file else current_version
actual_next_version = next_version.replace('-', '+') if 'setup.py' in version_file else next_version
updated = list(
map(
lambda line: line.replace(actual_current_version, actual_next_version) if pattern.match(line) else line,
content
)
)

with open(version_file, 'w') as f:
f.write(''.join(updated))


def apply_next_version(version_files, current_version, next_version):
for version_file, version_regex in version_files.items():
apply_next_version_to(
version_file=version_file,
current_version=current_version,
next_version=next_version,
with_version_regex=version_regex
)


def exec_git_command(command):
if subprocess.run(command).returncode == 0:
logging.debug('Executed git command [{}]'.format(' '.join(command)))
else:
logging.error('Release failed - could not execute git command [{}]'.format(' '.join(command)))
sys.exit(1)


def commit_version_files(version_files, next_version):
for version_file in version_files:
exec_git_command(command=['git', 'add', version_file])
exec_git_command(command=['git', 'commit', '-m', 'Updating version to {}'.format(next_version)])


def create_tag(next_version):
exec_git_command(command=['git', 'tag', 'v{}'.format(next_version)])


def main():
version_regex = '\\d+\\.\\d+\\.\\d+.*'

version_files = {
'mix.exs': '\\s*version: "({})",$'.format(version_regex),
}

parser = argparse.ArgumentParser(description=DESCRIPTION)

parser.add_argument(
'-n', '--next',
required=False,
default='patch',
help='select next release version; can be either one of [major|minor|patch] or an explicit version (ex: 1.5.0)'
)

parser.add_argument(
'-v', '--verbose',
action='store_true',
help='enable debug logging'
)

args = parser.parse_args()

logging.basicConfig(
format='[%(asctime)-15s] [%(levelname)s] [%(name)-5s]: %(message)s',
level=logging.getLevelName(logging.DEBUG if args.verbose else logging.INFO)
)

require_no_changes()

current_version = get_current_version(version_files=version_files)
next_version = get_next_version(current_version=current_version, next_version=args.next)

apply_next_version(version_files=version_files, current_version=current_version, next_version=next_version)

updated_version = get_current_version(version_files=version_files)

require_version_updated(next_version=next_version, updated_version=updated_version)

commit_version_files(version_files=version_files, next_version=next_version)
create_tag(next_version=next_version)

next_snapshot_version = '{}-SNAPSHOT'.format(get_next_version(current_version=next_version, next_version='patch'))
apply_next_version(version_files=version_files, current_version=next_version, next_version=next_snapshot_version)

updated_snapshot_version = get_current_version(version_files=version_files)

require_version_updated(next_version=next_snapshot_version, updated_version=updated_snapshot_version)

commit_version_files(version_files=version_files, next_version=next_snapshot_version)


if __name__ == '__main__':
main()

0 comments on commit 74f8be7

Please sign in to comment.