gitoriaLog in with ident

tickets

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commit2ab91ee92ab91ee9tickets: gate checks rows appear once (session sync); re-vendor to ff51cf46 stopped on hybriel#122, stays 837fe120mre2ab91ee9/import.hl

2.9 KB

  1. // import.hl — import AntColony ticket files into the RUNNING app, over its JSON API.
  2. //
  3. // bin/hybriel import.hl
  4. // TICKETS_IMPORT_DIR=/some/dir TICKETS_URL=http://127.0.0.1:8350 bin/hybriel import.hl
  5. //
  6. // WRITES NEED A TOKEN (ticket #7): TICKETS_TOKEN = an API token (log in with ident, /you →
  7. // "Create a token"); the imported tickets are opened by that token's user.
  8. //
  9. // A ticket file is `project:` and `subject:` header lines, a blank line, the summary
  10. // (hard-wrapped lines are joined into paragraphs, blank line = new paragraph —
  11. // ticketfile.hl).
  12. // Each file is POSTed to /api/tickets with `source` = its file name; the app answers a
  13. // known source with the ticket it already has (200, existed) instead of a second one
  14. // (201), so running this twice imports nothing twice. Going through the API (not the
  15. // tables) means the running server stays the only writer and open browsers see the
  16. // imported tickets arrive live.
  17. import { listDir, readFile } from 'hl:fs'
  18. import { env } from 'hl:proc'
  19. import { fetch } from 'hl:fetch'
  20. import { parse } from './ticketfile.hl'
  21. static dir = env('TICKETS_IMPORT_DIR') != null ? env('TICKETS_IMPORT_DIR') : './import/tickets'
  22. static base = env('TICKETS_URL') != null ? env('TICKETS_URL') : 'http://127.0.0.1:8350'
  23. static token = env('TICKETS_TOKEN') != null ? env('TICKETS_TOKEN') : ''
  24. if (token == '') { console.log('import: TICKETS_TOKEN is not set — API writes need a token (log in, /you → Create a token)') }
  25. // a > b for two strings (strings order by code point, hybriel#2; still no list sort())
  26. static after = (a, b) => { return a > b }
  27. // file names, sorted, so an empty store numbers each project's tickets in file order
  28. names = []
  29. for (n of listDir(dir)) {
  30. let name = hlTypeName(n) == 'String' ? n : n.name
  31. if (name.endsWith('.md')) { names.push(name) }
  32. }
  33. let i = 1
  34. while (i < names.length) {
  35. let cur = names[i]
  36. let j = i - 1
  37. while (j >= 0 && after(names[j], cur)) {
  38. names[j + 1] = names[j]
  39. j = j - 1
  40. }
  41. names[j + 1] = cur
  42. i = i + 1
  43. }
  44. created = 0
  45. existed = 0
  46. failed = 0
  47. for (name of names) {
  48. let t = parse(readFile(dir + '/' + name))
  49. if (t.error != null) {
  50. console.log('SKIP ' + name + ': ' + t.error)
  51. failed = failed + 1
  52. } else {
  53. let res = fetch(base + '/api/tickets', { method = 'POST' headers = { authorization = 'Bearer ' + token } json = { project = t.project subject = t.subject summary = t.summary source = name } })
  54. if (res.status == 201) {
  55. created = created + 1
  56. let tk = res.json().ticket
  57. console.log('NEW ' + name + ' → ' + tk.project + ' ' + tk.ref)
  58. } else if (res.status == 200) {
  59. existed = existed + 1
  60. let tk = res.json().ticket
  61. console.log('HAVE ' + name + ' = ' + tk.project + ' ' + tk.ref)
  62. } else {
  63. failed = failed + 1
  64. console.log('FAIL ' + name + ': ' + res.status + ' ' + res.text())
  65. }
  66. }
  67. }
  68. console.log('import: ' + created + ' new, ' + existed + ' already there, ' + failed + ' failed (' + dir + ' → ' + base + ')')

Branches

Latest commits

  • 2ab91ee9tickets: gate checks rows appear once (session sync); re-vendor to ff51cf46 stopped on hybriel#122, stays 837fe120mre
  • e01c2b1dtickets#24: installable app (manifest, service worker, offline list), own icon; gate waits for the hello's pongmre
  • 752fbb7fdeploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
  • 38bdd5e4deploy.sh: never send .git or .gitignore to Byrodinmre
  • f12fa1bcState of 2026-09-27, before the move to gitoriamre