From de024c5f96e9f3f74bb932c569d0a1133ac81864 Mon Sep 17 00:00:00 2001 From: Nicolas Harraudeau <40498978+nicolas-harraudeau-sonarsource@users.noreply.github.com> Date: Tue, 16 Feb 2021 21:21:46 +0100 Subject: [PATCH] Add RuleCreator to rspec-tools --- .github/workflows/create_new_rspec.yml | 50 ++------ rspec-tools/Pipfile | 2 + rspec-tools/Pipfile.lock | 94 ++++++++++++++- .../rspec_template/common/metadata.json | 0 .../language_specific/metadata.json | 0 .../language_specific/rule.adoc | 0 rspec-tools/rspec_tools/cli.py | 35 +++++- rspec-tools/rspec_tools/create_rule.py | 108 ++++++++++++++++++ rspec-tools/rspec_tools/errors.py | 5 + rspec-tools/rspec_tools/utils.py | 9 ++ rspec-tools/tests/test_create_rule.py | 107 +++++++++++++++++ scripts/create_new_rspec_branch.sh | 28 ----- scripts/reserve_rspec_id.sh | 21 ---- 13 files changed, 364 insertions(+), 95 deletions(-) rename {scripts => rspec-tools}/rspec_template/common/metadata.json (100%) rename {scripts => rspec-tools}/rspec_template/language_specific/metadata.json (100%) rename {scripts => rspec-tools}/rspec_template/language_specific/rule.adoc (100%) create mode 100644 rspec-tools/rspec_tools/create_rule.py create mode 100644 rspec-tools/rspec_tools/utils.py create mode 100644 rspec-tools/tests/test_create_rule.py delete mode 100755 scripts/create_new_rspec_branch.sh delete mode 100755 scripts/reserve_rspec_id.sh diff --git a/.github/workflows/create_new_rspec.yml b/.github/workflows/create_new_rspec.yml index eaf6065c11..a1c8fededb 100644 --- a/.github/workflows/create_new_rspec.yml +++ b/.github/workflows/create_new_rspec.yml @@ -14,52 +14,18 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - with: - #repository: 'nicolas-harraudeau-sonarsource/test-github-actions' - #token: ${{ secrets.NHARRAUD_PUBLIC_REPOS }} - persist-credentials: true - ref: rspec-id-counter - path: 'rspec-id-counter' - uses: actions/checkout@v2 with: persist-credentials: true ref: master - path: 'master' - - name: 'Configure Git' - working-directory: 'rspec-id-counter' + path: 'rspec' + + - name: 'Install Pipenv' run: | - git config user.name "${{ github.actor }}" - git config user.email "<${{ github.actor }}@users.noreply.github.com>" + pip install pipenv - - name: 'Increment the RSPEC ID counter' - id: increment-rspec-id - working-directory: 'rspec-id-counter' - run: ../master/scripts/reserve_rspec_id.sh next_rspec_id.txt - - - name: 'Test RSPEC ID' - run: echo $RSPEC_ID - - name: 'print actor' - run: echo $GITHUB_ACTOR - - - name: 'Create new rule in a branch' - working-directory: 'master' - run: ./scripts/create_new_rspec_branch.sh $RSPEC_ID "${{ github.event.inputs.languages }}" rules - - - name: Create Pull Request - id: cpr - uses: peter-evans/create-pull-request@v3 - with: - path: 'master' - commit-message: Create rule ${{ steps.increment-rspec-id.outputs.rspec-id }} - title: Create rule ${{ steps.increment-rspec-id.outputs.rspec-id }} - committer: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> - author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> - assignees: "${{ github.actor }}" - branch: add-RSPEC-${{ steps.increment-rspec-id.outputs.rspec-id }} - draft: true - - - name: Check outputs + - name: 'Create Rule' + working-directory: 'rspec/rspec-tools' run: | - echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" - echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" \ No newline at end of file + pipenv install -e . + pipenv run create_rule --languages "${{ github.event.inputs.languages }}" diff --git a/rspec-tools/Pipfile b/rspec-tools/Pipfile index 950f628af2..1b6b996855 100644 --- a/rspec-tools/Pipfile +++ b/rspec-tools/Pipfile @@ -7,6 +7,8 @@ name = "pypi" click = ">=7.1.2" bs4 = "*" rspec-tools = {editable = true, path = "."} +gitpython = "*" +pygithub = "*" [dev-packages] pytest = ">=6.2.2" diff --git a/rspec-tools/Pipfile.lock b/rspec-tools/Pipfile.lock index ec777d472b..975598aec7 100644 --- a/rspec-tools/Pipfile.lock +++ b/rspec-tools/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c21b312520580b430e4d8e52d6619f9e729c8de14b73cc3a072bd146d341c622" + "sha256": "74591c9934ebe1adbe00466ef69a05fd1d91a857d6a8354c3da8f17b65108eff" }, "pipfile-spec": 6, "requires": { @@ -31,6 +31,21 @@ "index": "pypi", "version": "==0.0.1" }, + "certifi": { + "hashes": [ + "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", + "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" + ], + "version": "==2020.12.5" + }, + "chardet": { + "hashes": [ + "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", + "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==4.0.0" + }, "click": { "hashes": [ "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", @@ -39,10 +54,73 @@ "index": "pypi", "version": "==7.1.2" }, + "deprecated": { + "hashes": [ + "sha256:471ec32b2755172046e28102cd46c481f21c6036a0ec027521eba8521aa4ef35", + "sha256:924b6921f822b64ec54f49be6700a126bab0640cfafca78f22c9d429ed590560" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.2.11" + }, + "gitdb": { + "hashes": [ + "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac", + "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9" + ], + "markers": "python_version >= '3.4'", + "version": "==4.0.5" + }, + "gitpython": { + "hashes": [ + "sha256:8621a7e777e276a5ec838b59280ba5272dd144a18169c36c903d8b38b99f750a", + "sha256:c5347c81d232d9b8e7f47b68a83e5dc92e7952127133c5f2df9133f2c75a1b29" + ], + "index": "pypi", + "version": "==3.1.13" + }, + "idna": { + "hashes": [ + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" + }, + "pygithub": { + "hashes": [ + "sha256:300bc16e62886ca6537b0830e8f516ea4bc3ef12d308e0c5aff8bdbd099173d4", + "sha256:87afd6a67ea582aa7533afdbf41635725f13d12581faed7e3e04b1579c0c0627" + ], + "index": "pypi", + "version": "==1.54.1" + }, + "pyjwt": { + "hashes": [ + "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", + "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96" + ], + "version": "==1.7.1" + }, + "requests": { + "hashes": [ + "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", + "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.25.1" + }, "rspec-tools": { "editable": true, "path": "." }, + "smmap": { + "hashes": [ + "sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714", + "sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==3.0.5" + }, "soupsieve": { "hashes": [ "sha256:407fa1e8eb3458d1b5614df51d9651a1180ea5fedf07feb46e45d7e25e6d6cdd", @@ -50,6 +128,20 @@ ], "markers": "python_version >= '3.0'", "version": "==2.2" + }, + "urllib3": { + "hashes": [ + "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", + "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.26.3" + }, + "wrapt": { + "hashes": [ + "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7" + ], + "version": "==1.12.1" } }, "develop": { diff --git a/scripts/rspec_template/common/metadata.json b/rspec-tools/rspec_template/common/metadata.json similarity index 100% rename from scripts/rspec_template/common/metadata.json rename to rspec-tools/rspec_template/common/metadata.json diff --git a/scripts/rspec_template/language_specific/metadata.json b/rspec-tools/rspec_template/language_specific/metadata.json similarity index 100% rename from scripts/rspec_template/language_specific/metadata.json rename to rspec-tools/rspec_template/language_specific/metadata.json diff --git a/scripts/rspec_template/language_specific/rule.adoc b/rspec-tools/rspec_template/language_specific/rule.adoc similarity index 100% rename from scripts/rspec_template/language_specific/rule.adoc rename to rspec-tools/rspec_template/language_specific/rule.adoc diff --git a/rspec-tools/rspec_tools/cli.py b/rspec-tools/rspec_tools/cli.py index b19f56a7b4..d66424b754 100644 --- a/rspec-tools/rspec_tools/cli.py +++ b/rspec-tools/rspec_tools/cli.py @@ -1,6 +1,11 @@ +import os +import tempfile +from typing import Optional + import click -from .checklinks import check_html_links -from .errors import RuleNotFoundError +from rspec_tools.checklinks import check_html_links +from rspec_tools.errors import InvalidArgumenError, RuleNotFoundError +from rspec_tools.create_rule import RuleCreator, build_github_repository_url @click.group() @click.option('--debug/--no-debug', default=False) @@ -20,6 +25,30 @@ def validate(rule): def check_links(d): '''Check links in html.''' check_html_links(d) - + +@cli.command() +@click.option('--languages', required=True) +@click.option('--user', required=False) +def create_rule(languages: str, user: Optional[str]): + '''Create a new rule.''' + token = os.environ.get('GITHUB_TOKEN') + url = build_github_repository_url(token) + config = {} + if user: + config['user.name'] = user + config['user.email'] = f'<{user}@users.noreply.github.com>' + lang_list = [lang.strip() for lang in languages.split(',')] + if len(languages.strip()) == 0 or len(lang_list) == 0: + raise InvalidArgumenError('Invalid argument for "languages". At least one language should be provided.') + # TODO: accept only valid languages + + with tempfile.TemporaryDirectory() as tmpdirname: + rule_creator = RuleCreator(url, tmpdirname, config) + rule_number = rule_creator.reserve_rule_number() + click.echo(f'Reserved Rule ID S{rule_number}') + pull_request = rule_creator.create_new_rule_pull_request(token, rule_number, lang_list) + click.echo(f'Created Rule Pull Request branch: {pull_request.head} url: {pull_request.html_url}') + + __all__=['cli'] diff --git a/rspec-tools/rspec_tools/create_rule.py b/rspec-tools/rspec_tools/create_rule.py new file mode 100644 index 0000000000..9b2f59231a --- /dev/null +++ b/rspec-tools/rspec_tools/create_rule.py @@ -0,0 +1,108 @@ +from git import Repo +from github import Github +from github.PullRequest import PullRequest +from pathlib import Path +from typing import Final, Iterable, Optional +from contextlib import contextmanager + +from rspec_tools.utils import copy_directory_content + +def build_github_repository_url(token): + 'Builds the rspec repository url' + return f'https://{token}@github.com/SonarSource/rspec.git' + +def extract_repository_name(url): + url_end = url.split('/')[-2:] + return '/'.join(url_end).removesuffix('.git') + +class RuleCreator: + ''' Create a new Rule in a repository following the official Github 'rspec' repository structure.''' + MASTER_BRANCH: Final[str] = 'master' + ID_COUNTER_BRANCH: Final[str] = 'rspec-id-counter' + ID_COUNTER_FILENAME: Final[str] = 'next_rspec_id.txt' + TEMPLATE_PATH: Final[Path] = Path(__file__).parent.parent.joinpath('rspec_template') + + repository: Final[Repo] + origin_url: Final[str] + + def __init__(self, repository_url: str, clone_directory: str, configuration: dict[str, str]): + self.repository = Repo.clone_from(repository_url, clone_directory) + self.origin_url = repository_url + + # create local branches tracking remote ones + for branch in [self.MASTER_BRANCH, self.ID_COUNTER_BRANCH]: + self.repository.remote().fetch(branch) + self.repository.git.checkout('-B', branch, f'origin/{branch}') + + # update repository config + with self.repository.config_writer() as config_writer: + for key, value in configuration.items(): + split_key = key.split('.') + config_writer.set_value(*split_key, value) + + + def reserve_rule_number(self) -> int: + '''Reserve an id on the id counter branch of the repository.''' + with self._current_git_branch(self.ID_COUNTER_BRANCH): + counter_file_path = Path(self.repository.working_dir).joinpath(self.ID_COUNTER_FILENAME) + counter = int(counter_file_path.read_text()) + counter_file_path.write_text(str(counter + 1)) + + self.repository.index.add([str(counter_file_path)]) + self.repository.index.commit('Increment RSPEC ID counter') + + origin = self.repository.remote(name='origin') + origin.push() + return counter + + def create_new_rule_branch(self, rule_number: int, languages: Iterable[str]) -> str: + '''Create all the files required for a new rule.''' + branch_name = f'add-RSPEC-S{rule_number}' + with self._current_git_branch(self.MASTER_BRANCH, branch_name): + repo_dir = Path(self.repository.working_dir) + rule_dir = repo_dir.joinpath('rules', f'S{rule_number}') + rule_dir.mkdir() + common_template = self.TEMPLATE_PATH.joinpath('common') + lang_specific_template = self.TEMPLATE_PATH.joinpath('language_specific') + copy_directory_content(common_template, rule_dir) + + for lang in languages: + lang_dir = rule_dir.joinpath(lang) + lang_dir.mkdir() + copy_directory_content(lang_specific_template, lang_dir) + + for rule_item in rule_dir.glob('**/*'): + if rule_item.is_file(): + template_content = rule_item.read_text() + final_content = template_content.replace('${RSPEC_ID}', str(rule_number)) + rule_item.write_text(final_content) + self.repository.git.add('--all') + self.repository.index.commit(f'Create rule S{rule_number}') + + origin = self.repository.remote(name='origin') + origin.push(f'refs/heads/{branch_name}:refs/heads/{branch_name}') + return branch_name + + def create_new_rule_pull_request(self, token: str, rule_number: int, languages: Iterable[str]) -> PullRequest: + branch_name = self.create_new_rule_branch(rule_number, languages) + repository_url = extract_repository_name(self.origin_url) + github = Github(token) + github_repo = github.get_repo(repository_url) + return github_repo.create_pull( + title=f'Create rule S{rule_number}', body='', head=branch_name, base=self.MASTER_BRANCH, + draft=True, maintainer_can_modify=True + ) + + @contextmanager + def _current_git_branch(self, base_branch: str, new_branch: Optional[str] = None): + '''Checkout a given branch before yielding, then revert to the previous branch.''' + past_branch = self.repository.active_branch + try: + self.repository.git.checkout(base_branch) + origin = self.repository.remote(name='origin') + origin.pull() + if new_branch is not None: + self.repository.git.checkout('-B', new_branch) + yield + finally: + self.repository.git.checkout(past_branch) \ No newline at end of file diff --git a/rspec-tools/rspec_tools/errors.py b/rspec-tools/rspec_tools/errors.py index 096803afdd..737c842a77 100644 --- a/rspec-tools/rspec_tools/errors.py +++ b/rspec-tools/rspec_tools/errors.py @@ -3,3 +3,8 @@ from click import ClickException class RuleNotFoundError(ClickException): def __init__(self, id): super().__init__(f'No rule has ID {id}') + +class InvalidArgumenError(ClickException): + '''Exception raised when an invalid argument is given to a CLI command.''' + def __init__(self, message): + super().__init__(message) \ No newline at end of file diff --git a/rspec-tools/rspec_tools/utils.py b/rspec-tools/rspec_tools/utils.py new file mode 100644 index 0000000000..6e48d908e5 --- /dev/null +++ b/rspec-tools/rspec_tools/utils.py @@ -0,0 +1,9 @@ +from pathlib import Path +import shutil + +def copy_directory_content(src:Path, dest:Path): + for item in src.iterdir(): + if (item.is_dir()): + shutil.copytree(item, dest) + else: + shutil.copy2(item, dest) diff --git a/rspec-tools/tests/test_create_rule.py b/rspec-tools/tests/test_create_rule.py new file mode 100644 index 0000000000..ff5fb9ec83 --- /dev/null +++ b/rspec-tools/tests/test_create_rule.py @@ -0,0 +1,107 @@ +from git import Repo, Head +from pathlib import Path +import pytest + +from rspec_tools.create_rule import RuleCreator + +@pytest.fixture +def git_config(): + '''Create a mock git configuration.''' + return { + 'user.name': 'testuser', + 'user.email': 'testuser@mock.mock' + } + +@pytest.fixture +def mock_rspec_repo(tmpdir): + repo_dir = tmpdir.mkdir("mock_rspec") + repo = Repo.init(str(repo_dir)) + repo.init() + + with repo.config_writer() as config_writer: + config_writer.set_value('user', 'name', 'originuser') + config_writer.set_value('user', 'email', 'originuser@mock.mock') + + rules_dir = repo_dir.mkdir('rules') + # create a file just to have a "rules" directory + gitignore = rules_dir.join('.gitignore') + gitignore.ensure() + repo.index.add([str(gitignore)]) + repo.index.commit('init rules') + + # Create the id counter branch. Note that it is an orphan branch. + repo.head.reference = Head(repo, f'refs/heads/{RuleCreator.ID_COUNTER_BRANCH}') + repo.git.reset('--hard') + counter_file = repo_dir.join(RuleCreator.ID_COUNTER_FILENAME) + counter_file.write('0') + repo.index.add([str(counter_file)]) + commit = repo.index.commit('init counter', parent_commits=None) + + # Checkout a specific commit so that the repo can be pushed to without + # making the index and work tree inconsistent. + repo.git.checkout(commit.hexsha) + + return repo + +@pytest.fixture +def rule_creator(tmpdir, mock_rspec_repo: Repo, git_config: dict[str, str]): + cloned_repo = tmpdir.mkdir("cloned_repo") + return RuleCreator(mock_rspec_repo.working_dir, str(cloned_repo), git_config) + + +def test_reserve_rule_number_simple(rule_creator: RuleCreator, mock_rspec_repo: Repo): + '''Test that RuleCreator.reserve_rule_id() increments the id and returns the old value.''' + assert rule_creator.reserve_rule_number() == 0 + + assert read_counter_file(mock_rspec_repo) == '1' + + +def test_reserve_rule_number_parallel_reservations(tmpdir, mock_rspec_repo: Repo, git_config): + '''Test that RuleCreator.reserve_rule_id() works when multiple reservations are done in parallel.''' + cloned_repo1 = tmpdir.mkdir("cloned_repo1") + rule_creator1 = RuleCreator(mock_rspec_repo.working_dir, str(cloned_repo1), git_config) + cloned_repo2 = tmpdir.mkdir("cloned_repo2") + rule_creator2 = RuleCreator(mock_rspec_repo.working_dir, str(cloned_repo2), git_config) + + assert rule_creator1.reserve_rule_number() == 0 + assert rule_creator2.reserve_rule_number() == 1 + assert rule_creator1.reserve_rule_number() == 2 + + assert read_counter_file(mock_rspec_repo) == '3' + + +def read_counter_file(repo): + '''Reads the counter file from the provided repository and returns its content.''' + repo.git.checkout(RuleCreator.ID_COUNTER_BRANCH) + counter_path = Path(repo.working_dir).joinpath(RuleCreator.ID_COUNTER_FILENAME) + return counter_path.read_text() + + +def test_create_new_rule_branch(rule_creator: RuleCreator, mock_rspec_repo: Repo): + '''Test create_new_rule_branch.''' + rule_number = rule_creator.reserve_rule_number() + + languages = ['java', 'javascript'] + branch = rule_creator.create_new_rule_branch(rule_number, languages) + + # Check that the branch was pushed successfully to the origin + mock_rspec_repo.git.checkout(branch) + rule_dir = Path(mock_rspec_repo.working_dir).joinpath('rules', f'S{rule_number}') + assert rule_dir.exists() + + common_root = rule_creator.TEMPLATE_PATH.joinpath('common') + for common_item in common_root.glob('**/*'): + if common_item.is_file(): + expected_content = common_item.read_text().replace('${RSPEC_ID}', str(rule_number)) + relative_path = common_item.relative_to(common_root) + actual_content = rule_dir.joinpath(relative_path).read_text() + assert actual_content == expected_content + + lang_root = rule_creator.TEMPLATE_PATH.joinpath('language_specific') + for lang in languages: + for lang_item in lang_root.glob('**/*'): + if lang_item.is_file(): + expected_content = lang_item.read_text().replace('${RSPEC_ID}', str(rule_number)) + relative_path = lang_item.relative_to(lang_root) + actual_content = rule_dir.joinpath(lang, relative_path).read_text() + assert actual_content == expected_content diff --git a/scripts/create_new_rspec_branch.sh b/scripts/create_new_rspec_branch.sh deleted file mode 100755 index 609d988a93..0000000000 --- a/scripts/create_new_rspec_branch.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -# Create the new Rule in a branch -# It is used by the Github Action script "create_new_rspec.yml". - -# Stop script in case of error. -set -e - -RSPEC_ID=$1 -LANGUAGES=$2 -RULES_DIRECTORY=$3 - -scripts_dir=$(dirname "$0") -template_dir="${scripts_dir}/rspec_template" -rule_directory="${RULES_DIRECTORY}/S${RSPEC_ID}" - -mkdir $rule_directory -cp $template_dir/common/* $rule_directory/ - -for language in $(echo $LANGUAGES | sed "s/,/ /g") -do - mkdir $rule_directory/$language - cp $template_dir/language_specific/* $rule_directory/$language/ -done - -cd $rule_directory - -grep -rl '${RSPEC_ID}' . | xargs sed -i "s/\${RSPEC_ID}/${RSPEC_ID}/g" \ No newline at end of file diff --git a/scripts/reserve_rspec_id.sh b/scripts/reserve_rspec_id.sh deleted file mode 100755 index 1afb04fafb..0000000000 --- a/scripts/reserve_rspec_id.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -# Script reserving a RSPEC identifier. -# It is used by the Github Action script "create_new_rspec.yml". - -# Stop script in case of error. -set -e - -RSPEC_ID_COUNTER_FILE=$1 - -# Increment the next_id counter. -next_id=`cat ${RSPEC_ID_COUNTER_FILE}` -new_next_id=`expr $next_id + 1` -echo $new_next_id > ${RSPEC_ID_COUNTER_FILE} -git add ${RSPEC_ID_COUNTER_FILE} -git commit -m "Increment RSPEC ID counter" -git push origin rspec-id-counter - -# Set the Environment variable for the next Github Action. -echo "::set-env name=RSPEC_ID::${next_id}" -echo "::set-output name=rspec-id::${next_id}" \ No newline at end of file