diff --git a/.github/workflows/draft.yml b/.github/workflows/draft.yml new file mode 100644 index 0000000..e4f5ccd --- /dev/null +++ b/.github/workflows/draft.yml @@ -0,0 +1,53 @@ +name: Update draft specification +on: + workflow_dispatch: + push: + branches: draft + +jobs: + build-draft: + name: Make draft spec release + runs-on: ubuntu-latest + steps: + - name: Set up Python + uses: actions/setup-python@3105fb18c05ddd93efea5f9e0bef7a03a6e9e7df + with: + python-version: 3.x + + - name: Find pip cache dir + id: pip-cache + run: echo "::set-output name=dir::$(pip cache dir)" + + - name: pip cache + uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 + with: + # Use the os dependent pip cache directory found above + path: ${{ steps.pip-cache.outputs.dir }} + # A match with 'restore-keys' is used as fallback + key: ${{ runner.os }}-pip- + + - name: Clone + uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f + + - name: Build specification + run: | + python -m pip install bikeshed + mkdir build && cd build + make -f ../Makefile draft + + - name: Switch branch + uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f + with: + ref: gh-pages + clean: false + + - name: Push generated specification + run: | + git config user.name "TUF Specification Automation" + git config user.email theupdateframework@googlegroups.com + rm -fr draft + mv build/* . + rmdir build + git add . + git commit -m "Publish latest draft specification" + git push diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..a6b696c --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,20 @@ +name: CI +on: + pull_request: + branches: + - master + +jobs: + main: + name: Check date and version are updated + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # we want all refs for the --is-ancestor check + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.x + - name: Check date and version + run: python check_release.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..ef69df7 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,83 @@ +name: Release specification +on: + workflow_dispatch: + push: + branches: master + +jobs: + make-release: + name: Make and publish spec release + runs-on: ubuntu-latest + steps: + - name: Set up Python + uses: actions/setup-python@3105fb18c05ddd93efea5f9e0bef7a03a6e9e7df + with: + python-version: 3.x + + - name: Find pip cache dir + id: pip-cache + run: echo "::set-output name=dir::$(pip cache dir)" + + - name: pip cache + uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 + with: + # Use the os dependent pip cache directory found above + path: ${{ steps.pip-cache.outputs.dir }} + # A match with 'key' counts as cache hit + key: ${{ runner.os }}-pip- + + - name: Clone main + uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f + with: + fetch-depth: 0 + + - name: Get previous version + id: prevver + run: | + prev_version=`git tag | sort -V -r | head -n 1 | cut -c 2-` + echo "::set-output name=prev_version::$(echo -n $prev_version)" + + - name: Get version + id: getver + run: | + spec_version=`grep -oP 'VERSION \K(\d+\.\d+\.\d+)' tuf-spec.md` + echo "::set-output name=spec_version::$(echo -n $spec_version)" + + - name: Make release + if: steps.getver.outputs.spec_version != steps.prevver.outputs.prev_version + uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ steps.getver.outputs.spec_version }} + release_name: v${{ steps.getver.outputs.spec_version }} + body: Specification release v${{ steps.getver.outputs.spec_version }} + + - name: Build specification + if: steps.getver.outputs.spec_version != steps.prevver.outputs.prev_version + run: | + python -m pip install bikeshed + mkdir build && cd build + make -f ../Makefile release + + - name: Switch branch + if: steps.getver.outputs.spec_version != steps.prevver.outputs.prev_version + uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f + with: + ref: gh-pages + clean: false + + - name: Push generated specification + if: steps.getver.outputs.spec_version != steps.prevver.outputs.prev_version + env: + SPEC_VERSION: v${{ steps.getver.outputs.spec_version }} + run: | + git config user.name "TUF Specification Automation" + git config user.email theupdateframework@googlegroups.com + rm -fr latest + mv build/* . + rmdir build + make index + git add . + git commit -m "Publish latest specification $SPEC_VERSION" + git push diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1037e43..0000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: python - -# Disable auto-cloning and ... -git: - clone: false - -# ... instead manually fetch and checkout the pull request source branch, which -# is expected by check_release.py -# https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/checking-out-pull-requests-locally -install: - - git clone --depth=50 https://github.com/${TRAVIS_REPO_SLUG}.git ${TRAVIS_REPO_SLUG} - - cd ${TRAVIS_REPO_SLUG} - - git fetch origin pull/${TRAVIS_PULL_REQUEST}/head:${TRAVIS_PULL_REQUEST_BRANCH} - - git checkout -qf ${TRAVIS_PULL_REQUEST_BRANCH} - -script: - - python check_release.py diff --git a/Makefile b/Makefile index 9d56cc7..98dcd2b 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,23 @@ SHELL=/bin/bash -o pipefail -.PHONY: local +SPEC_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +.PHONY: spec -local: tuf-spec.md - bikeshed spec tuf-spec.md tuf-spec.html +spec: $(SPEC_DIR)/tuf-spec.md + bikeshed spec $(SPEC_DIR)/tuf-spec.md tuf-spec.html + +latest: spec + mkdir -p latest + cp tuf-spec.html latest/index.html + +draft: spec + mkdir -p draft + cp tuf-spec.html draft/index.html + +versioned: spec + mkdir -p $(shell python3 $(SPEC_DIR)/get_version.py $(SPEC_DIR)/tuf-spec.md) + cp tuf-spec.html $(shell python3 $(SPEC_DIR)/get_version.py $(SPEC_DIR)/tuf-spec.md)/index.html + +index: + python3 $(SPEC_DIR)/build_index.py + +release: spec latest versioned diff --git a/build_index.py b/build_index.py new file mode 100644 index 0000000..54f136f --- /dev/null +++ b/build_index.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python3 + +""" + + build_index.py + + + Joshua Lock + + + Feb 1, 2021 + + + See LICENSE-MIT for licensing information. + + + Quick and dirty script to generate an index of published specification + versions. + + Style cribbed from the bikeshed W3C theme we are using in our bikeshed + generated specification documents. +""" + +import os +import sys + +from subprocess import run + +html_header = """ + + + + The Update Framework Specification + + + + +
+

The Update Framework Specification

+
+
+
    +""" + +html_footer = """
+ + +""" + +def build_index(): + html = html_header + + html_locations = ['latest', 'draft'] + dir_contents = sorted(os.listdir('.'), reverse=True) + for path in dir_contents: + if path.startswith('v'): + if not os.path.exists(f'{path}/index.html'): + continue + html_locations.append(path) + + for loc in html_locations: + link = f"
  • {loc}
  • \n" + html = html + link + + html = html + html_footer + + return html + +if __name__ == "__main__": + html = build_index() + with open('index.html', 'w') as index: + index.write(html) diff --git a/check_release.py b/check_release.py index e4067f6..e56f7c4 100644 --- a/check_release.py +++ b/check_release.py @@ -15,11 +15,11 @@ Check that specification updates are performed according to the versioning requirements in README.rst. - Expects Travis environment variables: - - TRAVIS_BRANCH - - TRAVIS_PULL_REQUEST_BRANCH - (see https://docs.travis-ci.com/user/environment-variables/) - + Expects GitHub Actions environment variables: + - GITHUB_REF the ref that triggered the workflow (i.e refs/pull/33/merge) + - GITHUB_BASE_REF the target branch (usually master) + - GITHUB_HEAD_REF the name of the submitters branch + (see https://docs.github.com/en/free-pro-team@latest/actions/reference/environment-variables) """ import os import re @@ -40,7 +40,7 @@ class SpecError(Exception): """Common error message part. """ def __init__(self, msg): super().__init__( - msg + " please see 'Versioning' section in README.rst for details.") + msg + ", please see 'Versioning' section in README.rst for details.") def get_spec_head(): @@ -87,26 +87,11 @@ def main(): the last modified date and version number in the specification document header are higher than in the master branch, i.e. were bumped. """ - # Skip version and date comparison on push builds ... - # As per https://docs.travis-ci.com/user/environment-variables/ - # if the current job is a push build, this [env] variable is empty ("") - if not os.environ.get("TRAVIS_PULL_REQUEST_BRANCH"): - print("skipping version and date check for non pr builds ...") - sys.exit(0) - - # ... also skip on PRs that don't target the master branch - # As per https://docs.travis-ci.com/user/environment-variables/: - # for builds triggered by a pull request this [env variable] is the name of - # the branch targeted by the pull request - if not os.environ.get("TRAVIS_BRANCH") == "master": - print("skipping version and date for builds that don't target master ...") - sys.exit(0) - # Check that the current branch is based off of the master branch try: subprocess.run( - shlex.split("git merge-base --is-ancestor master {}".format( - os.environ["TRAVIS_PULL_REQUEST_BRANCH"])), check=True) + shlex.split("git merge-base --is-ancestor origin/master {}".format( + os.environ["GITHUB_REF"].lstrip("refs/"))), check=True) except subprocess.CalledProcessError as e: raise SpecError("make sure the current branch is based off of master") @@ -136,7 +121,7 @@ def main(): # Assert version bump type depending on the PR originating branch # - if the originating branch is 'draft', it must be a major (x)or minor bump # - otherwise, it must be a patch bump - if os.environ["TRAVIS_PULL_REQUEST_BRANCH"] == "draft": + if os.environ["GITHUB_BASE_REF"] == "draft": if not (((version_new[0] > version_prev[0]) != (version_new[1] > version_prev[1])) and (version_new[2] == version_prev[2])): @@ -155,9 +140,8 @@ def main(): print("*"*68) print("thanks for correctly bumping version and last modified date. :)") - print("don't forget to tag the release and to sync 'draft' with master!! :P") print("*"*68) if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/get_version.py b/get_version.py new file mode 100644 index 0000000..c2474f0 --- /dev/null +++ b/get_version.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 + +""" + + get_version.py + + + Joshua Lock + + + Feb 2, 2021 + + + See LICENSE-MIT for licensing information. + + + Quick and dirty script to get the version number from tuf-spec.md + + Unfortunately GNU grep and BSD grep take different options... +""" + +import re +import sys + +pattern = re.compile("VERSION (\d+\.\d+\.\d+)") + +def get_version(): + out = '' + spec = 'tuf-spec.md' + + if (len(sys.argv) > 1): + spec = sys.argv[1] + + with open(spec, 'r') as spec: + for line in spec: + for match in re.finditer(pattern, line): + if match.group(): + break + out = match.groups()[0] + + return f'v{out}' + +if __name__ == "__main__": + print(get_version())