From b2eb703212866170a13a80d53aac1c07b5b683b3 Mon Sep 17 00:00:00 2001 From: tanaiadam <65241679+tanaiadam@users.noreply.github.com> Date: Thu, 26 Sep 2024 22:59:21 +0200 Subject: [PATCH 1/4] Deleted old publish-result --- .../workflows/publish-result-pr-build.yaml | 36 -- publish-results-pr/.devcontainer/Dockerfile | 5 - .../.devcontainer/devcontainer.json | 25 -- publish-results-pr/.editorconfig | 18 - publish-results-pr/.gitattributes | 1 - publish-results-pr/.gitignore | 339 ------------------ publish-results-pr/.vscode/launch.json | 12 - publish-results-pr/Dockerfile | 10 - publish-results-pr/go.mod | 10 - publish-results-pr/go.sum | 24 -- .../internal/appargs/args_githubaction.go | 138 ------- .../appargs/args_githubaction_test.go | 100 ------ .../internal/appargs/argsreader.go | 22 -- .../internal/processing/ahkprocessresult.go | 14 - .../imagefilesfinder/imagefilesfinder.go | 25 -- .../imagefilesfinder/imagefilesfinder_test.go | 37 -- .../imagefilesfinder/testfiles/IMG1.PNG | 0 .../imagefilesfinder/testfiles/img3.jpg | 0 .../imagefilesfinder/testfiles/pic2.png | 0 .../processing/neptunparser/neptunparser.go | 42 --- .../neptunparser/neptunparser_test.go | 37 -- .../neptunparser/testfiles/NEPtun03.txt | 1 - .../neptunparser/testfiles/neptun01.txt | 1 - .../neptunparser/testfiles/neptun02.txt | 1 - .../neptunparser/testfiles/neptun04.txt | 1 - .../neptunparser/testfiles/neptun05.txt | 4 - .../neptunparser/testfiles/neptun10.txt | 0 .../neptunparser/testfiles/neptun11.txt | 1 - .../neptunparser/testfiles/neptun12.txt | 1 - .../neptunparser/testfiles/neptun13.txt | 1 - .../internal/processing/processor.go | 72 ---- .../resultsfile/resultsfileparser.go | 145 -------- .../resultsfile/resultsfileparser_test.go | 148 -------- .../resultsfile/testfiles/empty.txt | 0 .../processing/resultsfile/testfiles/res1.txt | 1 - .../processing/resultsfile/testfiles/res2.txt | 1 - .../processing/resultsfile/testfiles/res3.txt | 3 - .../processing/resultsfile/testfiles/res4.txt | 10 - .../processing/resultsfile/testfiles/res5.txt | 2 - .../internal/publishtoapi/apipublisher.go | 98 ----- .../publishtoapi/apipublisher_test.go | 157 -------- .../internal/publishtoapi/config.go | 10 - .../publishtoapi/hmacsignature_test.go | 61 ---- .../internal/publishtoapi/randomstring.go | 15 - .../publishtoapi/randomstring_test.go | 14 - .../internal/publishtopr/commentformatter.go | 113 ------ .../publishtopr/commentformatter_test.go | 285 --------------- .../internal/publishtopr/config.go | 9 - .../httpclientwithdefaultheader.go | 33 -- .../internal/publishtopr/prpublisher.go | 69 ---- publish-results-pr/main.go | 70 ---- 51 files changed, 2222 deletions(-) delete mode 100644 .github/workflows/publish-result-pr-build.yaml delete mode 100644 publish-results-pr/.devcontainer/Dockerfile delete mode 100644 publish-results-pr/.devcontainer/devcontainer.json delete mode 100644 publish-results-pr/.editorconfig delete mode 100644 publish-results-pr/.gitattributes delete mode 100644 publish-results-pr/.gitignore delete mode 100644 publish-results-pr/.vscode/launch.json delete mode 100644 publish-results-pr/Dockerfile delete mode 100644 publish-results-pr/go.mod delete mode 100644 publish-results-pr/go.sum delete mode 100644 publish-results-pr/internal/appargs/args_githubaction.go delete mode 100644 publish-results-pr/internal/appargs/args_githubaction_test.go delete mode 100644 publish-results-pr/internal/appargs/argsreader.go delete mode 100644 publish-results-pr/internal/processing/ahkprocessresult.go delete mode 100644 publish-results-pr/internal/processing/imagefilesfinder/imagefilesfinder.go delete mode 100644 publish-results-pr/internal/processing/imagefilesfinder/imagefilesfinder_test.go delete mode 100644 publish-results-pr/internal/processing/imagefilesfinder/testfiles/IMG1.PNG delete mode 100644 publish-results-pr/internal/processing/imagefilesfinder/testfiles/img3.jpg delete mode 100644 publish-results-pr/internal/processing/imagefilesfinder/testfiles/pic2.png delete mode 100644 publish-results-pr/internal/processing/neptunparser/neptunparser.go delete mode 100644 publish-results-pr/internal/processing/neptunparser/neptunparser_test.go delete mode 100644 publish-results-pr/internal/processing/neptunparser/testfiles/NEPtun03.txt delete mode 100644 publish-results-pr/internal/processing/neptunparser/testfiles/neptun01.txt delete mode 100644 publish-results-pr/internal/processing/neptunparser/testfiles/neptun02.txt delete mode 100644 publish-results-pr/internal/processing/neptunparser/testfiles/neptun04.txt delete mode 100644 publish-results-pr/internal/processing/neptunparser/testfiles/neptun05.txt delete mode 100644 publish-results-pr/internal/processing/neptunparser/testfiles/neptun10.txt delete mode 100644 publish-results-pr/internal/processing/neptunparser/testfiles/neptun11.txt delete mode 100644 publish-results-pr/internal/processing/neptunparser/testfiles/neptun12.txt delete mode 100644 publish-results-pr/internal/processing/neptunparser/testfiles/neptun13.txt delete mode 100644 publish-results-pr/internal/processing/processor.go delete mode 100644 publish-results-pr/internal/processing/resultsfile/resultsfileparser.go delete mode 100644 publish-results-pr/internal/processing/resultsfile/resultsfileparser_test.go delete mode 100644 publish-results-pr/internal/processing/resultsfile/testfiles/empty.txt delete mode 100644 publish-results-pr/internal/processing/resultsfile/testfiles/res1.txt delete mode 100644 publish-results-pr/internal/processing/resultsfile/testfiles/res2.txt delete mode 100644 publish-results-pr/internal/processing/resultsfile/testfiles/res3.txt delete mode 100644 publish-results-pr/internal/processing/resultsfile/testfiles/res4.txt delete mode 100644 publish-results-pr/internal/processing/resultsfile/testfiles/res5.txt delete mode 100644 publish-results-pr/internal/publishtoapi/apipublisher.go delete mode 100644 publish-results-pr/internal/publishtoapi/apipublisher_test.go delete mode 100644 publish-results-pr/internal/publishtoapi/config.go delete mode 100644 publish-results-pr/internal/publishtoapi/hmacsignature_test.go delete mode 100644 publish-results-pr/internal/publishtoapi/randomstring.go delete mode 100644 publish-results-pr/internal/publishtoapi/randomstring_test.go delete mode 100644 publish-results-pr/internal/publishtopr/commentformatter.go delete mode 100644 publish-results-pr/internal/publishtopr/commentformatter_test.go delete mode 100644 publish-results-pr/internal/publishtopr/config.go delete mode 100644 publish-results-pr/internal/publishtopr/httpclientwithdefaultheader.go delete mode 100644 publish-results-pr/internal/publishtopr/prpublisher.go delete mode 100644 publish-results-pr/main.go diff --git a/.github/workflows/publish-result-pr-build.yaml b/.github/workflows/publish-result-pr-build.yaml deleted file mode 100644 index 002eb613..00000000 --- a/.github/workflows/publish-result-pr-build.yaml +++ /dev/null @@ -1,36 +0,0 @@ -name: Publish Result PR - build - -on: - push: - paths: - - "publish-results-pr/**" - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Go setup - uses: actions/setup-go@v2 - with: - go-version: "1.17" - - - uses: actions/cache@v2 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - - name: Build - working-directory: publish-results-pr - run: go build - - - name: Test - working-directory: publish-results-pr - run: go test ./... -test.v diff --git a/publish-results-pr/.devcontainer/Dockerfile b/publish-results-pr/.devcontainer/Dockerfile deleted file mode 100644 index 5cb00887..00000000 --- a/publish-results-pr/.devcontainer/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -ARG VARIANT="1" -FROM mcr.microsoft.com/vscode/devcontainers/go:0-${VARIANT} - -ARG NODE_VERSION="lts/*" -RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c ". /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi diff --git a/publish-results-pr/.devcontainer/devcontainer.json b/publish-results-pr/.devcontainer/devcontainer.json deleted file mode 100644 index f019dc39..00000000 --- a/publish-results-pr/.devcontainer/devcontainer.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "Go", - "build": { - "dockerfile": "Dockerfile", - "args": { - "VARIANT": "1.17", - "NODE_VERSION": "lts/*" - } - }, - "runArgs": [ - "--cap-add=SYS_PTRACE", - "--security-opt", - "seccomp=unconfined" - ], - "settings": { - "go.toolsManagement.checkForUpdates": "local", - "go.useLanguageServer": true, - "go.gopath": "/go", - "go.goroot": "/usr/local/go" - }, - "extensions": [ - "golang.Go" - ], - "remoteUser": "vscode" -} \ No newline at end of file diff --git a/publish-results-pr/.editorconfig b/publish-results-pr/.editorconfig deleted file mode 100644 index 9019d91d..00000000 --- a/publish-results-pr/.editorconfig +++ /dev/null @@ -1,18 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true - -[{*.go,Makefile,.gitmodules,go.mod,go.sum}] -indent_style = tab - -[*.md] -indent_style = tab -trim_trailing_whitespace = false - -[*.{yml,yaml,json}] -indent_style = space -indent_size = 2 diff --git a/publish-results-pr/.gitattributes b/publish-results-pr/.gitattributes deleted file mode 100644 index 6313b56c..00000000 --- a/publish-results-pr/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text=auto eol=lf diff --git a/publish-results-pr/.gitignore b/publish-results-pr/.gitignore deleted file mode 100644 index 54774640..00000000 --- a/publish-results-pr/.gitignore +++ /dev/null @@ -1,339 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ -**/Properties/launchSettings.json - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -*.DS_Store - -out -pkg -debug - -# default binary name -resultprocessor diff --git a/publish-results-pr/.vscode/launch.json b/publish-results-pr/.vscode/launch.json deleted file mode 100644 index 595408a6..00000000 --- a/publish-results-pr/.vscode/launch.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Launch Server", - "type": "go", - "request": "launch", - "mode": "debug", - "program": "${workspaceFolder}/src/server.go" - } - ] -} \ No newline at end of file diff --git a/publish-results-pr/Dockerfile b/publish-results-pr/Dockerfile deleted file mode 100644 index bbef3791..00000000 --- a/publish-results-pr/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM golang:1.17-alpine AS build - -WORKDIR /src -COPY . . -RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-w -extldflags "-static"' -o /bin/ahkpublishresultpr - -FROM scratch -COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ -COPY --from=build /bin/ahkpublishresultpr /bin/ahkpublishresultpr -ENTRYPOINT ["/bin/ahkpublishresultpr"] \ No newline at end of file diff --git a/publish-results-pr/go.mod b/publish-results-pr/go.mod deleted file mode 100644 index e3392914..00000000 --- a/publish-results-pr/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module ahk/publishresultpr - -go 1.17 - -require github.com/google/go-github/v39 v39.0.0 - -require ( - github.com/google/go-querystring v1.1.0 // indirect - golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect -) diff --git a/publish-results-pr/go.sum b/publish-results-pr/go.sum deleted file mode 100644 index d98fb5c8..00000000 --- a/publish-results-pr/go.sum +++ /dev/null @@ -1,24 +0,0 @@ -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github/v39 v39.0.0 h1:pygGA5ySwxEez1N39GnDauD0PaWWuGgayudyZAc941s= -github.com/google/go-github/v39 v39.0.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= diff --git a/publish-results-pr/internal/appargs/args_githubaction.go b/publish-results-pr/internal/appargs/args_githubaction.go deleted file mode 100644 index 5a48eb56..00000000 --- a/publish-results-pr/internal/appargs/args_githubaction.go +++ /dev/null @@ -1,138 +0,0 @@ -package appargs - -import ( - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "os" - "strings" -) - -type argsFromGitHubAction struct { -} - -func NewGitHubActionArgsReader() ArgsReader { - return new(argsFromGitHubAction) -} - -func (r argsFromGitHubAction) GetArgs() (args *AppArgs, err error) { - // getting most information is only possible when running inside GitHub Action. - // Assert that the environment is such. - _, err = getRequiredEnv("GITHUB_ACTIONS") - if err != nil { - return nil, errors.New("GITHUB_ACTIONS not set (not running inside GitHub Actions)") - } - - // These variables are implicitly set bu GitHub Action for the action execution. - ghRepoFullName, err := getRequiredEnv("GITHUB_REPOSITORY") - if err != nil { - return nil, err - } - ghRepoSplit := strings.Split(ghRepoFullName, "/") - if len(ghRepoSplit) != 2 { - return nil, errors.New("GITHUB_REPOSITORY is not in expected format owner/name") - } - ghRepoOwner := ghRepoSplit[0] - ghRepoName := ghRepoSplit[1] - - ghBranch, err := getRequiredEnv("GITHUB_REF") - if err != nil { - return nil, err - } - - ghCommitHash, err := getRequiredEnv("GITHUB_SHA") - if err != nil { - return nil, err - } - - ghActionRunId := getEnvOrDefault("GITHUB_RUN_ID", "") - - // The following are app settings passed using the "with" directive - // the name of the environment variable is prefixed with INPUT_ - neptunFileName := getEnvOrDefault("INPUT_AHK_NEPTUNFILENAME", "neptun.txt") - resultsFile := getEnvOrDefault("INPUT_AHK_RESULTFILE", "result.txt") - imageExt := getEnvOrDefault("INPUT_AHK_IMAGEEXT", "") - - ahkAppUrl := getEnvOrDefault("INPUT_AHK_APPURL", "https://ahk-grade-management.azurewebsites.net/api/evaluation-result") - ahkAppToken := getEnvOrDefault("INPUT_AHK_APPTOKEN", "") - ahkAppSecret := getEnvOrDefault("INPUT_AHK_APPSECRET", "") - - // The following is the token to communicate with GitHub. Passed using the "with" directive too. - ghToken, err := getRequiredEnv("INPUT_GITHUB_TOKEN") - if err != nil { - return nil, err - } - - // The action expects to be executed within a pull request context. This information is - // parsed from the pull request event payload event present as a file. - ghEventPayloadFilePath, err := getRequiredEnv("GITHUB_EVENT_PATH") - if err != nil { - return nil, err - } - - ghPrNum, err := getPrNumFromPayload(ghEventPayloadFilePath) - if err != nil { - return nil, err - } - - return &AppArgs{ - GitHubRepoFullName: ghRepoFullName, - GitHubRepoOwner: ghRepoOwner, - GitHubRepoName: ghRepoName, - GitHubBranch: ghBranch, - GitHubActionRunId: ghActionRunId, - GitCommitHash: ghCommitHash, - GitHubPullRequestNum: ghPrNum, - GitHubToken: ghToken, - NeptunFileName: neptunFileName, - ImageExtension: imageExt, - ResultFile: resultsFile, - AhkAppUrl: ahkAppUrl, - AhkAppToken: ahkAppToken, - AhkAppSecret: ahkAppSecret, - }, nil -} - -func getRequiredEnv(key string) (value string, err error) { - value, success := os.LookupEnv(key) - if !success || value == "" { - return "", fmt.Errorf("missing required environment variable %s", key) - } - return value, nil -} - -func getEnvOrDefault(key string, defaultValue string) string { - value, success := os.LookupEnv(key) - if !success { - return defaultValue - } - return value -} - -type GitHubEventPayload struct { - PullRequest struct { - Number int `json:"number"` - } `json:"pull_request"` -} - -func getPrNumFromPayload(ghEventPayloadFile string) (value int, err error) { - f, err := os.Open(ghEventPayloadFile) - if err != nil { - return -1, fmt.Errorf("file at %s (from GITHUB_EVENT_PATH) does not exist", ghEventPayloadFile) - } - defer f.Close() - - rawBytes, err := ioutil.ReadAll(f) - if err != nil { - return -1, fmt.Errorf("file at %s (from GITHUB_EVENT_PATH) cannot be read", ghEventPayloadFile) - } - - payload := GitHubEventPayload{} - err = json.Unmarshal(rawBytes, &payload) - if err != nil { - return -1, errors.New("not running within a pull request event context") - } - - return payload.PullRequest.Number, nil -} diff --git a/publish-results-pr/internal/appargs/args_githubaction_test.go b/publish-results-pr/internal/appargs/args_githubaction_test.go deleted file mode 100644 index 38fef82f..00000000 --- a/publish-results-pr/internal/appargs/args_githubaction_test.go +++ /dev/null @@ -1,100 +0,0 @@ -package appargs - -import ( - "os" - "path" - "reflect" - "strings" - "testing" -) - -func TestGitHubActionArgs_ErrorWhenMissingEnv(t *testing.T) { - if os.Getenv("GITHUB_ACTIONS") != "" { - t.Skip("Skipping test in GitHub Actions") - return - } - - envs := map[string]string{ - "GITHUB_ACTIONS": "true", - "GITHUB_REPOSITORY": "org/repo", - "GITHUB_REF": "main", - "GITHUB_SHA": "aa11bbcc33", - "GITHUB_EVENT_PATH": "path/to.json", - "INPUT_GITHUB_TOKEN": "ghtokghtok", - } - - for envToIgnore := range envs { - t.Run(envToIgnore, func(t *testing.T) { - for key, value := range envs { - if key != envToIgnore { - t.Setenv(key, value) - } - } - - r := NewGitHubActionArgsReader() - _, err := r.GetArgs() - - if err == nil || !strings.Contains(err.Error(), envToIgnore) { - t.Errorf("argsFromGitHubAction should have failed with missing env variable %v", envToIgnore) - } - }) - } -} - -func TestGitHubActionArgs_ArgsReadFromEnv(t *testing.T) { - if os.Getenv("GITHUB_ACTIONS") != "" { - t.Skip("Skipping test in GitHub Actions") - return - } - - tempDir := t.TempDir() - tempJsonFile := path.Join(tempDir, "ghe.json") - t.Setenv("GITHUB_EVENT_PATH", tempJsonFile) - - os.WriteFile(tempJsonFile, []byte(`{"pull_request":{"number":123}}`), 0666) - - envs := map[string]string{ - "GITHUB_ACTIONS": "true", - "GITHUB_REPOSITORY": "org/repo", - "GITHUB_REF": "main", - "GITHUB_SHA": "aa11bbcc33", - "GITHUB_RUN_ID": "2112121212", - "INPUT_GITHUB_TOKEN": "ghtokghtok", - "INPUT_AHK_APPTOKEN": "tokentoken", - "INPUT_AHK_IMAGEEXT": ".ext", - "INPUT_AHK_APPSECRET": "secretsecret", - } - - expected := AppArgs{ - GitHubRepoFullName: "org/repo", - GitHubRepoOwner: "org", - GitHubRepoName: "repo", - GitHubBranch: "main", - GitCommitHash: "aa11bbcc33", - GitHubActionRunId: "2112121212", - GitHubPullRequestNum: 123, - GitHubToken: "ghtokghtok", - NeptunFileName: "neptun.txt", - ImageExtension: ".ext", - ResultFile: "result.txt", - AhkAppUrl: `https://ahk-grade-management.azurewebsites.net/api/evaluation-result`, - AhkAppToken: "tokentoken", - AhkAppSecret: "secretsecret", - } - - for key, value := range envs { - t.Setenv(key, value) - } - - r := NewGitHubActionArgsReader() - actual, err := r.GetArgs() - - if err != nil { - t.Errorf("argsFromGitHubAction failed with %v", err) - return - } - - if !reflect.DeepEqual(*actual, expected) { - t.Errorf("argsFromGitHubAction expected %+v got %+v", expected, *actual) - } -} diff --git a/publish-results-pr/internal/appargs/argsreader.go b/publish-results-pr/internal/appargs/argsreader.go deleted file mode 100644 index f01c5a37..00000000 --- a/publish-results-pr/internal/appargs/argsreader.go +++ /dev/null @@ -1,22 +0,0 @@ -package appargs - -type AppArgs struct { - GitHubRepoFullName string - GitHubRepoOwner string - GitHubRepoName string - GitHubBranch string - GitCommitHash string - GitHubActionRunId string - GitHubPullRequestNum int - GitHubToken string - NeptunFileName string - ImageExtension string - ResultFile string - AhkAppUrl string - AhkAppSecret string - AhkAppToken string -} - -type ArgsReader interface { - GetArgs() (args *AppArgs, err error) -} diff --git a/publish-results-pr/internal/processing/ahkprocessresult.go b/publish-results-pr/internal/processing/ahkprocessresult.go deleted file mode 100644 index 5f79680a..00000000 --- a/publish-results-pr/internal/processing/ahkprocessresult.go +++ /dev/null @@ -1,14 +0,0 @@ -package processing - -import resultsfileparser "ahk/publishresultpr/internal/processing/resultsfile" - -type AhkProcessResult struct { - GitHubRepoName string `json:"gitHubRepoName"` - GitHubBranch string `json:"gitHubBranch"` - GitHubPullRequestNum int `json:"gitHubPullRequestNum,omitempty"` - GitHubCommitHash string `json:"gitHubCommitHash"` - NeptunCode string `json:"neptunCode"` - ImageFiles []string `json:"imageFiles"` - Result []resultsfileparser.AhkTaskResult `json:"result"` - Origin string `json:"origin,omitempty"` -} diff --git a/publish-results-pr/internal/processing/imagefilesfinder/imagefilesfinder.go b/publish-results-pr/internal/processing/imagefilesfinder/imagefilesfinder.go deleted file mode 100644 index 2ed67368..00000000 --- a/publish-results-pr/internal/processing/imagefilesfinder/imagefilesfinder.go +++ /dev/null @@ -1,25 +0,0 @@ -package imagefilesfinder - -import ( - "os" - "path/filepath" - "sort" - "strings" -) - -type ImageFileFinder struct{} - -func (p *ImageFileFinder) GetImageFiles(dir string, fileExtension string) (value []string, err error) { - files := make([]string, 0) - err = filepath.WalkDir(dir, func(path string, f os.DirEntry, _ error) error { - if !f.IsDir() { - if strings.EqualFold(filepath.Ext(path), fileExtension) { - files = append(files, f.Name()) - } - } - return nil - }) - - sort.Strings(files) - return files, err -} diff --git a/publish-results-pr/internal/processing/imagefilesfinder/imagefilesfinder_test.go b/publish-results-pr/internal/processing/imagefilesfinder/imagefilesfinder_test.go deleted file mode 100644 index e887815f..00000000 --- a/publish-results-pr/internal/processing/imagefilesfinder/imagefilesfinder_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package imagefilesfinder - -import ( - "reflect" - "testing" -) - -func TestImageFileFinder_GetImageFiles(t *testing.T) { - tests := []struct { - dir string - fileExtension string - wantValue []string - wantErr bool - }{ - {"testfiles", ".png", []string{"IMG1.PNG", "pic2.png"}, false}, - {"testfiles", ".jpg", []string{"img3.jpg"}, false}, - {"testfiles", ".abc", []string{}, false}, - } - for _, tt := range tests { - t.Run("a", func(t *testing.T) { - p := &ImageFileFinder{} - gotValue, err := p.GetImageFiles(tt.dir, tt.fileExtension) - - if (err != nil) != tt.wantErr { - t.Errorf("ImageFileFinder.GetImageFiles() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if tt.wantValue == nil && gotValue != nil { - t.Errorf("ImageFileFinder.GetImageFiles() = %v, want %v", gotValue, tt.wantValue) - } - if tt.wantValue != nil && !reflect.DeepEqual(gotValue, tt.wantValue) { - t.Errorf("ImageFileFinder.GetImageFiles() = %v, want %v", gotValue, tt.wantValue) - } - }) - } -} diff --git a/publish-results-pr/internal/processing/imagefilesfinder/testfiles/IMG1.PNG b/publish-results-pr/internal/processing/imagefilesfinder/testfiles/IMG1.PNG deleted file mode 100644 index e69de29b..00000000 diff --git a/publish-results-pr/internal/processing/imagefilesfinder/testfiles/img3.jpg b/publish-results-pr/internal/processing/imagefilesfinder/testfiles/img3.jpg deleted file mode 100644 index e69de29b..00000000 diff --git a/publish-results-pr/internal/processing/imagefilesfinder/testfiles/pic2.png b/publish-results-pr/internal/processing/imagefilesfinder/testfiles/pic2.png deleted file mode 100644 index e69de29b..00000000 diff --git a/publish-results-pr/internal/processing/neptunparser/neptunparser.go b/publish-results-pr/internal/processing/neptunparser/neptunparser.go deleted file mode 100644 index c1d7f00c..00000000 --- a/publish-results-pr/internal/processing/neptunparser/neptunparser.go +++ /dev/null @@ -1,42 +0,0 @@ -package neptunparser - -import ( - "errors" - "io/ioutil" - "os" - "regexp" - "strings" -) - -type NeptunParser struct{} - -func (p *NeptunParser) ParseNeptun(fileName string) (value *string, err error) { - f, err := os.Open(fileName) - if err != nil { - return nil, errors.New("neptun.txt nem talalhato - neptun.txt does not exist") - } - defer f.Close() - - rawBytes, err := ioutil.ReadAll(f) - if err != nil { - return nil, errors.New("neptun.txt nem talalhato - neptun.txt does not exist") - } - - lines := strings.Split(string(rawBytes), "\n") - if len(lines) == 0 { - return nil, errors.New("neptun.txt ures - neptun.txt is empty") - } - - neptun := strings.TrimSpace(lines[0]) - if len(neptun) == 0 { - return nil, errors.New("neptun.txt ures - neptun.txt is empty") - } - - matched, _ := regexp.MatchString("^[a-zA-Z0-9]{6}$", neptun) - if !matched { - return nil, errors.New("neptun.txt ervenytelen neptun kodot tartalmaz - neptun.txt contains an invalid neptun code") - } - - neptun = strings.ToUpper(neptun) - return &neptun, nil -} diff --git a/publish-results-pr/internal/processing/neptunparser/neptunparser_test.go b/publish-results-pr/internal/processing/neptunparser/neptunparser_test.go deleted file mode 100644 index 6200628c..00000000 --- a/publish-results-pr/internal/processing/neptunparser/neptunparser_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package neptunparser - -import "testing" - -func TestNeptunParser_ParseNeptun(t *testing.T) { - tests := []struct { - fileName string - wantValue string - wantErr bool - }{ - {"testfiles/neptun01.txt", "ABC123", false}, - {"testfiles/neptun02.txt", "ABC123", false}, - {"testfiles/NEPtun03.txt", "AB12C3", false}, - {"testfiles/neptun04.txt", "ABC123", false}, - {"testfiles/neptun05.txt", "ABC123", false}, - {"testfiles/nosuchfile", "", true}, - {"testfiles/nosuchfile.txt", "", true}, - {"testfiles/neptun10.txt", "", true}, - } - for _, tt := range tests { - t.Run(tt.fileName, func(t *testing.T) { - p := &NeptunParser{} - gotValue, err := p.ParseNeptun(tt.fileName) - if (err != nil) != tt.wantErr { - t.Errorf("NeptunParser.ParseNeptun() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if tt.wantValue == "" && gotValue != nil { - t.Errorf("NeptunParser.ParseNeptun() = %v, want nil", gotValue) - } - if gotValue != nil && *gotValue != tt.wantValue { - t.Errorf("NeptunParser.ParseNeptun() = %v, want %v", gotValue, tt.wantValue) - } - }) - } -} diff --git a/publish-results-pr/internal/processing/neptunparser/testfiles/NEPtun03.txt b/publish-results-pr/internal/processing/neptunparser/testfiles/NEPtun03.txt deleted file mode 100644 index 998a930c..00000000 --- a/publish-results-pr/internal/processing/neptunparser/testfiles/NEPtun03.txt +++ /dev/null @@ -1 +0,0 @@ -Ab12C3 \ No newline at end of file diff --git a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun01.txt b/publish-results-pr/internal/processing/neptunparser/testfiles/neptun01.txt deleted file mode 100644 index 8edce441..00000000 --- a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun01.txt +++ /dev/null @@ -1 +0,0 @@ -ABC123 \ No newline at end of file diff --git a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun02.txt b/publish-results-pr/internal/processing/neptunparser/testfiles/neptun02.txt deleted file mode 100644 index d79ed91b..00000000 --- a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun02.txt +++ /dev/null @@ -1 +0,0 @@ -abC123 \ No newline at end of file diff --git a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun04.txt b/publish-results-pr/internal/processing/neptunparser/testfiles/neptun04.txt deleted file mode 100644 index 92dd6473..00000000 --- a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun04.txt +++ /dev/null @@ -1 +0,0 @@ -ABC123 diff --git a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun05.txt b/publish-results-pr/internal/processing/neptunparser/testfiles/neptun05.txt deleted file mode 100644 index dd6d622e..00000000 --- a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun05.txt +++ /dev/null @@ -1,4 +0,0 @@ -ABC123 - - - diff --git a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun10.txt b/publish-results-pr/internal/processing/neptunparser/testfiles/neptun10.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun11.txt b/publish-results-pr/internal/processing/neptunparser/testfiles/neptun11.txt deleted file mode 100644 index dfc91791..00000000 --- a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun11.txt +++ /dev/null @@ -1 +0,0 @@ -AB \ No newline at end of file diff --git a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun12.txt b/publish-results-pr/internal/processing/neptunparser/testfiles/neptun12.txt deleted file mode 100644 index bb1645ec..00000000 --- a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun12.txt +++ /dev/null @@ -1 +0,0 @@ -ABCABCABC \ No newline at end of file diff --git a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun13.txt b/publish-results-pr/internal/processing/neptunparser/testfiles/neptun13.txt deleted file mode 100644 index f0a71ae9..00000000 --- a/publish-results-pr/internal/processing/neptunparser/testfiles/neptun13.txt +++ /dev/null @@ -1 +0,0 @@ -abc123abc123 diff --git a/publish-results-pr/internal/processing/processor.go b/publish-results-pr/internal/processing/processor.go deleted file mode 100644 index 2d378e1b..00000000 --- a/publish-results-pr/internal/processing/processor.go +++ /dev/null @@ -1,72 +0,0 @@ -package processing - -import ( - "fmt" - "log" - - "ahk/publishresultpr/internal/appargs" - "ahk/publishresultpr/internal/processing/imagefilesfinder" - "ahk/publishresultpr/internal/processing/neptunparser" - resultsfileparser "ahk/publishresultpr/internal/processing/resultsfile" -) - -type Processor interface { - Process(appArgs appargs.AppArgs, workingDir string) (res AhkProcessResult, err error) -} - -type processor struct { -} - -func NewProcessor() Processor { - return new(processor) -} - -func (p *processor) Process(appArgs appargs.AppArgs, workingDir string) (res AhkProcessResult, err error) { - neptunParser := new(neptunparser.NeptunParser) - neptun, err := neptunParser.ParseNeptun(appArgs.NeptunFileName) - if err != nil { - return AhkProcessResult{}, err - } - log.Printf("Neptun: %s\n", *neptun) - - var imageFiles []string - if appArgs.ImageExtension == "" { - log.Println("Image files gathering not requested") - imageFiles = []string{} - } else { - imageFilesFinder := new(imagefilesfinder.ImageFileFinder) - imageFiles, err = imageFilesFinder.GetImageFiles(workingDir, appArgs.ImageExtension) - if err != nil { - return AhkProcessResult{}, err - } - for _, imageFile := range imageFiles { - log.Printf("Found image file: %s\n", imageFile) - } - } - - var results []resultsfileparser.AhkTaskResult - if appArgs.ResultFile == "" { - log.Println("Result file processing not requested") - results = []resultsfileparser.AhkTaskResult{} - } else { - resultsFileParser := new(resultsfileparser.ResultsFileParser) - results, err = resultsFileParser.ParseResultsFile(appArgs.ResultFile) - if err != nil { - return AhkProcessResult{}, err - } - for _, r := range results { - log.Printf("Result for %s %s %f\n", r.ExerciseName, r.TaskName, r.Points) - } - } - - return AhkProcessResult{ - GitHubRepoName: appArgs.GitHubRepoFullName, - GitHubBranch: appArgs.GitHubBranch, - GitHubPullRequestNum: appArgs.GitHubPullRequestNum, - GitHubCommitHash: appArgs.GitCommitHash, - NeptunCode: *neptun, - ImageFiles: imageFiles, - Result: results, - Origin: fmt.Sprintf("https://github.com/%s/commit/%s https://github.com/%s/actions/runs/%s", appArgs.GitHubRepoFullName, appArgs.GitCommitHash, appArgs.GitHubRepoFullName, appArgs.GitHubActionRunId), - }, nil -} diff --git a/publish-results-pr/internal/processing/resultsfile/resultsfileparser.go b/publish-results-pr/internal/processing/resultsfile/resultsfileparser.go deleted file mode 100644 index 5e2ebaae..00000000 --- a/publish-results-pr/internal/processing/resultsfile/resultsfileparser.go +++ /dev/null @@ -1,145 +0,0 @@ -package resultsfileparser - -import ( - "errors" - "io/ioutil" - "log" - "math" - "os" - "strconv" - "strings" -) - -type AhkTaskResult struct { - ExerciseName string `json:"exerciseName,omitempty"` - TaskName string `json:"taskName"` - Points float64 `json:"points"` - Comment string `json:"comment,omitempty"` -} - -type ResultsFileParser struct{} - -func (p *ResultsFileParser) ParseResultsFile(fileName string) (value []AhkTaskResult, err error) { - f, err := os.Open(fileName) - if err != nil { - return nil, errors.New("eredmeny fajl nem talalhato - result file not found") - } - defer f.Close() - - rawBytes, err := ioutil.ReadAll(f) - if err != nil { - return nil, errors.New("eredmeny fajl nem talalhato - result file not found") - } - - lines := strings.Split(strings.TrimPrefix(string(rawBytes), "\uFEFF"), "\n") // strip BOM and split lines - if len(lines) == 0 { - return nil, errors.New("eredmeny fajl ures - result file is empty") - } - - results := make([]AhkTaskResult, 0) - lineIdx := 0 - for { - if lineIdx >= len(lines) { - break - } - - line := lines[lineIdx] - lineIdx = lineIdx + 1 - - line = strings.TrimSpace(line) - if len(line) == 0 { - continue - } - - if strings.HasPrefix(line, "###ahk#") { - for strings.HasSuffix(line, "\\") { - line = strings.TrimSpace(line[:len(line)-1]) - - if lineIdx < len(lines) { - nextLine := lines[lineIdx] - lineIdx = lineIdx + 1 - line = line + "\n" + strings.TrimSpace(nextLine) - } - } - - // ###ahk#taskname#result#comment - items := strings.Split(line, "#") - items = removeEmptyStrings(items) - if len(items) < 3 { - log.Printf("Invalid line: %s", line) - } else { - results = append(results, AhkTaskResult{ - ExerciseName: getExerciseName(items[1]), - TaskName: getTaskName(items[1]), - Points: getPoints(items[2]), - Comment: getComments(items), - }) - } - } else { - log.Printf("Invalid prefix in line: %s", line) - } - } - - if len(results) == 0 { - return nil, errors.New("eredmeny fajl ures - result file is empty") - } - - return results, nil -} - -// Gets task from exercise@task -func getTaskName(name string) string { - if len(name) == 0 { - return "" - } - - idx := strings.Index(name, "@") - if idx > -1 { - return name[idx+1:] - } else { - return name - } -} - -// Gets exercise from exercise@task -func getExerciseName(name string) string { - if len(name) == 0 { - return "" - } - - idx := strings.Index(name, "@") - if idx > -1 { - return name[0:idx] - } else { - return "" - } -} - -func getPoints(str string) float64 { - if len(str) == 0 { - return math.NaN() - } - - if num, err := strconv.ParseFloat(str, 64); err == nil { - return num - } - - return math.NaN() -} - -func getComments(items []string) string { - if len(items) > 3 { - return strings.Join(items[3:], " ") - } - return "" -} - -func removeEmptyStrings(value []string) []string { - result := []string{} - for i := range value { - if len(value[i]) > 0 { - result = append(result, value[i]) - } - } - return result -} diff --git a/publish-results-pr/internal/processing/resultsfile/resultsfileparser_test.go b/publish-results-pr/internal/processing/resultsfile/resultsfileparser_test.go deleted file mode 100644 index dcb72e57..00000000 --- a/publish-results-pr/internal/processing/resultsfile/resultsfileparser_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package resultsfileparser - -import ( - "math" - "testing" -) - -func TestResultsFileParser_ParseResultsFile(t *testing.T) { - tests := []struct { - fileName string - wantValue []AhkTaskResult - wantErr bool - }{ - { - fileName: "testfiles/doesnotexist.txt", - wantErr: true, - }, - { - fileName: "testfiles/empty.txt", - wantErr: true, - }, - { - fileName: "testfiles/res1.txt", - wantErr: false, - wantValue: []AhkTaskResult{ - { - ExerciseName: "", - TaskName: "ex1", - Points: 2, - }, - }, - }, - { - fileName: "testfiles/res2.txt", - wantErr: false, - wantValue: []AhkTaskResult{ - { - ExerciseName: "", - TaskName: "ex1", - Points: 2, - }, - }, - }, - { - fileName: "testfiles/res3.txt", - wantErr: false, - wantValue: []AhkTaskResult{ - { - ExerciseName: "ex1", - TaskName: "t1", - Points: 2.5, - }, - { - ExerciseName: "ex1", - TaskName: "t2", - Points: 3, - Comment: "comment", - }, - }, - }, - { - fileName: "testfiles/res4.txt", - wantErr: false, - wantValue: []AhkTaskResult{ - { - ExerciseName: "ex1", - TaskName: "t1", - Points: 2, - Comment: "line1\nline2 abc\nline3 end", - }, - { - ExerciseName: "ex1", - TaskName: "t2", - Points: 3, - Comment: "comment", - }, - { - ExerciseName: "", - TaskName: "ex3", - Points: 0, - Comment: "line1\nline2 abc\nline3 end", - }, - }, - }, - { - fileName: "testfiles/res5.txt", - wantErr: false, - wantValue: []AhkTaskResult{ - { - ExerciseName: "", - TaskName: "ex1", - Points: 1, - }, - { - ExerciseName: "", - TaskName: "ex2", - Points: math.NaN(), - Comment: "comment", - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.fileName, func(t *testing.T) { - p := &ResultsFileParser{} - gotValue, err := p.ParseResultsFile(tt.fileName) - if (err != nil) != tt.wantErr { - t.Errorf("ResultsFileParser.ParseResultsFile() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !isEqualArray(gotValue, tt.wantValue) { - t.Errorf("ResultsFileParser.ParseResultsFile() = %v, want %v", gotValue, tt.wantValue) - } - }) - } -} - -// need manual comparison as NaN does not equal NaN -func isEqualArray(actual, expected []AhkTaskResult) bool { - if len(actual) != len(expected) { - return false - } - for i := 0; i < len(actual); i++ { - if !isEqualOne(actual[i], expected[i]) { - return false - } - } - return true -} - -func isEqualOne(actual, expected AhkTaskResult) bool { - if actual.ExerciseName != expected.ExerciseName { - return false - } - if actual.TaskName != expected.TaskName { - return false - } - if actual.Comment != expected.Comment { - return false - } - if math.IsNaN(expected.Points) != math.IsNaN(actual.Points) { - return false - } - if !math.IsNaN(expected.Points) && expected.Points != actual.Points { - return false - } - return true -} diff --git a/publish-results-pr/internal/processing/resultsfile/testfiles/empty.txt b/publish-results-pr/internal/processing/resultsfile/testfiles/empty.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/publish-results-pr/internal/processing/resultsfile/testfiles/res1.txt b/publish-results-pr/internal/processing/resultsfile/testfiles/res1.txt deleted file mode 100644 index 00e089cf..00000000 --- a/publish-results-pr/internal/processing/resultsfile/testfiles/res1.txt +++ /dev/null @@ -1 +0,0 @@ -###ahk#ex1#2 \ No newline at end of file diff --git a/publish-results-pr/internal/processing/resultsfile/testfiles/res2.txt b/publish-results-pr/internal/processing/resultsfile/testfiles/res2.txt deleted file mode 100644 index 90cc2d01..00000000 --- a/publish-results-pr/internal/processing/resultsfile/testfiles/res2.txt +++ /dev/null @@ -1 +0,0 @@ -###ahk#ex1#2 diff --git a/publish-results-pr/internal/processing/resultsfile/testfiles/res3.txt b/publish-results-pr/internal/processing/resultsfile/testfiles/res3.txt deleted file mode 100644 index 3c860560..00000000 --- a/publish-results-pr/internal/processing/resultsfile/testfiles/res3.txt +++ /dev/null @@ -1,3 +0,0 @@ -###ahk#ex1@t1#2.5 -###ahk#ex1@t2#3#comment -###ahk#invalid diff --git a/publish-results-pr/internal/processing/resultsfile/testfiles/res4.txt b/publish-results-pr/internal/processing/resultsfile/testfiles/res4.txt deleted file mode 100644 index b4b8a5f5..00000000 --- a/publish-results-pr/internal/processing/resultsfile/testfiles/res4.txt +++ /dev/null @@ -1,10 +0,0 @@ -something -###ahk#ex1@t1#2#line1\ -line2 abc \ -line3 end -###ahk#ex1@t2#3#comment -aaa aaa -###ahk#ex3#0#line1\ -line2 abc \ -line3 end -aaa aaa diff --git a/publish-results-pr/internal/processing/resultsfile/testfiles/res5.txt b/publish-results-pr/internal/processing/resultsfile/testfiles/res5.txt deleted file mode 100644 index f164fd5a..00000000 --- a/publish-results-pr/internal/processing/resultsfile/testfiles/res5.txt +++ /dev/null @@ -1,2 +0,0 @@ -###ahk#ex1#1 -###ahk#ex2#inconclusive#comment diff --git a/publish-results-pr/internal/publishtoapi/apipublisher.go b/publish-results-pr/internal/publishtoapi/apipublisher.go deleted file mode 100644 index 5549ef50..00000000 --- a/publish-results-pr/internal/publishtoapi/apipublisher.go +++ /dev/null @@ -1,98 +0,0 @@ -package publishtoapi - -import ( - "bytes" - "crypto/hmac" - "crypto/sha256" - "encoding/base64" - "encoding/json" - "fmt" - "log" - "math" - "net/http" - "net/http/httputil" - "strings" - "time" - - "ahk/publishresultpr/internal/processing" -) - -type apiPublisher struct{} - -type ApiPublisher interface { - Publish(result processing.AhkProcessResult, config Config) error -} - -func NewApiPublisher() ApiPublisher { - return new(apiPublisher) -} - -func SerializeResultAsJson(result processing.AhkProcessResult) ([]byte, error) { - // marshaler does not tolerate NaN - fixupData(&result) - jsonStr, err := json.Marshal(result) - return jsonStr, err -} - -func (s *apiPublisher) Publish(result processing.AhkProcessResult, config Config) error { - - jsonStr, err := SerializeResultAsJson(result) - if err != nil { - return err - } - - req, err := http.NewRequest(http.MethodPost, config.Url, bytes.NewBuffer(jsonStr)) - if err != nil { - return err - } - - hmacsig := getHmacSignature(string(jsonStr), http.MethodPost, config.Url, config.Secret, config.Date) - - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Ahk-Token", config.Token) - req.Header.Set("X-Ahk-Sha256", hmacsig) - req.Header.Set("X-Ahk-Delivery", getRandomString(16)) - req.Header.Set("Date", config.Date.Format(http.TimeFormat)) - - log.Printf("Sending HTTP %s to %s\n", req.Method, req.URL) - log.Printf("Token: %s*****\n", config.Token[:4]) - log.Printf("Sig: %s*****\n", hmacsig[:4]) - log.Printf("Date: %s\n", config.Date.Format(http.TimeFormat)) - - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - log.Println("Request sent.") - - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - d, _ := httputil.DumpResponse(resp, true) - log.Printf("Response indicates an error\n%s", string(d)) - return fmt.Errorf("sending data to server was not successful, received status code %d", resp.StatusCode) - } - - log.Println("Response indicates success.") - return nil -} - -func getHmacSignature(payload, httpverb, httpurl, secret string, date time.Time) string { - h := hmac.New(sha256.New, []byte(secret)) - h.Write([]byte(strings.ToUpper(httpverb) + "\n")) - h.Write([]byte(strings.ToLower(httpurl) + "\n")) - h.Write([]byte(date.Format(http.TimeFormat) + "\n")) - h.Write([]byte(payload)) - return base64.StdEncoding.EncodeToString(h.Sum(nil)) -} - -func fixupData(data *processing.AhkProcessResult) { - if data.Result != nil { - for i := 0; i < len(data.Result); i++ { - if math.IsNaN(data.Result[i].Points) { - data.Result[i].Points = 0 - } - } - } -} diff --git a/publish-results-pr/internal/publishtoapi/apipublisher_test.go b/publish-results-pr/internal/publishtoapi/apipublisher_test.go deleted file mode 100644 index 14396b87..00000000 --- a/publish-results-pr/internal/publishtoapi/apipublisher_test.go +++ /dev/null @@ -1,157 +0,0 @@ -package publishtoapi - -import ( - "math" - "net/http" - "net/http/httptest" - "testing" - "time" - - "ahk/publishresultpr/internal/processing" - resultsfileparser "ahk/publishresultpr/internal/processing/resultsfile" -) - -func TestApiPublisher_Json(t *testing.T) { - tests := []struct { - data processing.AhkProcessResult - wantValue string - }{ - { - data: processing.AhkProcessResult{ - GitHubRepoName: "org/name", - GitHubBranch: "branch", - GitHubPullRequestNum: 0, - GitHubCommitHash: "aa11cc33", - NeptunCode: "ABC123", - ImageFiles: []string{"img1.png", "img2.png"}, - Result: []resultsfileparser.AhkTaskResult{ - { - ExerciseName: "ex1", - TaskName: "t1", - Points: 2, - Comment: "line1 abc\nlin2 end", - }, - }, - }, - wantValue: `{"gitHubRepoName":"org/name","gitHubBranch":"branch","gitHubCommitHash":"aa11cc33","neptunCode":"ABC123","imageFiles":["img1.png","img2.png"],"result":[{"exerciseName":"ex1","taskName":"t1","points":2,"comment":"line1 abc\nlin2 end"}]}`, - }, - { - data: processing.AhkProcessResult{ - GitHubRepoName: "org/name", - GitHubBranch: "branch", - GitHubPullRequestNum: 123, - GitHubCommitHash: "aa11cc33", - NeptunCode: "ABC123", - ImageFiles: []string{}, - Result: []resultsfileparser.AhkTaskResult{ - { - ExerciseName: "ex1", - TaskName: "t1", - Points: 2, - Comment: "line1 abc\nlin2 end", - }, - { - TaskName: "t1", - Points: 5, - }, - }, - Origin: "orgstr", - }, - wantValue: `{"gitHubRepoName":"org/name","gitHubBranch":"branch","gitHubPullRequestNum":123,"gitHubCommitHash":"aa11cc33","neptunCode":"ABC123","imageFiles":[],"result":[{"exerciseName":"ex1","taskName":"t1","points":2,"comment":"line1 abc\nlin2 end"},{"taskName":"t1","points":5}],"origin":"orgstr"}`, - }, - { - data: processing.AhkProcessResult{ - GitHubRepoName: "org/name", - GitHubBranch: "branch", - GitHubPullRequestNum: 0, - GitHubCommitHash: "aa11cc33", - NeptunCode: "ABC123", - ImageFiles: []string{"img1.png", "img2.png"}, - Result: []resultsfileparser.AhkTaskResult{ - { - ExerciseName: "ex1", - TaskName: "t1", - Points: math.NaN(), - Comment: "ccc", - }, - }, - }, - wantValue: `{"gitHubRepoName":"org/name","gitHubBranch":"branch","gitHubCommitHash":"aa11cc33","neptunCode":"ABC123","imageFiles":["img1.png","img2.png"],"result":[{"exerciseName":"ex1","taskName":"t1","points":0,"comment":"ccc"}]}`, - }, - } - for _, tt := range tests { - t.Run("TestApiPublisher_Json", func(t *testing.T) { - - bytes, err := SerializeResultAsJson(tt.data) - if err != nil { - t.Error(err) - return - } - actual := string(bytes) - - if actual != tt.wantValue { - t.Errorf("AhkProcessResult Json serialized = %v, want %v", actual, tt.wantValue) - } - }) - } -} - -func TestApiPublisher_HasContent(t *testing.T) { - headers := []struct { - headerName string - wantValue string - }{ - { - headerName: "X-Ahk-Token", - wantValue: "xxtoken3333", - }, - { - headerName: "Date", - wantValue: "Wed, 01 Sep 2021 13:34:56 GMT", - }, - } - t.Run("TestApiPublisher_HasContent", func(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - - if r.Method != "POST" { - t.Errorf("Expected POST request, got %s", r.Method) - } - - if _, found := r.Header["X-Ahk-Delivery"]; !found { - t.Errorf("Missing X-Ahk-Delivery header from request") - } - - for _, h := range headers { - actual := r.Header[h.headerName][0] - if actual != h.wantValue { - t.Errorf("Http header %v = %v, want %v", h.headerName, actual, h.wantValue) - } - } - })) - defer ts.Close() - - sender := NewApiPublisher() - err := sender.Publish(processing.AhkProcessResult{}, Config{ - Url: ts.URL, - Token: "xxtoken3333", - Secret: "secret", - Date: time.Date(2021, time.September, 1, 13, 34, 56, 0, time.UTC), - }) - if err != nil { - t.Error(err) - } - }) -} - -func TestApiPublisher_ErrorIfNot200Ok(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusServiceUnavailable) - })) - defer ts.Close() - - sender := NewApiPublisher() - err := sender.Publish(processing.AhkProcessResult{}, Config{Url: ts.URL, Token: "token"}) - if err == nil { - t.Error("failed request should have reported error") - } -} diff --git a/publish-results-pr/internal/publishtoapi/config.go b/publish-results-pr/internal/publishtoapi/config.go deleted file mode 100644 index 17d7dd17..00000000 --- a/publish-results-pr/internal/publishtoapi/config.go +++ /dev/null @@ -1,10 +0,0 @@ -package publishtoapi - -import "time" - -type Config struct { - Url string - Token string - Secret string - Date time.Time -} diff --git a/publish-results-pr/internal/publishtoapi/hmacsignature_test.go b/publish-results-pr/internal/publishtoapi/hmacsignature_test.go deleted file mode 100644 index d41c07eb..00000000 --- a/publish-results-pr/internal/publishtoapi/hmacsignature_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package publishtoapi - -import ( - "testing" - "time" -) - -const secret string = "Wcks02cnncc67c33" -const httpverb string = "POST" -const httpurl string = "https://my.url.com/address" - -func TestHmacSignature(t *testing.T) { - tests := []struct { - data string - wantValue string - }{ - { - data: "aaaaaa\r\nbbbbbbb\r\ncccccccccc\r\n", - wantValue: "SGAhL9hfzLqi30G1uqtQyErRC4oKBlxT9NImaJ/V9CQ=", - }, - { - data: "qqqq\r\nsdfsdfsdfsdf\r\nwwwwwwwwwwwww\r\n", - wantValue: "K7lZXguubpUONKhHh40lAzxt2vPyZnm6LkjLhrYPwAo=", - }, - { - data: "aaaaaaqqqqqqqqqqqqqqq", - wantValue: "cN9KEIb9uO7VskC9mmZ7wWkzqOXirFXcjqB3i4cK0mA=", - }, - } - for _, tt := range tests { - t.Run("TestHmacSignature", func(t *testing.T) { - - date := time.Date(2021, time.September, 1, 13, 34, 56, 0, time.UTC) - - gotValue := getHmacSignature(string(tt.data), httpverb, httpurl, secret, date) - if gotValue != tt.wantValue { - t.Errorf("getHmacSignature() = %v, want %v", gotValue, tt.wantValue) - } - - sigWrongVerb := getHmacSignature(string(tt.data), "wrongverb", httpurl, secret, date) - if sigWrongVerb == tt.wantValue { - t.Errorf("getHmacSignature() should use HttpVerb in calculating hash") - } - - sigWrongUrl := getHmacSignature(string(tt.data), httpverb, "wrongurl", secret, date) - if sigWrongUrl == tt.wantValue { - t.Errorf("getHmacSignature() should use url in calculating hash") - } - - sigWrongPayload := getHmacSignature(string(tt.data)+"data", httpverb, httpurl, secret, date) - if sigWrongPayload == tt.wantValue { - t.Errorf("getHmacSignature() should use payload in calculating hash") - } - - sigWrongDate := getHmacSignature(string(tt.data), httpverb, httpurl, secret, date.Add(time.Second)) - if sigWrongDate == tt.wantValue { - t.Errorf("getHmacSignature() should use date in calculating hash") - } - }) - } -} diff --git a/publish-results-pr/internal/publishtoapi/randomstring.go b/publish-results-pr/internal/publishtoapi/randomstring.go deleted file mode 100644 index eac2b65a..00000000 --- a/publish-results-pr/internal/publishtoapi/randomstring.go +++ /dev/null @@ -1,15 +0,0 @@ -package publishtoapi - -import ( - "crypto/rand" - "encoding/base64" - "math" -) - -func getRandomString(l int) string { - // based on: https://stackoverflow.com/a/55860599 - buff := make([]byte, int(math.Ceil(float64(l)/float64(1.33333333333)))) - rand.Read(buff) - str := base64.RawURLEncoding.EncodeToString(buff) - return str[:l] -} diff --git a/publish-results-pr/internal/publishtoapi/randomstring_test.go b/publish-results-pr/internal/publishtoapi/randomstring_test.go deleted file mode 100644 index 6a05d28a..00000000 --- a/publish-results-pr/internal/publishtoapi/randomstring_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package publishtoapi - -import ( - "testing" -) - -func TestGenerateRandomString(t *testing.T) { - for l := 1; l < 32; l++ { - s := getRandomString(l) - if len(s) != l { - t.Error("wrong length") - } - } -} diff --git a/publish-results-pr/internal/publishtopr/commentformatter.go b/publish-results-pr/internal/publishtopr/commentformatter.go deleted file mode 100644 index a50816a7..00000000 --- a/publish-results-pr/internal/publishtopr/commentformatter.go +++ /dev/null @@ -1,113 +0,0 @@ -package publishtopr - -import ( - resultsfileparser "ahk/publishresultpr/internal/processing/resultsfile" - "fmt" - "math" - "path" - "sort" - "strconv" - "strings" -) - -const markdown_newline = "\n" - -func createComment(neptun string, imageFiles []string, taskResults []resultsfileparser.AhkTaskResult, repoOwner, repoName, commitHash string) string { - str := strings.Builder{} - - addImages(&str, imageFiles, repoOwner, repoName, commitHash) - addNeptun(&str, neptun) - str.WriteString(markdown_newline + markdown_newline) - addDetailedResults(&str, taskResults) - addSumary(&str, taskResults) - - return str.String() -} - -func addImages(str *strings.Builder, imageFiles []string, repoOwner, repoName, commitHash string) { - if len(imageFiles) > 0 { - for _, r := range imageFiles { - f := path.Base(r) - str.WriteString("**" + f + "**" + markdown_newline + markdown_newline) - str.WriteString(fmt.Sprintf("![](https://github.com/%s/%s/blob/%s/%s?raw=true)", repoOwner, repoName, commitHash, f)) - str.WriteString(markdown_newline + markdown_newline) - } - } -} - -func addNeptun(str *strings.Builder, neptun string) { - if len(neptun) > 0 { - str.WriteString("**Neptun**: " + neptun) - } else { - str.WriteString("**Neptun**: :exclamation: N/A") - } -} - -func addDetailedResults(str *strings.Builder, taskResults []resultsfileparser.AhkTaskResult) { - if len(taskResults) == 0 { - return - } - - for _, r := range taskResults { - str.WriteString("**" + formatTaskName(r) + "**: ") - if math.IsNaN(r.Points) { - str.WriteString("N/A") - } else { - str.WriteString(strconv.FormatFloat(r.Points, 'f', -1, 64)) - } - str.WriteString(markdown_newline) - if len(r.Comment) > 0 { - str.WriteString("> " + r.Comment) - } - str.WriteString(markdown_newline + markdown_newline) - } -} - -func addSumary(str *strings.Builder, taskResults []resultsfileparser.AhkTaskResult) { - if len(taskResults) == 0 { - return - } - - str.WriteString("**Osszesen / Total**:") - str.WriteString(markdown_newline) - - groupByExercise := map[string]float64{} - for _, r := range taskResults { - groupByExercise[r.ExerciseName] += r.Points - } - - // deterministic ordering of items require explicit sorting - exNamesSorted := make([]string, 0) - for name := range groupByExercise { - exNamesSorted = append(exNamesSorted, name) - } - sort.Strings(exNamesSorted) - - for _, name := range exNamesSorted { - value := groupByExercise[name] - if len(name) > 0 { - str.WriteString(name + ": ") - } - - if math.IsNaN(value) { - str.WriteString("inconclusive") - } else { - str.WriteString(strconv.FormatFloat(value, 'f', -1, 64)) - } - - str.WriteString(markdown_newline) - } -} - -func formatTaskName(r resultsfileparser.AhkTaskResult) string { - taskName := r.TaskName - if len(taskName) == 0 { - taskName = "N/A" - } - - if len(r.ExerciseName) > 0 { - return fmt.Sprintf("%s / %s", r.ExerciseName, taskName) - } else { - return taskName - } -} diff --git a/publish-results-pr/internal/publishtopr/commentformatter_test.go b/publish-results-pr/internal/publishtopr/commentformatter_test.go deleted file mode 100644 index b1d322cb..00000000 --- a/publish-results-pr/internal/publishtopr/commentformatter_test.go +++ /dev/null @@ -1,285 +0,0 @@ -package publishtopr - -import ( - resultsfileparser "ahk/publishresultpr/internal/processing/resultsfile" - "math" - "strings" - "testing" -) - -func TestGitHubPublisherTaskNameFormatter(t *testing.T) { - tests := []struct { - taskName string - exerciseName string - wantValue string - }{ - { - taskName: "task", - exerciseName: "ex", - wantValue: "ex / task", - }, - { - taskName: "", - exerciseName: "ex", - wantValue: "ex / N/A", - }, - { - taskName: "task", - exerciseName: "", - wantValue: "task", - }, - } - for _, tt := range tests { - t.Run("TestGitHubPusherTaskNameFormatter", func(t *testing.T) { - input := resultsfileparser.AhkTaskResult{ - ExerciseName: tt.exerciseName, - TaskName: tt.taskName, - } - gotValue := formatTaskName(input) - - if gotValue != tt.wantValue { - t.Errorf("formatTaskName() = %v, want %v", gotValue, tt.wantValue) - } - }) - } -} - -func TestGitHubPublisherNeptunFormatter(t *testing.T) { - tests := []struct { - neptun string - wantValue string - }{ - { - neptun: "ALMA12", - wantValue: "**Neptun**: ALMA12", - }, - { - neptun: "", - wantValue: "**Neptun**: :exclamation: N/A", - }, - } - for _, tt := range tests { - t.Run("TestGitHubPublisherNeptunFormatter", func(t *testing.T) { - str := strings.Builder{} - addNeptun(&str, tt.neptun) - gotValue := str.String() - - if gotValue != tt.wantValue { - t.Errorf("addNeptun() = %v, want %v", gotValue, tt.wantValue) - } - }) - } -} - -func TestGitHubPublisherImagesFormatter(t *testing.T) { - repoOwner := "org" - repoName := "repo" - commitHash := "aa11" - tests := []struct { - imageFiles []string - wantValue string - }{ - { - imageFiles: []string{}, - wantValue: "", - }, - { - imageFiles: []string{"file.jpg"}, - wantValue: "**file.jpg**\n\n![](https://github.com/org/repo/blob/aa11/file.jpg?raw=true)\n\n", - }, - { - imageFiles: []string{"file.jpg", "second.PNG"}, - wantValue: "**file.jpg**\n\n![](https://github.com/org/repo/blob/aa11/file.jpg?raw=true)\n\n**second.PNG**\n\n![](https://github.com/org/repo/blob/aa11/second.PNG?raw=true)\n\n", - }, - } - for _, tt := range tests { - t.Run("TestGitHubPublisherImagesFormatter", func(t *testing.T) { - str := strings.Builder{} - addImages(&str, tt.imageFiles, repoOwner, repoName, commitHash) - gotValue := str.String() - - if gotValue != tt.wantValue { - t.Errorf("addImages() = %v, want %v", gotValue, tt.wantValue) - } - }) - } -} - -func TestGitHubPublisherDetailsResultsFormatter(t *testing.T) { - tests := []struct { - result []resultsfileparser.AhkTaskResult - wantValue string - }{ - { - result: []resultsfileparser.AhkTaskResult{}, - wantValue: "", - }, - { - result: []resultsfileparser.AhkTaskResult{ - { - ExerciseName: "ex1", - TaskName: "t1", - Points: 12, - }, - }, - wantValue: "**ex1 / t1**: 12\n\n\n", - }, - { - result: []resultsfileparser.AhkTaskResult{ - { - ExerciseName: "ex1", - TaskName: "t1", - Points: 12, - }, - { - ExerciseName: "ex2", - TaskName: "t2", - Points: 2, - Comment: "comment comment", - }, - }, - wantValue: "**ex1 / t1**: 12\n\n\n**ex2 / t2**: 2\n> comment comment\n\n", - }, - { - result: []resultsfileparser.AhkTaskResult{ - { - ExerciseName: "", - TaskName: "t1", - Points: 5.1, - }, - { - ExerciseName: "", - TaskName: "t2", - Points: 1, - Comment: "apple apple", - }, - }, - wantValue: "**t1**: 5.1\n\n\n**t2**: 1\n> apple apple\n\n", - }, - { - result: []resultsfileparser.AhkTaskResult{ - { - ExerciseName: "", - TaskName: "t1", - Points: 5.1, - }, - { - ExerciseName: "", - TaskName: "t2", - Points: math.NaN(), - Comment: "apple apple", - }, - { - ExerciseName: "xx", - TaskName: "t4", - Points: 1.1, - }, - { - ExerciseName: "xx", - TaskName: "t5", - Points: 3, - }, - }, - wantValue: "**t1**: 5.1\n\n\n**t2**: N/A\n> apple apple\n\n**xx / t4**: 1.1\n\n\n**xx / t5**: 3\n\n\n", - }, - } - for _, tt := range tests { - t.Run("TestGitHubPublisherDetailsResultsFormatter", func(t *testing.T) { - str := strings.Builder{} - addDetailedResults(&str, tt.result) - gotValue := str.String() - - if gotValue != tt.wantValue { - t.Errorf("addDetailedResults() = %v, want %v", gotValue, tt.wantValue) - } - }) - } -} - -func TestGitHubPublisherSummaryFormatter(t *testing.T) { - tests := []struct { - result []resultsfileparser.AhkTaskResult - wantValue string - }{ - { - result: []resultsfileparser.AhkTaskResult{}, - wantValue: "", - }, - { - result: []resultsfileparser.AhkTaskResult{ - { - ExerciseName: "ex1", - TaskName: "t1", - Points: 12, - }, - }, - wantValue: "**Osszesen / Total**:\nex1: 12\n", - }, - { - result: []resultsfileparser.AhkTaskResult{ - { - ExerciseName: "ex1", - TaskName: "t1", - Points: 12, - }, - { - ExerciseName: "ex2", - TaskName: "t2", - Points: 2, - }, - }, - wantValue: "**Osszesen / Total**:\nex1: 12\nex2: 2\n", - }, - { - result: []resultsfileparser.AhkTaskResult{ - { - ExerciseName: "", - TaskName: "t1", - Points: 5, - }, - { - ExerciseName: "", - TaskName: "t2", - Points: 1, - }, - }, - wantValue: "**Osszesen / Total**:\n6\n", - }, - { - result: []resultsfileparser.AhkTaskResult{ - { - ExerciseName: "", - TaskName: "t1", - Points: 5, - }, - { - ExerciseName: "", - TaskName: "t2", - Points: math.NaN(), - }, - { - ExerciseName: "xx", - TaskName: "t4", - Points: 1.1, - }, - { - ExerciseName: "xx", - TaskName: "t5", - Points: 3, - }, - }, - wantValue: "**Osszesen / Total**:\ninconclusive\nxx: 4.1\n", - }, - } - for _, tt := range tests { - t.Run("TestGitHubPublisherSummaryFormatter", func(t *testing.T) { - str := strings.Builder{} - addSumary(&str, tt.result) - gotValue := str.String() - - if gotValue != tt.wantValue { - t.Errorf("addSumary() = %v, want %v", gotValue, tt.wantValue) - } - }) - } -} diff --git a/publish-results-pr/internal/publishtopr/config.go b/publish-results-pr/internal/publishtopr/config.go deleted file mode 100644 index 04fbd437..00000000 --- a/publish-results-pr/internal/publishtopr/config.go +++ /dev/null @@ -1,9 +0,0 @@ -package publishtopr - -type Config struct { - GitHubToken string - RepoOwner string - RepoName string - PrNumber int - CommitHash string -} diff --git a/publish-results-pr/internal/publishtopr/httpclientwithdefaultheader.go b/publish-results-pr/internal/publishtopr/httpclientwithdefaultheader.go deleted file mode 100644 index 205b8e59..00000000 --- a/publish-results-pr/internal/publishtopr/httpclientwithdefaultheader.go +++ /dev/null @@ -1,33 +0,0 @@ -package publishtopr - -import "net/http" - -type wrappedTransport struct { - http.Header - rt http.RoundTripper -} - -func (h wrappedTransport) RoundTrip(req *http.Request) (*http.Response, error) { - for k, v := range h.Header { - req.Header[k] = v - } - return h.rt.RoundTrip(req) -} - -func getHttpClientWithHeader(name, value string) *http.Client { - client := http.DefaultClient - - transport := client.Transport - if transport == nil { - transport = http.DefaultTransport - } - - mewTransport := wrappedTransport{ - Header: make(http.Header), - rt: transport, - } - mewTransport.Header.Set(name, value) - - client.Transport = mewTransport - return client -} diff --git a/publish-results-pr/internal/publishtopr/prpublisher.go b/publish-results-pr/internal/publishtopr/prpublisher.go deleted file mode 100644 index ac2b8b45..00000000 --- a/publish-results-pr/internal/publishtopr/prpublisher.go +++ /dev/null @@ -1,69 +0,0 @@ -package publishtopr - -import ( - "ahk/publishresultpr/internal/processing" - "context" - "fmt" - "log" - "net/http/httputil" - - "github.com/google/go-github/v39/github" -) - -type prPublisher struct{} - -type PrPublisher interface { - Publish(result processing.AhkProcessResult, config Config) error -} - -func NewPrPublisher() PrPublisher { - return new(prPublisher) -} - -func (s *prPublisher) Publish(result processing.AhkProcessResult, config Config) (err error) { - h := getHttpClientWithHeader("Authorization", fmt.Sprintf("token %s", config.GitHubToken)) - client := github.NewClient(h) - - var commentText = createComment(result.NeptunCode, result.ImageFiles, result.Result, config.RepoOwner, config.RepoName, config.CommitHash) - err = addComment(client, config.RepoOwner, config.RepoName, config.PrNumber, commentText) - if err != nil { - return err - } - - err = removeLabels(client, config.RepoOwner, config.RepoName, config.PrNumber) - if err != nil { - return err - } - - return err -} - -func addComment(client *github.Client, repoOwner, repoName string, prNum int, commentText string) error { - comment := github.IssueComment{ - Body: &commentText, - } - - log.Printf("Sending comment to %s/%s PR %d", repoOwner, repoName, prNum) - createdComment, resp, err := client.Issues.CreateComment(context.Background(), repoOwner, repoName, prNum, &comment) - if err != nil { - d, _ := httputil.DumpResponse(resp.Response, true) - log.Printf("Response indicates an error\n%s", string(d)) - return fmt.Errorf("adding comment to GitHub failed: %w", err) - } - - log.Printf("Created comment with id %d at %s\n", *createdComment.ID, *createdComment.HTMLURL) - return nil -} - -func removeLabels(client *github.Client, repoOwner, repoName string, prNum int) error { - log.Printf("Removing labels from %s/%s PR %d", repoOwner, repoName, prNum) - resp, err := client.Issues.RemoveLabelsForIssue(context.Background(), repoOwner, repoName, prNum) - if err != nil { - d, _ := httputil.DumpResponse(resp.Response, true) - log.Printf("Response indicates an error\n%s", string(d)) - return fmt.Errorf("adding comment to GitHub failed: %w", err) - } - - log.Printf("Removed labels") - return nil -} diff --git a/publish-results-pr/main.go b/publish-results-pr/main.go deleted file mode 100644 index c0f22ee5..00000000 --- a/publish-results-pr/main.go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -import ( - "log" - "os" - "time" - - "ahk/publishresultpr/internal/appargs" - "ahk/publishresultpr/internal/processing" - "ahk/publishresultpr/internal/publishtoapi" - "ahk/publishresultpr/internal/publishtopr" -) - -func main() { - log.Println("AHK Publish Result to GitHub PR") - - log.Println("Reading args...") - argReader := appargs.NewGitHubActionArgsReader() - appArgs, err := argReader.GetArgs() - if err != nil { - log.Fatal(err) - } - log.Println("Reading args... done.") - - dir, _ := os.Getwd() - log.Printf("Working directory is: %s\n", dir) - - log.Println("Processing...") - processor := processing.NewProcessor() - result, err := processor.Process(*appArgs, dir) - if err != nil { - log.Fatal(err) - } - log.Println("Processing... done.") - - log.Println("Publishing results to PR...") - prpub := publishtopr.NewPrPublisher() - prpubConfig := publishtopr.Config{ - GitHubToken: appArgs.GitHubToken, - RepoOwner: appArgs.GitHubRepoOwner, - RepoName: appArgs.GitHubRepoName, - CommitHash: appArgs.GitCommitHash, - PrNumber: appArgs.GitHubPullRequestNum, - } - err = prpub.Publish(result, prpubConfig) - if err != nil { - log.Fatal(err) - } - log.Println("Publishing results to PR... done.") - - if appArgs.AhkAppUrl != "" && appArgs.AhkAppToken != "" && appArgs.AhkAppSecret != "" { - log.Println("Sending result to Ahk Api...") - apipub := publishtoapi.NewApiPublisher() - apipubConfig := publishtoapi.Config{ - Url: appArgs.AhkAppUrl, - Token: appArgs.AhkAppToken, - Secret: appArgs.AhkAppSecret, - Date: time.Now(), - } - err = apipub.Publish(result, apipubConfig) - if err != nil { - log.Fatal(err) - } - log.Println("Sending result to Ahk Api... done.") - } else { - log.Println("Sending result to Ahk Api disabled.") - } - - log.Println("Finished. Bye.") -} From 2a67f81a922387ffcd03eeb6cbab4f171f1aa856 Mon Sep 17 00:00:00 2001 From: tanaiadam <65241679+tanaiadam@users.noreply.github.com> Date: Thu, 26 Sep 2024 23:00:24 +0200 Subject: [PATCH 2/4] Added PublishResult .NET project --- .../publish-result-pr-docker-publish.yaml | 31 +++-- publish-results-pr/AppArgs/ArgReader.cs | 118 ++++++++++++++++++ publish-results-pr/AppArgs/Exercise.cs | 13 ++ publish-results-pr/Dockerfile | 17 +++ .../Processing/ImageFilesFinder.cs | 22 ++++ publish-results-pr/Processing/NeptunParser.cs | 20 +++ publish-results-pr/Processing/Processor.cs | 71 +++++++++++ publish-results-pr/Program.cs | 43 +++++++ publish-results-pr/PublishResult.csproj | 14 +++ publish-results-pr/PublishResult.sln | 25 ++++ .../PublishToApi/ApiPublisher.cs | 51 ++++++++ .../PublishToApi/ResultForApi.cs | 17 +++ .../PublishToPr/CommentFormatter.cs | 84 +++++++++++++ publish-results-pr/PublishToPr/PrPublisher.cs | 25 ++++ publish-results-pr/README.md | 102 +++++++-------- 15 files changed, 594 insertions(+), 59 deletions(-) create mode 100644 publish-results-pr/AppArgs/ArgReader.cs create mode 100644 publish-results-pr/AppArgs/Exercise.cs create mode 100644 publish-results-pr/Dockerfile create mode 100644 publish-results-pr/Processing/ImageFilesFinder.cs create mode 100644 publish-results-pr/Processing/NeptunParser.cs create mode 100644 publish-results-pr/Processing/Processor.cs create mode 100644 publish-results-pr/Program.cs create mode 100644 publish-results-pr/PublishResult.csproj create mode 100644 publish-results-pr/PublishResult.sln create mode 100644 publish-results-pr/PublishToApi/ApiPublisher.cs create mode 100644 publish-results-pr/PublishToApi/ResultForApi.cs create mode 100644 publish-results-pr/PublishToPr/CommentFormatter.cs create mode 100644 publish-results-pr/PublishToPr/PrPublisher.cs diff --git a/.github/workflows/publish-result-pr-docker-publish.yaml b/.github/workflows/publish-result-pr-docker-publish.yaml index d531a985..b80e1e6d 100644 --- a/.github/workflows/publish-result-pr-docker-publish.yaml +++ b/.github/workflows/publish-result-pr-docker-publish.yaml @@ -1,19 +1,32 @@ -name: Publish Result PR - Docker publish +name: Publish to GHCR on: [workflow_dispatch] jobs: - publish: + publish-docker-image: runs-on: ubuntu-latest + permissions: + packages: write + contents: read steps: - - name: Checkout - uses: actions/checkout@v2 + - name: Checkout code + uses: actions/checkout@v4 - - name: Build and push to GHCR + - name: Prepare .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: "8.0.x" + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push to GitHub Container Registry working-directory: publish-results-pr run: | - echo "${{ secrets.GITHUB_TOKEN }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin - docker build -t ghcr.io/akosdudas/ahk-publish-results-pr:v1 . - docker push ghcr.io/akosdudas/ahk-publish-results-pr:v1 - docker logout https://ghcr.io + docker build -t ghcr.io/tanaiadam/publish-result:latest . + docker push ghcr.io/tanaiadam/publish-result:latest diff --git a/publish-results-pr/AppArgs/ArgReader.cs b/publish-results-pr/AppArgs/ArgReader.cs new file mode 100644 index 00000000..eaf11c9e --- /dev/null +++ b/publish-results-pr/AppArgs/ArgReader.cs @@ -0,0 +1,118 @@ +using System.Text.Json; + +namespace PublishResult.AppArgs; + +public readonly struct AppArgs +{ + public string GitHubRepoFullName { get; init; } + public string GitHubRepoOwner { get; init; } + public string GitHubRepoName { get; init; } + public string GitHubBranch { get; init; } + public string GitCommitHash { get; init; } + public string GitHubActionRunId { get; init; } + public int GitHubPullRequestNum { get; init; } + public string GitHubToken { get; init; } + public string NeptunFileName { get; init; } + public string ImageExtension { get; init; } + public string ResultFile { get; init; } + public string AhkAppUrl { get; init; } + public string AhkAppSecret { get; init; } + public string AhkAppToken { get; init; } +} + +public static class ArgReader +{ + public static AppArgs GetArgs() + { + _ = Environment.GetEnvironmentVariable("GITHUB_ACTIONS") + ?? throw new ArgumentException("GITHUB_ACTIONS not set (not running inside GitHub Actions)"); + var ghRepoFullName = Environment.GetEnvironmentVariable("GITHUB_REPOSITORY"); + if (ghRepoFullName is null) + throw new ArgumentNullException(nameof(ghRepoFullName)); + + var ghRepoSplit = ghRepoFullName.Split("/"); + if (ghRepoSplit.Length != 2) + throw new ArgumentException("GITHUB_REPOSITORY is not in expected format owner/name"); + var ghRepoOwner = ghRepoSplit[0]; + var ghRepoName = ghRepoSplit[1]; + + var ghBranch = Environment.GetEnvironmentVariable("GITHUB_REF"); + if (ghBranch is null) + throw new ArgumentNullException(nameof(ghBranch)); + + var ghCommitHash = Environment.GetEnvironmentVariable("GITHUB_SHA"); + if (ghCommitHash is null) + throw new ArgumentNullException(nameof(ghCommitHash)); + + var ghActionRunId = Environment.GetEnvironmentVariable("GITHUB_RUN_ID"); + ghActionRunId ??= ""; + + var ghToken = Environment.GetEnvironmentVariable("INPUT_GITHUB_TOKEN"); + if (ghToken is null) + throw new ArgumentNullException(nameof(ghToken)); + + var neptunFileName = Environment.GetEnvironmentVariable("INPUT_AHK_NEPTUNFILENAME"); + neptunFileName ??= "neptun.txt"; + + var imageExt = Environment.GetEnvironmentVariable("INPUT_AHK_IMAGEEXT"); + imageExt ??= ".png"; + + var resultsFile = Environment.GetEnvironmentVariable("INPUT_AHK_RESULTFILE"); + resultsFile ??= "result.json"; + + var ahkAppUrl = Environment.GetEnvironmentVariable("INPUT_AHK_APPURL"); + ahkAppUrl ??= "https://ahk-grade-management.azurewebsites.net/api/evaluation-result"; + + var ahkAppToken = Environment.GetEnvironmentVariable("INPUT_AHK_APPTOKEN"); + ahkAppToken ??= ""; + + var ahkAppSecret = Environment.GetEnvironmentVariable("INPUT_AHK_APPSECRET"); + ahkAppSecret ??= ""; + + var ghEventPayloadFilePath = Environment.GetEnvironmentVariable("GITHUB_EVENT_PATH"); + if (ghEventPayloadFilePath is null) + throw new ArgumentNullException(ghEventPayloadFilePath); + var ghPrNum = GetPrNumFromPayload(ghEventPayloadFilePath); + + return new AppArgs() + { + GitHubRepoFullName = ghRepoFullName, + GitHubRepoOwner = ghRepoOwner, + GitHubRepoName = ghRepoName, + GitHubBranch = ghBranch, + GitCommitHash = ghCommitHash, + GitHubActionRunId = ghActionRunId, + GitHubPullRequestNum = ghPrNum, + GitHubToken = ghToken, + NeptunFileName = neptunFileName, + ImageExtension = imageExt, + ResultFile = resultsFile, + AhkAppUrl = ahkAppUrl, + AhkAppToken = ahkAppToken, + AhkAppSecret = ahkAppSecret, + }; + } + + private static int GetPrNumFromPayload(string ghEventPayloadFilePath) + { + var jsonText = File.ReadAllText(ghEventPayloadFilePath) + ?? throw new ArgumentNullException($"file at {ghEventPayloadFilePath} does not exist"); + + var json = JsonSerializer.Deserialize(jsonText); + + try + { + var pullRequest = json.TryGetProperty("pull_request", out var numberValue); + var number = numberValue.TryGetProperty("number", out var numberValue2); + + if (numberValue2.ToString().Length <= 0) + throw new Exception("not running within a pull request event context"); + + return Int32.Parse(numberValue2.ToString()); + } + catch (Exception) + { + throw new Exception("not running within a pull request event context"); + } + } +} diff --git a/publish-results-pr/AppArgs/Exercise.cs b/publish-results-pr/AppArgs/Exercise.cs new file mode 100644 index 00000000..bebf2806 --- /dev/null +++ b/publish-results-pr/AppArgs/Exercise.cs @@ -0,0 +1,13 @@ +namespace PublishResult.AppArgs; + +public class Exercise(string exerciseName, int maxPoint, int givenPoint) +{ + public string ExerciseName { get; set; } = exerciseName; + public int MaxPoint { get; set; } = maxPoint; + public int GivenPoint { get; set; } = givenPoint; + + public override string ToString() + { + return $"{ExerciseName}: {GivenPoint} out of {MaxPoint} points."; + } +} diff --git a/publish-results-pr/Dockerfile b/publish-results-pr/Dockerfile new file mode 100644 index 00000000..679a54ba --- /dev/null +++ b/publish-results-pr/Dockerfile @@ -0,0 +1,17 @@ +# Build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /app + +# Copy files, restore, publish +COPY ./PublishResult.csproj ./ +RUN dotnet restore PublishResult.csproj +COPY ./. ./ +RUN dotnet publish PublishResult.csproj -c Release -o out + +# Runtime +FROM mcr.microsoft.com/dotnet/runtime:8.0 +WORKDIR /app + +# Copy the published output +COPY --from=build /app/out /src +CMD ["dotnet", "/src/PublishResult.dll"] diff --git a/publish-results-pr/Processing/ImageFilesFinder.cs b/publish-results-pr/Processing/ImageFilesFinder.cs new file mode 100644 index 00000000..e8af982b --- /dev/null +++ b/publish-results-pr/Processing/ImageFilesFinder.cs @@ -0,0 +1,22 @@ +namespace PublishResult.Processing; + +public class ImageFilesFinder +{ + public static string?[] GetImageFiles(string dir, string fileExtension) + { + try + { + var imageFiles = Directory.GetFiles(dir, $"*{fileExtension}", SearchOption.TopDirectoryOnly) + .Select(Path.GetFileName) + .Order() + .ToArray(); + + return imageFiles; + } + catch (Exception ex) + { + Console.WriteLine($"Error: {ex.Message}"); + return []; + } + } +} diff --git a/publish-results-pr/Processing/NeptunParser.cs b/publish-results-pr/Processing/NeptunParser.cs new file mode 100644 index 00000000..83c84c4c --- /dev/null +++ b/publish-results-pr/Processing/NeptunParser.cs @@ -0,0 +1,20 @@ +using System.Text.RegularExpressions; + +namespace PublishResult.Processing; + +public partial class NeptunParser +{ + [GeneratedRegex("^[a-zA-Z0-9]{6}$", RegexOptions.Compiled)] + private static partial Regex NeptunRegex(); + + public static string? ParseNeptun(string neptunFileName) + { + using var file = File.OpenText(neptunFileName); + var neptun = file.ReadToEnd(); + + if (string.IsNullOrEmpty(neptun) || !NeptunRegex().IsMatch(neptun)) + return null; + + return neptun; + } +} diff --git a/publish-results-pr/Processing/Processor.cs b/publish-results-pr/Processing/Processor.cs new file mode 100644 index 00000000..7ebf3aa1 --- /dev/null +++ b/publish-results-pr/Processing/Processor.cs @@ -0,0 +1,71 @@ +using System.Text.Json; + +using PublishResult.AppArgs; + +namespace PublishResult.Processing; + +public readonly struct AhkProcessResult +{ + public string GitHubRepoName { get; init; } + public string GitHubBranch { get; init; } + public int GitHubPullRequestNum { get; init; } + public string GitHubCommitHash { get; init; } + public string NeptunCode { get; init; } + public string?[]? ImageFiles { get; init; } + public string Result { get; init; } + public string Origin { get; init; } +} + +public static class Processor +{ + public static AhkProcessResult Process(AppArgs.AppArgs appArgs, string workDir) + { + var neptun = NeptunParser.ParseNeptun(appArgs.NeptunFileName); + + Console.WriteLine($"Neptun: {neptun}"); + + string?[]? imageFiles = null; + if (appArgs.ImageExtension == "") + Console.WriteLine("Image files gathering not requested"); + else + { + imageFiles = ImageFilesFinder.GetImageFiles(workDir, appArgs.ImageExtension); + if (imageFiles != null && imageFiles.Length > 0) + { + foreach (var imageFile in imageFiles) + { + Console.WriteLine($"Found image file: {imageFile}"); + } + } + else + Console.WriteLine("Found 0 image files"); + } + + string result = null!; + if (appArgs.ResultFile == "") + Console.WriteLine("Result file processing not requested"); + else + { + // JSON + result = File.ReadAllText(appArgs.ResultFile); + var exercises = JsonSerializer.Deserialize(result); + if (exercises != null) + foreach (var exercise in exercises) + { + Console.WriteLine(exercise); + } + } + + return new AhkProcessResult + { + GitHubRepoName = appArgs.GitHubRepoFullName, + GitHubBranch = appArgs.GitHubBranch, + GitHubPullRequestNum = appArgs.GitHubPullRequestNum, + GitHubCommitHash = appArgs.GitCommitHash, + NeptunCode = neptun!, + ImageFiles = imageFiles, + Result = result, + Origin = $"https://github.com/{appArgs.GitHubRepoFullName}/commit/{appArgs.GitCommitHash} https://github.com/{appArgs.GitHubRepoFullName}/actions/runs/{appArgs.GitHubActionRunId}", + }; + } +} diff --git a/publish-results-pr/Program.cs b/publish-results-pr/Program.cs new file mode 100644 index 00000000..3b5f4edd --- /dev/null +++ b/publish-results-pr/Program.cs @@ -0,0 +1,43 @@ +using PublishResult.AppArgs; +using PublishResult.Processing; +using PublishResult.PublishToPr; + +namespace PublishResult; + +public class Program +{ + public static async Task Main() + { + Console.WriteLine("AHK Publish Result to GitHub PR\n"); + + Console.WriteLine("Reading args..."); + var appArgs = ArgReader.GetArgs(); + //Console.WriteLine(appArgs); + Console.WriteLine("Reading args... done.\n"); + + var dir = Directory.GetCurrentDirectory(); + Console.WriteLine($"Working directory is {dir}\n"); + + Console.WriteLine("Processing..."); + var result = Processor.Process(appArgs, dir); + Console.WriteLine("Processing... done.\n"); + + Console.WriteLine("Publishing results to PR..."); + await PrPublisher.PublishToPrAsync(appArgs, result); + Console.WriteLine("Publishing results to PR... done.\n"); + + // TODO: Uncomment if backend is ready + + //if (appArgs.AhkAppUrl != "" && appArgs.AhkAppToken != "" && appArgs.AhkAppSecret != "") + //{ + // Console.WriteLine("Sending result to Ahk Api..."); + // var apiPublisher = new ApiPublisher(); + // apiPublisher.PublishToApi(appArgs, result); + // Console.WriteLine("Sending result to Ahk Api... done.\n"); + //} + //else + // Console.WriteLine("Sending result to Ahk Api disabled.\n"); + + Console.WriteLine("Finished. Bye."); + } +} diff --git a/publish-results-pr/PublishResult.csproj b/publish-results-pr/PublishResult.csproj new file mode 100644 index 00000000..5fd05d76 --- /dev/null +++ b/publish-results-pr/PublishResult.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/publish-results-pr/PublishResult.sln b/publish-results-pr/PublishResult.sln new file mode 100644 index 00000000..5875fc4c --- /dev/null +++ b/publish-results-pr/PublishResult.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PublishResult", "PublishResult.csproj", "{131F9BF2-A3BB-4E62-9451-8BA56109E09D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {131F9BF2-A3BB-4E62-9451-8BA56109E09D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {131F9BF2-A3BB-4E62-9451-8BA56109E09D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {131F9BF2-A3BB-4E62-9451-8BA56109E09D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {131F9BF2-A3BB-4E62-9451-8BA56109E09D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {44C6CE0A-3DBE-4821-9F9A-A08CAA32E1B6} + EndGlobalSection +EndGlobal diff --git a/publish-results-pr/PublishToApi/ApiPublisher.cs b/publish-results-pr/PublishToApi/ApiPublisher.cs new file mode 100644 index 00000000..c8c270d8 --- /dev/null +++ b/publish-results-pr/PublishToApi/ApiPublisher.cs @@ -0,0 +1,51 @@ +using System.Text.Json; + +using PublishResult.AppArgs; +using PublishResult.Processing; + +namespace PublishResult.PublishToApi; + +public static class ApiPublisher +{ + private static readonly JsonSerializerOptions writeOptions = new() + { + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }; + + public static void PublishToApi(AppArgs.AppArgs appArgs, AhkProcessResult result) + { + var githubRepositoryUrl = $"https://github.com/{appArgs.GitHubRepoFullName}"; + var pullrequestUrl = $"https://github.com/{appArgs.GitHubRepoOwner}/{appArgs.GitHubRepoName}/pull/{appArgs.GitHubPullRequestNum}"; + var neptun = result.NeptunCode; + var scores = new List(); + + var exercises = JsonSerializer.Deserialize(result.Result); + var createdDate = DateTimeOffset.Now; + + if (exercises is not null && exercises.Length != 0) + { + foreach (var exercise in exercises) + { + scores.Add(new EventScore() + { + Value = exercise.GivenPoint, + CreatedDate = createdDate, + ScoreType = exercise.ExerciseName, + }); + } + } + + var resultToApi = new ResultForApi() + { + GithubRepositoryUrl = githubRepositoryUrl, + PullRequestUrl = pullrequestUrl, + StudentNeptun = neptun, + Scores = scores, + }; + + var json = JsonSerializer.Serialize(resultToApi, writeOptions); + + // TODO: send json to backend + } +} diff --git a/publish-results-pr/PublishToApi/ResultForApi.cs b/publish-results-pr/PublishToApi/ResultForApi.cs new file mode 100644 index 00000000..5204b131 --- /dev/null +++ b/publish-results-pr/PublishToApi/ResultForApi.cs @@ -0,0 +1,17 @@ +namespace PublishResult.PublishToApi; + +public class ResultForApi +{ + public string GithubRepositoryUrl { get; set; } = null!; + public string PullRequestUrl { get; set; } = null!; + public string StudentNeptun { get; set; } = null!; + public List Scores { get; set; } = null!; + +} + +public class EventScore +{ + public long Value { get; set; } + public DateTimeOffset CreatedDate { get; set; } + public string ScoreType { get; set; } = null!; +} diff --git a/publish-results-pr/PublishToPr/CommentFormatter.cs b/publish-results-pr/PublishToPr/CommentFormatter.cs new file mode 100644 index 00000000..660e002c --- /dev/null +++ b/publish-results-pr/PublishToPr/CommentFormatter.cs @@ -0,0 +1,84 @@ +using PublishResult.AppArgs; +using PublishResult.Processing; + +using System.Text.Json; + +namespace PublishResult.PublishToPr; + +public static class CommentFormatter +{ + public static string CreateComment(AppArgs.AppArgs appArgs, AhkProcessResult result) + { + var comment = ""; + + comment += AddImages(appArgs, result); + comment += "\n\n"; + comment += $"**Neptun**: {result.NeptunCode}"; + comment += "\n\n"; + comment += AddTasks(result); + comment += "\n\n"; + comment += AddSummary(result); + + return comment; + } + + private static string AddImages(AppArgs.AppArgs appArgs, AhkProcessResult result) + { + var str = ""; + + if (result.ImageFiles?.Length > 0) + { + foreach (var image in result.ImageFiles) + { + str += "**" + image + "**" + "\n"; + str += $"![](https://github.com/{appArgs.GitHubRepoOwner}/{appArgs.GitHubRepoName}/blob/{appArgs.GitCommitHash}/{image}?raw=true)\n\n"; + } + } + + return str; + } + + private static string AddTasks(AhkProcessResult result) + { + var str = ""; + var exercises = JsonSerializer.Deserialize(result.Result); + if (exercises is not null && exercises.Length != 0) + { + foreach (var exercise in exercises) + { + str += exercise.ToString() + "\n"; + } + } + + return str; + } + + private static string AddSummary(AhkProcessResult result) + { + var maxPoint = 0; + var givenPoint = 0; + var maxImsc = 0; + var givenImsc = 0; + + var exercises = JsonSerializer.Deserialize(result.Result); + + if (exercises is not null && exercises.Length != 0) + { + foreach (var exercise in exercises) + { + if (exercise.ExerciseName.StartsWith("imsc")) + { + maxImsc += exercise.MaxPoint; + givenImsc += exercise.GivenPoint; + } + else + { + maxPoint += exercise.MaxPoint; + givenPoint += exercise.GivenPoint; + } + } + } + + return $"**Osszesites/Summary**:\n{givenPoint} out of {maxPoint}\nimsc: {givenImsc} out of {maxImsc}"; + } +} diff --git a/publish-results-pr/PublishToPr/PrPublisher.cs b/publish-results-pr/PublishToPr/PrPublisher.cs new file mode 100644 index 00000000..8c680b05 --- /dev/null +++ b/publish-results-pr/PublishToPr/PrPublisher.cs @@ -0,0 +1,25 @@ +using Octokit; +using PublishResult.Processing; + +namespace PublishResult.PublishToPr; + +public static class PrPublisher +{ + public static async Task PublishToPrAsync(AppArgs.AppArgs appArgs, AhkProcessResult result) + { + var github = new GitHubClient(new ProductHeaderValue("MyApp")); + var token = appArgs.GitHubToken; + github.Credentials = new Credentials(token); + + var owner = appArgs.GitHubRepoOwner; + var repo = appArgs.GitHubRepoName; + var prNumber = appArgs.GitHubPullRequestNum; + + var newComment = CommentFormatter.CreateComment(appArgs, result); + + var comment = await github.Issue.Comment.Create(owner, repo, prNumber, newComment); + + Console.WriteLine($"Sending comment to {owner}/{repo} PR {prNumber}"); + Console.WriteLine($"Created comment with id {comment?.Id} at {comment?.HtmlUrl}"); + } +} diff --git a/publish-results-pr/README.md b/publish-results-pr/README.md index fdf6cbd0..6cc445b1 100644 --- a/publish-results-pr/README.md +++ b/publish-results-pr/README.md @@ -1,8 +1,8 @@ -# Publish Results to PR +# Publish Result -Posts the results of an automated evaluation of a student homework as a comment into a pull request and sends it to the _grade management_ application. +Posts the result of an automated evaluation of a student homework as a comment into a pull request and sends it to the _grade management_ application. -The application is a Go container to be used as part of a GitHub Action workflow. A previous step in the workflow is supposed to evaluate the student submission and a step using this application can process it and publish it in readable and manageable format. +The application is a .NET container to be used as part of a GitHub Action workflow. A previous step in the workflow is supposed to evaluate the student submission and a step using this application can process it and publish it in readable and manageable format. ## Usage of the action @@ -18,7 +18,7 @@ The action reads various environment variables automatically set by GitHub Actio #### `AHK_RESULTFILE` -The path of the input file containing the evaluation result. When specified, the parsed results will be included in the result comment. Defaults to `"result.txt"`. +The path of the input file containing the evaluation result. When specified, the parsed results will be included in the result comment. Defaults to `"result.json"`. #### `AHK_IMAGEEXT` @@ -54,7 +54,7 @@ jobs: - name: Publish results uses: docker://ghcr.io/akosdudas/ahk-publish-results-pr:v1 with: - AHK_RESULTFILE: "result.txt" + AHK_RESULTFILE: "result.json" AHK_IMAGEEXT: ".png" AHK_APPURL: "https://myaddress.azurewebsites.net/api/webhook-url" AHK_APPTOKEN: "${{ secrets.AHK_APPTOKEN }}" @@ -67,7 +67,7 @@ jobs: There are three types of file inputs, all taken from the repository root: - `neptun.txt` (**mandatory**); -- `result.txt` (or other file name configured as argument of the action); +- `result.json` (or other file name configured as argument of the action); - and image files. ### Example @@ -75,71 +75,73 @@ There are three types of file inputs, all taken from the repository root: Let the input be as follows. 1. `neptun.txt` has a single line with content "ABC123." -1. `result.txt` text file with content: - - ``` - ###ahk#Exercise 1#2#ok - ###ahk#Exercise 2#3#3/4 points: not all cases covered - ###ahk#Exercise 3#0#Unexpected exception:\ - System.NotImplementedException\ - The implementation is missing - ###ahk#optional@Exercise 4#3 - ``` +1. `result.json` text file with content: + + ``` + [ + { + "ExerciseName": "Feladat 1 - Exercise 1", + "MaxPoint": 2, + "GivenPoint": 0 + }, + { + "ExerciseName": "imsc Feladat 2 - Exercise 2", + "MaxPoint": 2, + "GivenPoint": 0 + } + ] + + ``` 1. And two image files, `image1.png` and `image2.png` are in the repository root. These files along with the configuration of the action as above yields the following comment in the pull request: +> **image1.png** > \ > +> **image2.png** > \ > > **Neptun**: ABC123 > -> **Exercise 1**: 2 -> -> ok -> -> **Exercise 2**: 3 -> -> 3/4 points: not all cases covered -> -> **Exercise 3**: 0 -> -> Unexpected exception: -> -> System.NotImplementedException +> Feladat 1 - Exercise 1: 2 out of 2 points. +> imsc Feladat 2 - Exercise 2: 2 out of 2 points. > -> The implementation is missing -> -> **Total**: -> -> 5 -> -> optional: 3 +> **Osszesites/Summary**: +> 2 out of 2 +> imsc: 2 out of 2 -### Syntax of `result.txt` file +### Syntax of `result.json` file -Every line in the file contains the evaluation result of one exercise as: +Every line in the file contains the evaluation result of exercises as: ``` -###ahk#taskname#result#comment -``` - -#### `###ahk#` +[ + { + "ExerciseName": "Feladat 1 - Exercise 1", + "MaxPoint": 2, + "GivenPoint": 0 + }, + { + "ExerciseName": "imsc Feladat 2 - Exercise 2", + "MaxPoint": 2, + "GivenPoint": 0 + } +] -`###ahk#` is a mandatory prefix. +``` -#### `taskname` +#### `ExerciseName` -A text that identifies the task or exercise name, e.g., "Exercise 2". +A text that identifies the task or exercise name, e.g., "Exercise 1". +An ExerciseName with the `imsc` prefix is an optional task. -Exercises can be "grouped," e.g., to distinguish optional tasks from mandatory ones. The group is optional and is part of the exercise name as "optional@Exercise 5". The total of the exercises (e.g., the cumulative points) are summed for each group separately. If there is no group in an exercise name, e.g., "Task 2", it belongs to a default group with no name. +#### `MaxPoint` -#### `result` +The maximum points achievable. -A number as text that corresponds to the result (i.e., score) achieved for the particular task. If there are no scores, you can use 1 for pass and 0 for failure. +#### `GivenPoint` -#### `comment` +The points achieved. -An optional text interpreted as a comment. Use it to comment on the achieved result and to report problems and errors. The comment can have multiple lines; check the example above. From aae696c8818024736e8c1fff244b67a33a4ad186 Mon Sep 17 00:00:00 2001 From: tanaiadam <65241679+tanaiadam@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:14:10 +0200 Subject: [PATCH 3/4] PublishToApi feature added --- publish-results-pr/AppArgs/ArgReader.cs | 2 +- publish-results-pr/Program.cs | 29 ++++++++++--------- .../PublishToApi/ApiPublisher.cs | 12 ++++++-- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/publish-results-pr/AppArgs/ArgReader.cs b/publish-results-pr/AppArgs/ArgReader.cs index eaf11c9e..27d957d1 100644 --- a/publish-results-pr/AppArgs/ArgReader.cs +++ b/publish-results-pr/AppArgs/ArgReader.cs @@ -61,7 +61,7 @@ public static AppArgs GetArgs() resultsFile ??= "result.json"; var ahkAppUrl = Environment.GetEnvironmentVariable("INPUT_AHK_APPURL"); - ahkAppUrl ??= "https://ahk-grade-management.azurewebsites.net/api/evaluation-result"; + ahkAppUrl ??= ""; var ahkAppToken = Environment.GetEnvironmentVariable("INPUT_AHK_APPTOKEN"); ahkAppToken ??= ""; diff --git a/publish-results-pr/Program.cs b/publish-results-pr/Program.cs index 3b5f4edd..8763f4e2 100644 --- a/publish-results-pr/Program.cs +++ b/publish-results-pr/Program.cs @@ -1,10 +1,11 @@ -using PublishResult.AppArgs; +using PublishResult.AppArgs; using PublishResult.Processing; +using PublishResult.PublishToApi; using PublishResult.PublishToPr; namespace PublishResult; -public class Program +public static class Program { public static async Task Main() { @@ -26,17 +27,19 @@ public static async Task Main() await PrPublisher.PublishToPrAsync(appArgs, result); Console.WriteLine("Publishing results to PR... done.\n"); - // TODO: Uncomment if backend is ready - - //if (appArgs.AhkAppUrl != "" && appArgs.AhkAppToken != "" && appArgs.AhkAppSecret != "") - //{ - // Console.WriteLine("Sending result to Ahk Api..."); - // var apiPublisher = new ApiPublisher(); - // apiPublisher.PublishToApi(appArgs, result); - // Console.WriteLine("Sending result to Ahk Api... done.\n"); - //} - //else - // Console.WriteLine("Sending result to Ahk Api disabled.\n"); + if (string.IsNullOrEmpty(appArgs.AhkAppUrl)) + Console.WriteLine("Sending result to Ahk Api not requested(AHK_APPURL not defined).\n"); + else if (!string.IsNullOrEmpty(appArgs.AhkAppToken) && !string.IsNullOrEmpty(appArgs.AhkAppSecret)) + { + Console.WriteLine("Sending result to Ahk Api..."); + var apiResult = await ApiPublisher.PublishToApiAsync(appArgs, result); + if (apiResult) + Console.WriteLine("Sending result to Ahk Api... done.\n"); + else + Console.WriteLine("Sending result to Ahk Api was not successful.\n"); + } + else + Console.WriteLine("Sending result to Ahk Api disabled.\n"); Console.WriteLine("Finished. Bye."); } diff --git a/publish-results-pr/PublishToApi/ApiPublisher.cs b/publish-results-pr/PublishToApi/ApiPublisher.cs index c8c270d8..c86f777f 100644 --- a/publish-results-pr/PublishToApi/ApiPublisher.cs +++ b/publish-results-pr/PublishToApi/ApiPublisher.cs @@ -1,5 +1,5 @@ +using System.Net.Http.Json; using System.Text.Json; - using PublishResult.AppArgs; using PublishResult.Processing; @@ -13,7 +13,7 @@ public static class ApiPublisher PropertyNamingPolicy = JsonNamingPolicy.CamelCase, }; - public static void PublishToApi(AppArgs.AppArgs appArgs, AhkProcessResult result) + public static async Task PublishToApiAsync(AppArgs.AppArgs appArgs, AhkProcessResult result) { var githubRepositoryUrl = $"https://github.com/{appArgs.GitHubRepoFullName}"; var pullrequestUrl = $"https://github.com/{appArgs.GitHubRepoOwner}/{appArgs.GitHubRepoName}/pull/{appArgs.GitHubPullRequestNum}"; @@ -46,6 +46,12 @@ public static void PublishToApi(AppArgs.AppArgs appArgs, AhkProcessResult result var json = JsonSerializer.Serialize(resultToApi, writeOptions); - // TODO: send json to backend + using HttpClient client = new HttpClient(); + var apiResult = await client.PostAsJsonAsync(appArgs.AhkAppUrl, json); + + if (apiResult.StatusCode == System.Net.HttpStatusCode.OK) + return true; + + return false; } } From 7b6c3d273fcd74573696ee5be60f88ccc432c482 Mon Sep 17 00:00:00 2001 From: tanaiadam <65241679+tanaiadam@users.noreply.github.com> Date: Sun, 20 Oct 2024 18:50:13 +0200 Subject: [PATCH 4/4] removed unused code --- publish-results-pr/Program.cs | 1 - publish-results-pr/PublishToApi/ApiPublisher.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/publish-results-pr/Program.cs b/publish-results-pr/Program.cs index 8763f4e2..c8052603 100644 --- a/publish-results-pr/Program.cs +++ b/publish-results-pr/Program.cs @@ -13,7 +13,6 @@ public static async Task Main() Console.WriteLine("Reading args..."); var appArgs = ArgReader.GetArgs(); - //Console.WriteLine(appArgs); Console.WriteLine("Reading args... done.\n"); var dir = Directory.GetCurrentDirectory(); diff --git a/publish-results-pr/PublishToApi/ApiPublisher.cs b/publish-results-pr/PublishToApi/ApiPublisher.cs index c86f777f..804a6392 100644 --- a/publish-results-pr/PublishToApi/ApiPublisher.cs +++ b/publish-results-pr/PublishToApi/ApiPublisher.cs @@ -46,7 +46,7 @@ public static async Task PublishToApiAsync(AppArgs.AppArgs appArgs, AhkPro var json = JsonSerializer.Serialize(resultToApi, writeOptions); - using HttpClient client = new HttpClient(); + using var client = new HttpClient(); var apiResult = await client.PostAsJsonAsync(appArgs.AhkAppUrl, json); if (apiResult.StatusCode == System.Net.HttpStatusCode.OK)