diff --git a/.github/workflows/pullRequest.yml b/.github/workflows/pullRequest.yml new file mode 100644 index 0000000..0cb29ed --- /dev/null +++ b/.github/workflows/pullRequest.yml @@ -0,0 +1,10 @@ +name: check for pull request into master + +on: + pull_request: + branches: + - master + +jobs: + build: + uses: ./.github/workflows/testAndBuild.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1b819d8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,50 @@ +name: Build and release for official + +on: + push: + tags: + - "*.*.*" + +jobs: + build: + uses: ./.github/workflows/testAndBuild.yml + with: + official_release: true + + deploy: + needs: build + runs-on: windows-latest + + steps: + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: ${{ github.event.repository.name }} + path: ./ + + - name: Deploy to GitHub + uses: softprops/action-gh-release@v1 + with: + body: ${{ github.event.repository.name }} official release + draft: true + files: | + ./${{ github.event.repository.name }}-*.zip + ./*-*.nvda-addon + ./${{ github.event.repository.name }}-*.json + + error_notify: + runs-on: ubuntu-latest + needs: deploy + if: ${{ failure() }} + steps: + - name: Send GitHub Action trigger data to Slack workflow + uses: slackapi/slack-github-action@v1 + with: + payload: | + { + "text": "Github actions build failed! <${{ github.server_url }}/${{ github.repository }}|${{ github.event.repository.name }}>のofficial releaseビルドが失敗しました。\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|対象のrun>お確認し、対応着手時・完了後は、本チャンネルにて経緯を報告ください。" + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_ALERT_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml new file mode 100644 index 0000000..0f293d7 --- /dev/null +++ b/.github/workflows/snapshot.yml @@ -0,0 +1,84 @@ +name: Build and release for snapshot + +on: + push: + branches: + - master + +jobs: + build: + uses: ./.github/workflows/testAndBuild.yml + + deploy: + needs: build + runs-on: windows-latest + + steps: + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: ${{ github.event.repository.name }} + path: ./ + + - name: Re-create the tag + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo + const tagName = repo + "-latestcommit" + try { + // Fetch the release by its tag + const { data: release } = await github.rest.repos.getReleaseByTag({ owner, repo, tag: tagName }) + // Delete the release if exists + await github.rest.repos.deleteRelease({ owner, repo, release_id: release.id }) + console.log("deleted release"); + } catch(err) { + if(err.status !== 404){ + throw err; + } + console.log('No release found for deletion'); + } + try { + await github.rest.git.deleteRef({owner, repo, ref: "tags/" + tagName}) + console.log("deleted tag"); + } catch(err) { + console.log('Failed to delete tag'+err.message); + } + try { + await github.rest.git.createRef({owner, repo, ref: "refs/tags/" + tagName, sha: context.sha}) + console.log("created tag"); + } catch(err) { + console.log('Failed to create tag'+err.message); + } + + - name: Deploy to GitHub + uses: softprops/action-gh-release@v1 + with: + name: Snapshot + tag_name: ${{ github.event.repository.name }}-latestcommit + body: Automatic build from master branch + files: | + ./${{ github.event.repository.name }}-*.zip + ./*-*.nvda-addon + ./${{ github.event.repository.name }}-*.json + + - name: register snapshot to actlab site + run: | + curl "https://actlab.org/api/addAlphaVersion?repo_name=${{ github.repository }}&commit_hash=${{ github.sha }}&version=${{ needs.build.outputs.build_version }}&password=${{ secrets.SCRIPT_PASSWORD }}" + + error_notify: + runs-on: ubuntu-latest + needs: deploy + if: ${{ failure() }} + steps: + - name: Send GitHub Action trigger data to Slack workflow + uses: slackapi/slack-github-action@v1 + with: + payload: | + { + "text": "Github actions build failed! <${{ github.server_url }}/${{ github.repository }}|${{ github.event.repository.name }}>のビルドが失敗しました。\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|対象のrun>お確認し、対応着手時・完了後は、本チャンネルにて経緯を報告ください。" + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_ALERT_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + diff --git a/.github/workflows/testAndBuild.yml b/.github/workflows/testAndBuild.yml new file mode 100644 index 0000000..c04948f --- /dev/null +++ b/.github/workflows/testAndBuild.yml @@ -0,0 +1,68 @@ +name: Test and build + +on: + workflow_call: + inputs: + official_release: + description: Whether this is an official release + default: false + type: boolean + outputs: + build_version: + description: Version of the built package + value: ${{ jobs.build.outputs.build_version }} + +jobs: + build: + runs-on: windows-latest + outputs: + build_version: ${{ steps.output_version.outputs.version }} + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + architecture: x86 + python-version: 3.8 + cache: pip + + - name: Install requirements + run: | + python -m pip install -r requirements.txt + + - name: Test + run: | + echo skiped tests + + - name: Set tag name if This is an official release + run: echo "TAG_NAME=$($env:GITHUB_REF.Replace('refs/tags/', ''))" >> $env:GITHUB_ENV + if: ${{ inputs.official_release }} + + - name: Build + run: | + python tools\build.py + env: + COMMIT_TIMESTAMP: ${{ github.event.head_commit.timestamp}} + + - name: output version + id: output_version + shell: python + run: | + import os, sys + sys.path.append(os.getcwd()) + import buildVars + with open(os.environ["GITHUB_OUTPUT"], mode = "a") as f: + f.write("version="+buildVars.ADDON_VERSION) + + - name: Archive production artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ github.event.repository.name }} + path: | + ./${{ github.event.repository.name }}-*.zip + ./*-*.nvda-addon + ./${{ github.event.repository.name }}-*.json + diff --git a/appveyor-release.yml b/appveyor-release.yml deleted file mode 100644 index 4e372ad..0000000 --- a/appveyor-release.yml +++ /dev/null @@ -1,55 +0,0 @@ -version: development.{build}-{branch} -branches: - only: - - release - -skip_branch_with_pr: true - -environment: - matrix: - # For Python versions available on Appveyor, see - # http://www.appveyor.com/docs/installed-software#python - # The list here is complete (excluding Python 2.6, which - # isn't covered by this document) at the time of writing. - - - PYTHON: "C:\\Python37" - -install: - # We need wheel installed to build wheels - - cmd: set path=C:\\Python37;C:\\Python37\\Scripts;C:\\Python37\\lib;%path% - - cmd: python -m pip install -r requirements.txt - -build: off - -test_script: - # Put your test command here. - # If you don't need to build C extensions on 64-bit Python 3.3 or 3.4, - # you can remove "build.cmd" from the front of the command, as it's - # only needed to support those cases. - # Note that you must use the environment variable %PYTHON% to refer to - # the interpreter you're using - Appveyor does not do anything special - # to put the Python evrsion you want to use on PATH. - - "echo Skipped Tests" - -after_test: - # This step builds your wheels. - # Again, you only need build.cmd if you're building C extensions for - # 64-bit Python 3.3/3.4. And you need to use %PYTHON% to get the correct - # interpreter - - cmd: python tools\\build.py --appveyor - -artifacts: - - path: DFN-*.zip - - path: dokutor_for_nvda-*.nvda-addon - - path: DFN-*.json - -deploy: - - provider: GitHub - description: "DFN official release" - auth_token: - secure: iNSx8v6c+0TP9IyckinrvNWuX+hc7SKruOqRDl9GxdX59sZ2yqB8+UDAtqdPzKIg - artifact: /(DFN-.*\.zip)|(dokutor_for_nvda-.*\.nvda-addon)|(DFN-.*\.json)/ - draft: true - prerelease: false - on: - APPVEYOR_REPO_TAG: true diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 82177d3..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,73 +0,0 @@ -version: development.{build}-{branch} -branches: - only: - - master - -skip_branch_with_pr: true -skip_tags: true - -environment: - githubToken: - secure: iNSx8v6c+0TP9IyckinrvNWuX+hc7SKruOqRDl9GxdX59sZ2yqB8+UDAtqdPzKIg - SCRIPT_PASSWORD: - secure: 9RvVUKVQ8MsoG5LOZ86VyFQF19JXXS33tDzomLH/jZM= - matrix: - - # For Python versions available on Appveyor, see - # http://www.appveyor.com/docs/installed-software#python - # The list here is complete (excluding Python 2.6, which - # isn't covered by this document) at the time of writing. - - - PYTHON: "C:\\Python37" - -install: - # We need wheel installed to build wheels - - cmd: set path=C:\\Python37;C:\\Python37\\Scripts;C:\\Python37\\lib;%path% - - cmd: python -m pip install -r requirements.txt - -build: off - -test_script: - # Put your test command here. - # If you don't need to build C extensions on 64-bit Python 3.3 or 3.4, - # you can remove "build.cmd" from the front of the command, as it's - # only needed to support those cases. - # Note that you must use the environment variable %PYTHON% to refer to - # the interpreter you're using - Appveyor does not do anything special - # to put the Python evrsion you want to use on PATH. - - "echo Skipped Tests" - -after_test: - # This step builds your wheels. - # Again, you only need build.cmd if you're building C extensions for - # 64-bit Python 3.3/3.4. And you need to use %PYTHON% to get the correct - # interpreter - - cmd: python tools\\build.py --appveyor - - cmd: if defined APPVEYOR_PULL_REQUEST_NUMBER appveyor exit 0 - - cmd: curl "https://actlab.org/git-release.php?repo_name=%APPVEYOR_REPO_NAME%&tag_name=DFN-latestcommit&password=%SCRIPT_PASSWORD%" - - cmd: git tag -d DFN-latestcommit - - cmd: git push -d https://actlab-auto:%githubToken%@github.com/actlaboratory/DFN.git DFN-latestcommit - - cmd: git tag DFN-latestcommit - - cmd: git push https://actlab-auto:%githubToken%@github.com/actlaboratory/DFN.git DFN-latestcommit - -artifacts: - - path: DFN-*.zip - - path: dokutor_for_nvda-*.nvda-addon - - path: DFN-*.json - -deploy: - - provider: GitHub - release: DFN-latestcommit - skip_tags: true - Force update: true - description: 'automatic build from master branch' - auth_token: - secure: iNSx8v6c+0TP9IyckinrvNWuX+hc7SKruOqRDl9GxdX59sZ2yqB8+UDAtqdPzKIg - artifact: /(DFN-.*\.zip)|(dokutor_for_nvda-.*\.nvda-addon)|(DFN-.*\.json)/ # upload all NuGet packages to release assets - draft: false - prerelease: false - on: - branch: master # release from master branch only - -after_deploy: - - cmd: echo import buildVars;print("https://actlab.org/api/addAlphaVersion?repo_name=%APPVEYOR_REPO_NAME%&commit_hash=%APPVEYOR_REPO_COMMIT%&version="+buildVars.ADDON_VERSION+"&password=%SCRIPT_PASSWORD%",end="") | C:\\Python37\python.exe | xargs -n1 curl diff --git a/tools/build.py b/tools/build.py index 0a76698..6e19ce8 100644 --- a/tools/build.py +++ b/tools/build.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- #app build tool #Copyright (C) 2019 Yukio Nozawa -#Copyright (C) 2019-2020 guredora +#Copyright (C) 2019-2024 guredora #Copyright (C) 2021 yamahubuki #Copyright (C) 2021 Hiroki Fujii @@ -25,20 +25,17 @@ class build: def __init__(self): - # appVeyorかどうかを判別し、処理をスタート - appveyor = self.setAppVeyor() - print("Starting build for %s (appveyor mode=%s)" % (buildVars.ADDON_KEYWORD, appveyor,)) + # Github actionsなどの自動実行かどうかを判別し、処理をスタート + automated = self.setAutomated() + print("Starting build for %s(automated mode=%s)" % (buildVars.ADDON_KEYWORD, automated,)) # パッケージのパスとファイル名を決定 package_path = "output\\" - if 'APPVEYOR_REPO_TAG_NAME' in os.environ: - build_filename = os.environ['APPVEYOR_REPO_TAG_NAME'] - # タグ名とバージョンが違ったらエラー - if build_filename != buildVars.ADDON_VERSION: - print("Unexpected tag name. expecting %s." %(buildVars.ADDON_VERSION,)) - exit(-1) - else: - build_filename = 'snapshot' + build_filename = os.environ.get('TAG_NAME', 'snapshot') + # snapshotではなかった場合は、タグ名とバージョンが違ったらエラー + if (build_filename != "snapshot") and (build_filename != buildVars.ADDON_VERSION): + print("Unexpected tag name. expecting %s." %(buildVars.ADDON_VERSION,)) + exit(-1) print("Will be built as %s" % build_filename) # addonフォルダの存在を確認 @@ -47,23 +44,18 @@ def __init__(self): exit(-1) # 前のビルドをクリーンアップ - self.creen(package_path) + self.clean(package_path) - # appveyorでのスナップショットの場合はバージョン番号を一時的に書き換え - # バージョン番号をセット - if build_filename == "snapshot" and appveyor: - self.version_number = self.makeSnapshotVersionNumber() - elif build_filename == "snapshot": - self.version_number = buildVars.ADDON_VERSION - else: - self.version_number = build_filename + # 自動実行でのスナップショットの場合はバージョン番号を一時的に書き換え + if build_filename == "snapshot" and automated: + print(self.makeSnapshotVersionNumber()) # ビルド self.build(package_path, build_filename) archive_name = "%s-%s.zip" % (buildVars.ADDON_KEYWORD, build_filename,) - addon_filename = "%s-%s.nvda-addon" % (buildVars.ADDON_NAME, self.version_number) + addon_filename = "%s-%s.nvda-addon" % (buildVars.ADDON_NAME, buildVars.ADDON_VERSION,) shutil.copyfile(package_path + addon_filename, addon_filename) - self.makePackageInfo(archive_name, addon_filename, self.version_number, build_filename) + self.makePackageInfo(archive_name, addon_filename, build_filename) print("Build finished!") def runcmd(self,cmd): @@ -71,12 +63,10 @@ def runcmd(self,cmd): proc.communicate() return proc.poll() - def setAppVeyor(self): - if len(sys.argv)>=2 and sys.argv[1]=="--appveyor": - return True - return False + def setAutomated(self): + return os.environ.get("GITHUB_ACTIONS", "false") == "true" - def creen(self,package_path): + def clean(self,package_path): if os.path.isdir(package_path): print("Clearling previous build...") shutil.rmtree("output\\") @@ -84,15 +74,15 @@ def creen(self,package_path): def makeSnapshotVersionNumber(self): #日本標準時オブジェクト JST = datetime.timezone(datetime.timedelta(hours=+9)) - #Pythonは世界標準時のZに対応していないので文字列処理で乗り切り、それを日本標準時に変換 - dt = datetime.datetime.fromisoformat(os.environ["APPVEYOR_REPO_COMMIT_TIMESTAMP"][0:19]+"+00:00").astimezone(JST) - major = str(dt.year)[2:4]+str(dt.month).zfill(2) + dt = datetime.datetime.fromisoformat(os.environ["COMMIT_TIMESTAMP"]).astimezone(JST) + major = f"{dt.year % 100:02d}{dt.month:02d}" minor = str(dt.day) patch = str(int(math.floor((dt.hour*3600+dt.minute*60+dt.second)/86400*1000))) + buildVars.ADDON_VERSION = major+"."+minor+"."+patch + buildVars.ADDON_RELEASE_DATE = str(dt.date()) bumpup.bumpup(major+"."+minor+"."+patch, str(dt.date())) return major+"."+minor+"."+patch - def build(self, package_path, build_filename): print("Building...") shutil.copytree("public", package_path) @@ -100,22 +90,11 @@ def build(self, package_path, build_filename): print("build finished with status %d" % ret) if ret != 0: sys.exit(ret) - - print("Compressing into package...") shutil.make_archive("%s-%s" % (buildVars.ADDON_KEYWORD, build_filename,),'zip',package_path) - def makePackageInfo(self, archive_name, addon_filename, addon_version, build_filename): - if "APPVEYOR_REPO_COMMIT_TIMESTAMP" in os.environ: - #日本標準時オブジェクト - JST = datetime.timezone(datetime.timedelta(hours=+9)) - #Pythonは世界標準時のZに対応していないので文字列処理で乗り切り、それを日本標準時に変換 - dt = datetime.datetime.fromisoformat(os.environ["APPVEYOR_REPO_COMMIT_TIMESTAMP"][0:19]+"+00:00").astimezone(JST) - dateStr = "%s-%s-%s" % (str(dt.year), str(dt.month).zfill(2), str(dt.day).zfill(2)) - else: - dateStr = "this is a local build." - - print("computing hash...") + def makePackageInfo(self, archive_name, addon_filename, build_filename): + print("Calculating hash...") with open(archive_name, mode = "rb") as f: content = f.read() package_hash = hashlib.sha1(content).hexdigest() @@ -127,9 +106,9 @@ def makePackageInfo(self, archive_name, addon_filename, addon_version, build_fil info["package_hash"] = package_hash info["patch_filename"] = addon_filename info["patch_hash"] = addon_hash - info["version"] = addon_version - info["released_date"] = dateStr - with open("DFN-%s_info.json" % (build_filename,), mode = "w") as f: + info["version"] = buildVars.ADDON_VERSION + info["released_date"] = buildVars.ADDON_RELEASE_DATE + with open("%s-%s_info.json" % (buildVars.ADDON_KEYWORD, build_filename,), mode = "w") as f: json.dump(info, f)